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

trunk.c (253418B)


      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:        trunk.c
      8  * Purpose:     Trident2 resilient hashing and VP LAG implementation.
      9  *              VP LAG code is enclosed in INCLUDE_L3.
     10  */
     11 
     12 #include <shared/bsl.h>
     13 
     14 #include <soc/defs.h>
     15 #include <sal/core/libc.h>
     16 #ifdef BCM_TRIDENT2_SUPPORT
     17 
     18 #include <soc/drv.h>
     19 #include <soc/scache.h>
     20 #include <soc/esw/cancun.h>
     21 
     22 #include <bcm/error.h>
     23 #include <bcm/trunk.h>
     24 
     25 #include <bcm_int/esw/vlan.h>
     26 #include <bcm_int/esw/virtual.h>
     27 #include <bcm_int/esw/niv.h>
     28 #include <bcm_int/esw/extender.h>
     29 #include <bcm_int/esw/trident2.h>
     30 #include <bcm_int/esw/failover.h>
     31 #include <bcm_int/esw/triumph3.h>
     32 #include <bcm_int/esw/vxlan.h>
     33 #include <bcm_int/esw/mim.h>
     34 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
     35 #include <bcm_int/esw/trident2plus.h>
     36 #endif /* BCM_TRIDENT2PLUS_SUPPORT */
     37 #if defined(BCM_TOMAHAWK_SUPPORT)
     38 #include <bcm_int/esw/tomahawk.h>
     39 #endif
     40 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
     41 #include <soc/esw/ecmp.h>
     42 #endif /*  SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
     43 #if defined(BCM_TRIDENT3_SUPPORT)
     44 #include <bcm_int/esw/trident3.h>
     45 #endif
     46 #if defined(BCM_HELIX5_SUPPORT)
     47 #include <bcm_int/esw/helix5.h>
     48 #endif /* BCM_HELIX5_SUPPORT */
     49 #include <bcm_int/esw/l2gre.h>
     50 #include <bcm_int/esw/mpls.h>
     51 #include <bcm_int/esw/flow.h>
     52 
     53 
     54 extern int ecmp_mode_hierarchical;
     55 extern int ecmp_mode_single;
     56 
     57 /* Bookkeeping info for Higig resilient hashing */
     58 
     59 typedef struct _td2_hg_rh_info_s {
     60     SHR_BITDCL *hg_rh_flowset_block_bitmap; /* Each block corresponds to
     61                                                64 entries */
     62     uint32 hg_rh_rand_seed; /* The seed for pseudo-random number generator */
     63 } _td2_hg_rh_info_t;
     64 
     65 STATIC _td2_hg_rh_info_t *_td2_hg_rh_info[BCM_MAX_NUM_UNITS];
     66 
     67 #define _BCM_HG_RH_FLOWSET_BLOCK_USED_GET(_u_, _idx_) \
     68     SHR_BITGET(_td2_hg_rh_info[_u_]->hg_rh_flowset_block_bitmap, _idx_)
     69 #define _BCM_HG_RH_FLOWSET_BLOCK_USED_SET(_u_, _idx_) \
     70     SHR_BITSET(_td2_hg_rh_info[_u_]->hg_rh_flowset_block_bitmap, _idx_)
     71 #define _BCM_HG_RH_FLOWSET_BLOCK_USED_CLR(_u_, _idx_) \
     72     SHR_BITCLR(_td2_hg_rh_info[_u_]->hg_rh_flowset_block_bitmap, _idx_)
     73 #define _BCM_HG_RH_FLOWSET_BLOCK_USED_SET_RANGE(_u_, _idx_, _count_) \
     74     SHR_BITSET_RANGE(_td2_hg_rh_info[_u_]->hg_rh_flowset_block_bitmap, _idx_, _count_)
     75 #define _BCM_HG_RH_FLOWSET_BLOCK_USED_CLR_RANGE(_u_, _idx_, _count_) \
     76     SHR_BITCLR_RANGE(_td2_hg_rh_info[_u_]->hg_rh_flowset_block_bitmap, _idx_, _count_)
     77 #define _BCM_HG_RH_FLOWSET_BLOCK_TEST_RANGE(_u_, _idx_, _count_, _result_) \
     78     SHR_BITTEST_RANGE(_td2_hg_rh_info[_u_]->hg_rh_flowset_block_bitmap, _idx_, _count_, _result_)
     79 
     80 /* Bookkeeping info for LAG resilient hashing */
     81 
     82 typedef struct _td2_lag_rh_info_s {
     83     int num_lag_rh_flowset_blocks;
     84     SHR_BITDCL *lag_rh_flowset_block_bitmap; /* Each block corresponds to
     85                                                 64 entries */
     86     uint32 lag_rh_rand_seed; /* The seed for pseudo-random number generator */
     87 } _td2_lag_rh_info_t;
     88 
     89 STATIC _td2_lag_rh_info_t *_td2_lag_rh_info[BCM_MAX_NUM_UNITS];
     90 
     91 #define _BCM_LAG_RH_FLOWSET_BLOCK_USED_GET(_u_, _idx_) \
     92     SHR_BITGET(_td2_lag_rh_info[_u_]->lag_rh_flowset_block_bitmap, _idx_)
     93 #define _BCM_LAG_RH_FLOWSET_BLOCK_USED_SET(_u_, _idx_) \
     94     SHR_BITSET(_td2_lag_rh_info[_u_]->lag_rh_flowset_block_bitmap, _idx_)
     95 #define _BCM_LAG_RH_FLOWSET_BLOCK_USED_CLR(_u_, _idx_) \
     96     SHR_BITCLR(_td2_lag_rh_info[_u_]->lag_rh_flowset_block_bitmap, _idx_)
     97 #define _BCM_LAG_RH_FLOWSET_BLOCK_USED_SET_RANGE(_u_, _idx_, _count_) \
     98     SHR_BITSET_RANGE(_td2_lag_rh_info[_u_]->lag_rh_flowset_block_bitmap, _idx_, _count_)
     99 #define _BCM_LAG_RH_FLOWSET_BLOCK_USED_CLR_RANGE(_u_, _idx_, _count_) \
    100     SHR_BITCLR_RANGE(_td2_lag_rh_info[_u_]->lag_rh_flowset_block_bitmap, _idx_, _count_)
    101 #define _BCM_LAG_RH_FLOWSET_BLOCK_TEST_RANGE(_u_, _idx_, _count_, _result_) \
    102     SHR_BITTEST_RANGE(_td2_lag_rh_info[_u_]->lag_rh_flowset_block_bitmap, _idx_, _count_, _result_)
    103 
    104 #ifdef INCLUDE_L3
    105 
    106 /* VP LAG software state */
    107 typedef struct _td2_vp_lag_member_s{
    108     bcm_gport_t *egr_dis_vp;     /* member VPs with BCM_TRUNK_MEMBER_EGRESS_DISABLE */
    109     int          num_egr_dis_vp;
    110 } _td2_vp_lag_member_t;
    111 
    112 typedef struct _td2_vp_lag_group_s {
    113     int vp_id; /* The VP value allocated to VP LAG */
    114     int has_member; /* Indicates if VP LAG has members programmed in L3_ECMP table */
    115     int non_uc_index; /* Index of the non-unicast member */
    116     _td2_vp_lag_member_t vp_lag_member_info;    /* info of member VPs */
    117 } _td2_vp_lag_group_t;
    118 
    119 typedef struct _td2_vp_lag_info_s {
    120     int max_vp_lags; /* Maximum number of VP LAGs */
    121     int base_ecmp_idx; /* In Riot, ECMP table for underlay does not start at index 0 */
    122     SHR_BITDCL *vp_lag_used_bitmap; /* Bitmap of used VP LAG IDs */
    123     SHR_BITDCL *vp_lag_egr_member_bitmap; /* Bitmap of used entries of
    124                                              EGR_VPLAG_MEMBER table */
    125     _td2_vp_lag_group_t *group_info; /* Array of VP LAG group info */
    126     sal_mutex_t lock;        /* VP LAG lock. */
    127 } _td2_vp_lag_info_t;
    128 
    129 STATIC _td2_vp_lag_info_t *_td2_vp_lag_info[BCM_MAX_NUM_UNITS];
    130 
    131 #define VP_LAG_INIT_CHECK(_u_) \
    132         if (NULL == _td2_vp_lag_info[_u_]) { return BCM_E_INIT; }
    133 
    134 #define MAX_VP_LAGS(_u_) (_td2_vp_lag_info[_u_]->max_vp_lags)
    135 
    136 #define VP_LAG_USED_GET(_u_, _idx_) \
    137     SHR_BITGET(_td2_vp_lag_info[_u_]->vp_lag_used_bitmap, _idx_)
    138 #define VP_LAG_USED_SET(_u_, _idx_) \
    139     SHR_BITSET(_td2_vp_lag_info[_u_]->vp_lag_used_bitmap, _idx_)
    140 #define VP_LAG_USED_CLR(_u_, _idx_) \
    141     SHR_BITCLR(_td2_vp_lag_info[_u_]->vp_lag_used_bitmap, _idx_)
    142  
    143 #define VP_LAG_EGR_MEMBER_USED_GET(_u_, _idx_) \
    144     SHR_BITGET(_td2_vp_lag_info[_u_]->vp_lag_egr_member_bitmap, _idx_)
    145 #define VP_LAG_EGR_MEMBER_USED_SET(_u_, _idx_) \
    146     SHR_BITSET(_td2_vp_lag_info[_u_]->vp_lag_egr_member_bitmap, _idx_)
    147 #define VP_LAG_EGR_MEMBER_USED_CLR(_u_, _idx_) \
    148     SHR_BITCLR(_td2_vp_lag_info[_u_]->vp_lag_egr_member_bitmap, _idx_)
    149 #define VP_LAG_EGR_MEMBER_USED_SET_RANGE(_u_, _idx_, _count_) \
    150     SHR_BITSET_RANGE(_td2_vp_lag_info[_u_]->vp_lag_egr_member_bitmap, _idx_, _count_)
    151 #define VP_LAG_EGR_MEMBER_USED_CLR_RANGE(_u_, _idx_, _count_) \
    152     SHR_BITCLR_RANGE(_td2_vp_lag_info[_u_]->vp_lag_egr_member_bitmap, _idx_, _count_)
    153 #define VP_LAG_EGR_MEMBER_TEST_RANGE(_u_, _idx_, _count_, _result_) \
    154     SHR_BITTEST_RANGE(_td2_vp_lag_info[_u_]->vp_lag_egr_member_bitmap, _idx_, _count_, _result_)
    155 
    156 #define VP_LAG_GROUP_INFO(_u_, _idx_) (_td2_vp_lag_info[_u_]->group_info[_idx_])
    157 
    158 #define VP_LAG_MEMBER_INFO(_u_, _lag_idx_) (VP_LAG_GROUP_INFO(_u_, _lag_idx_).vp_lag_member_info)
    159 
    160 
    161 #endif /* INCLUDE_L3 */
    162 
    163 /*
    164  * Function:
    165  *      bcm_td2_hg_rh_deinit
    166  * Purpose:
    167  *      Deallocate Higig resilient hashing internal data structures
    168  * Parameters:
    169  *      unit - (IN) SOC unit number.
    170  * Returns:
    171  *      BCM_E_xxx
    172  */
    173 void
    174 bcm_td2_hg_rh_deinit(int unit)
    175 {
    176     if (_td2_hg_rh_info[unit]) {
    177         if (_td2_hg_rh_info[unit]->hg_rh_flowset_block_bitmap) {
    178             sal_free(_td2_hg_rh_info[unit]->hg_rh_flowset_block_bitmap);
    179             _td2_hg_rh_info[unit]->hg_rh_flowset_block_bitmap = NULL;
    180         }
    181         sal_free(_td2_hg_rh_info[unit]);
    182         _td2_hg_rh_info[unit] = NULL;
    183     }
    184 }
    185 
    186 /*
    187  * Function:
    188  *      bcm_td2_hg_rh_init
    189  * Purpose:
    190  *      Initialize Higig resilient hashing internal data structures
    191  * Parameters:
    192  *      unit - (IN) SOC unit number.
    193  * Returns:
    194  *      BCM_E_xxx
    195  */
    196 int
    197 bcm_td2_hg_rh_init(int unit)
    198 {
    199     int num_blocks;
    200 
    201     if (_td2_hg_rh_info[unit] == NULL) {
    202         _td2_hg_rh_info[unit] = sal_alloc(sizeof(_td2_hg_rh_info_t),
    203                 "_td2_hg_rh_info");
    204         if (_td2_hg_rh_info[unit] == NULL) {
    205             return BCM_E_MEMORY;
    206         }
    207         sal_memset(_td2_hg_rh_info[unit], 0, sizeof(_td2_hg_rh_info_t));
    208     }
    209 
    210     /* Each bit in hg_rh_flowset_block_bitmap corresponds to a block of 64
    211      * resilient hashing flow set table entries.
    212      */
    213     num_blocks = soc_mem_index_count(unit, RH_HGT_FLOWSETm) / 64;
    214     if (_td2_hg_rh_info[unit]->hg_rh_flowset_block_bitmap == NULL) {
    215         _td2_hg_rh_info[unit]->hg_rh_flowset_block_bitmap = 
    216             sal_alloc(SHR_BITALLOCSIZE(num_blocks),
    217                     "hg_rh_flowset_block_bitmap");
    218         if (_td2_hg_rh_info[unit]->hg_rh_flowset_block_bitmap == NULL) {
    219             bcm_td2_hg_rh_deinit(unit);
    220             return BCM_E_MEMORY;
    221         }
    222         sal_memset(_td2_hg_rh_info[unit]->hg_rh_flowset_block_bitmap, 0,
    223                 SHR_BITALLOCSIZE(num_blocks));
    224     }
    225 
    226     /* Set the seed for the pseudo-random number generator */
    227     _td2_hg_rh_info[unit]->hg_rh_rand_seed = sal_time_usecs();
    228 
    229     if (!SOC_WARM_BOOT(unit)) {
    230         /* Clear Higig resilient hashing group control table */
    231         if (SOC_MEM_IS_VALID(unit, RH_HGT_GROUP_CONTROLm)) {
    232             SOC_IF_ERROR_RETURN
    233                 (soc_mem_clear(unit, RH_HGT_GROUP_CONTROLm, MEM_BLOCK_ALL, 0));
    234         }
    235     }
    236     return BCM_E_NONE;
    237 }
    238 
    239 /*
    240  * Function:
    241  *      bcm_td2_hg_rh_dynamic_size_encode
    242  * Purpose:
    243  *      Encode Higig trunk resilient hashing flow set size.
    244  * Parameters:
    245  *      dynamic_size - (IN) Number of flow sets.
    246  *      encoded_value - (OUT) Encoded value.
    247  * Returns:
    248  *      BCM_E_xxx
    249  */
    250 int
    251 bcm_td2_hg_rh_dynamic_size_encode(int unit, int dynamic_size,
    252                                   int *encoded_value)
    253 {   
    254 #ifdef BCM_HELIX5_SUPPORT
    255     if (SOC_IS_HELIX5(unit)) {
    256         return _bcm_hx5_hg_rh_dynamic_size_encode(dynamic_size, encoded_value);
    257     }
    258 #endif /* BCM_HELIX5_SUPPORT */
    259     switch (dynamic_size) {
    260         case 64:
    261             *encoded_value = 1;
    262             break;
    263         case 128:
    264             *encoded_value = 2;
    265             break;
    266         case 256:
    267             *encoded_value = 3;
    268             break;
    269         case 512:
    270             *encoded_value = 4;
    271             break;
    272         case 1024:
    273             *encoded_value = 5;
    274             break;
    275         case 2048:
    276             *encoded_value = 6;
    277             break;
    278         case 4096:
    279             *encoded_value = 7;
    280             break;
    281         case 8192:
    282             *encoded_value = 8;
    283             break;
    284         case 16384:
    285             *encoded_value = 9;
    286             break;
    287         case 32768:
    288             *encoded_value = 10;
    289             break;
    290         case 65536:
    291             *encoded_value = 11;
    292             break;
    293         default:
    294             return BCM_E_PARAM;
    295     }
    296 
    297     return BCM_E_NONE;
    298 }
    299 
    300 /*
    301  * Function:
    302  *      _bcm_td2_hg_rh_dynamic_size_decode
    303  * Purpose:
    304  *      Decode Higig trunk resilient hashing flow set size.
    305  * Parameters:
    306  *      encoded_value - (IN) Encoded value.
    307  *      dynamic_size - (OUT) Number of flow sets.
    308  * Returns:
    309  *      BCM_E_xxx
    310  */
    311 STATIC int
    312 _bcm_td2_hg_rh_dynamic_size_decode(int unit, int encoded_value,
    313                                    int *dynamic_size)
    314 {   
    315 #ifdef BCM_HELIX5_SUPPORT
    316     if (SOC_IS_HELIX5(unit)) {
    317         return _bcm_hx5_hg_rh_dynamic_size_decode(encoded_value, dynamic_size);
    318     }
    319 #endif /* BCM_HELIX5_SUPPORT */
    320     switch (encoded_value) {
    321         case 1:
    322             *dynamic_size = 64;
    323             break;
    324         case 2:
    325             *dynamic_size = 128;
    326             break;
    327         case 3:
    328             *dynamic_size = 256;
    329             break;
    330         case 4:
    331             *dynamic_size = 512;
    332             break;
    333         case 5:
    334             *dynamic_size = 1024;
    335             break;
    336         case 6:
    337             *dynamic_size = 2048;
    338             break;
    339         case 7:
    340             *dynamic_size = 4096;
    341             break;
    342         case 8:
    343             *dynamic_size = 8192;
    344             break;
    345         case 9:
    346             *dynamic_size = 16384;
    347             break;
    348         case 10:
    349             *dynamic_size = 32768;
    350             break;
    351         case 11:
    352             *dynamic_size = 65536;
    353             break;
    354         default:
    355             return BCM_E_INTERNAL;
    356     }
    357 
    358     return BCM_E_NONE;
    359 }
    360 
    361 /*
    362  * Function:
    363  *      bcm_td2_hg_rh_status_get
    364  * Purpose:
    365  *      Check if resilient hashing is enabled on any Higig trunk group.
    366  * Parameters:
    367  *      unit  - (IN) SOC unit number. 
    368  *      rh_status - (OUT) Higig resilient hashing status
    369  * Returns:
    370  *      BCM_E_xxx
    371  */
    372 int
    373 bcm_td2_hg_rh_status_get(int unit, int *rh_status)
    374 {
    375     bcm_trunk_chip_info_t chip_info;
    376     int i;
    377     int psc;
    378     int rv;
    379 
    380     *rh_status = FALSE;
    381 
    382     BCM_IF_ERROR_RETURN(bcm_esw_trunk_chip_info_get(unit, &chip_info));
    383     if (chip_info.trunk_fabric_id_min < 0) {
    384         /* There are no Higig trunk groups. */
    385         return BCM_E_NOT_FOUND;
    386     }
    387 
    388     for (i = chip_info.trunk_fabric_id_min;
    389             i <= chip_info.trunk_fabric_id_max; i++) {
    390         rv = bcm_esw_trunk_psc_get(unit, i, &psc);
    391         if ((rv != BCM_E_NONE) && (rv != BCM_E_NOT_FOUND)) {
    392             return rv;
    393         }
    394         if (psc == BCM_TRUNK_PSC_DYNAMIC_RESILIENT) {
    395             *rh_status = TRUE;
    396             break;
    397         }
    398     }
    399 
    400     return BCM_E_NONE;
    401 }
    402 
    403 /*
    404  * Function:
    405  *      bcm_td2_hg_rh_free_resource
    406  * Purpose:
    407  *      Free resources for a Higig resilient hashing.
    408  * Parameters:
    409  *      unit  - (IN) SOC unit number. 
    410  *      hgtid - (IN) Higig group ID.
    411  * Returns:
    412  *      BCM_E_xxx
    413  */
    414 int
    415 bcm_td2_hg_rh_free_resource(int unit, int hgtid)
    416 {
    417     int rv = BCM_E_NONE;
    418     uint32 rval;
    419     rh_hgt_group_control_entry_t rh_hgt_group_control_entry;
    420     hg_trunk_group_entry_t hg_trunk_group_entry;
    421     int entry_base_ptr;
    422     int flow_set_size;
    423     int num_entries;
    424     int block_base_ptr;
    425     int num_blocks;
    426     int alloc_size;
    427     uint32 *buf_ptr = NULL;
    428     int index_min, index_max;
    429     hg_trunk_mode_entry_t hg_trunk_mode_entry;
    430     if (soc_reg_field_valid(unit, ENHANCED_HASHING_CONTROLr, RH_HGT_ENABLEf)) {
    431         SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROLr(unit, &rval));
    432         if (0 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROLr, rval,
    433                 RH_HGT_ENABLEf)) {
    434            /* Higig resilient hashing is not enabled chip-wide. */
    435             return BCM_E_NONE;
    436         }
    437     } else {
    438         SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROL_2r(unit, &rval));
    439         if (0 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROL_2r, rval,
    440                 RH_DLB_SELECTIONf)) {
    441            /* Higig resilient hashing is not enabled chip-wide. */
    442             return BCM_E_NONE;
    443         }
    444     }
    445 
    446     SOC_IF_ERROR_RETURN(READ_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, hgtid,
    447                 &hg_trunk_group_entry));
    448     if (soc_mem_field_valid(unit, HG_TRUNK_GROUPm, ENHANCED_HASHING_ENABLEf)) {
    449         if (0 == soc_HG_TRUNK_GROUPm_field32_get(unit,
    450                           &hg_trunk_group_entry, ENHANCED_HASHING_ENABLEf)) {
    451             /* Either (1) resilient hashing is not enabled on this Higig trunk
    452              * group, or (2) resilient hahsing is enabled with no members.
    453              * In case (2), RH_HGT_GROUP_CONTROL.FLOW_SET_SIZE needs to be cleared.
    454             */
    455             SOC_IF_ERROR_RETURN(WRITE_RH_HGT_GROUP_CONTROLm(unit, MEM_BLOCK_ALL,
    456                     hgtid, soc_mem_entry_null(unit, RH_HGT_GROUP_CONTROLm)));
    457             return BCM_E_NONE;
    458         }
    459         /* Clear ENHANCED_HASHING_ENABLE in HG_TRUNK_GROUP */
    460         soc_HG_TRUNK_GROUPm_field32_set(unit, &hg_trunk_group_entry,
    461                      ENHANCED_HASHING_ENABLEf, 0);
    462         SOC_IF_ERROR_RETURN(WRITE_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ALL, hgtid,
    463                      &hg_trunk_group_entry));
    464 
    465         /* Clear RH_HGT_GROUP_CONTROL entry */
    466         SOC_IF_ERROR_RETURN(READ_RH_HGT_GROUP_CONTROLm(unit, MEM_BLOCK_ANY,
    467                      hgtid, &rh_hgt_group_control_entry));
    468         entry_base_ptr = soc_RH_HGT_GROUP_CONTROLm_field32_get(unit,
    469                     &rh_hgt_group_control_entry, FLOW_SET_BASEf);
    470         flow_set_size = soc_RH_HGT_GROUP_CONTROLm_field32_get(unit,
    471                     &rh_hgt_group_control_entry, FLOW_SET_SIZEf);
    472         SOC_IF_ERROR_RETURN(WRITE_RH_HGT_GROUP_CONTROLm(unit, MEM_BLOCK_ALL,
    473                     hgtid, soc_mem_entry_null(unit, RH_HGT_GROUP_CONTROLm)));
    474     } else {
    475         SOC_IF_ERROR_RETURN(READ_HG_TRUNK_MODEm(unit, MEM_BLOCK_ANY, hgtid,
    476                     &hg_trunk_mode_entry));
    477         if (1 != soc_HG_TRUNK_MODEm_field32_get(unit,
    478                           &hg_trunk_mode_entry, HG_TRUNK_LB_MODEf)) {
    479             return BCM_E_NONE;
    480         }
    481         /* Clear ENHANCED_HASHING_ENABLE in HG_TRUNK_MODE */
    482         SOC_IF_ERROR_RETURN(WRITE_HG_TRUNK_MODEm(unit, MEM_BLOCK_ALL,
    483                     hgtid, soc_mem_entry_null(unit, HG_TRUNK_MODEm)));
    484 
    485         entry_base_ptr = soc_HG_TRUNK_GROUPm_field32_get(unit,
    486                     &hg_trunk_group_entry, RH_FLOW_SET_BASEf);
    487         flow_set_size = soc_HG_TRUNK_GROUPm_field32_get(unit,
    488                     &hg_trunk_group_entry, RH_FLOW_SET_SIZEf);
    489 
    490 
    491       /* Clear ENHANCED_HASHING_ENABLE in HG_TRUNK_GROUP */
    492         soc_HG_TRUNK_GROUPm_field32_set(unit, &hg_trunk_group_entry,
    493                     RH_FLOW_SET_BASEf, 0);
    494         soc_HG_TRUNK_GROUPm_field32_set(unit, &hg_trunk_group_entry,
    495                     RH_FLOW_SET_SIZEf, 0);
    496         SOC_IF_ERROR_RETURN(WRITE_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ALL, hgtid,
    497                    &hg_trunk_group_entry));
    498     }
    499 
    500 
    501     /* Clear flow set table entries */
    502     BCM_IF_ERROR_RETURN
    503         (_bcm_td2_hg_rh_dynamic_size_decode(unit, flow_set_size, &num_entries));
    504     alloc_size = num_entries * sizeof(rh_hgt_flowset_entry_t);
    505     buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_HGT_FLOWSET entries");
    506     if (NULL == buf_ptr) {
    507         return BCM_E_MEMORY;
    508     }
    509     sal_memset(buf_ptr, 0, alloc_size);
    510     index_min = entry_base_ptr;
    511     index_max = index_min + num_entries - 1;
    512     rv = soc_mem_write_range(unit, RH_HGT_FLOWSETm, MEM_BLOCK_ALL,
    513             index_min, index_max, buf_ptr);
    514     if (SOC_FAILURE(rv)) {
    515         soc_cm_sfree(unit, buf_ptr);
    516         return rv;
    517     }
    518     soc_cm_sfree(unit, buf_ptr);
    519 
    520     /* Free flow set table resources */
    521     block_base_ptr = entry_base_ptr >> 6;
    522     num_blocks = num_entries >> 6; 
    523     _BCM_HG_RH_FLOWSET_BLOCK_USED_CLR_RANGE(unit, block_base_ptr, num_blocks);
    524 
    525     return BCM_E_NONE;
    526 }
    527 
    528 /*
    529  * Function:
    530  *      bcm_td2_hg_rh_dynamic_size_set
    531  * Purpose:
    532  *      Set the dynamic size for a Higig resilient hashing group with
    533  *      no members, so it can be recovered from hardware during warm boot.
    534  * Parameters:
    535  *      unit  - (IN) SOC unit number. 
    536  *      hgtid - (IN) Higig group ID.
    537  *      dynamic_size - (IN) Number of flow sets.
    538  * Returns:
    539  *      BCM_E_xxx
    540  */
    541 int
    542 bcm_td2_hg_rh_dynamic_size_set(int unit, int hgtid, int dynamic_size)
    543 {
    544     hg_trunk_group_entry_t hg_trunk_group_entry;
    545     rh_hgt_group_control_entry_t rh_hgt_group_control_entry;
    546     int flow_set_size;
    547     hg_trunk_mode_entry_t hg_trunk_mode_entry;
    548 
    549     SOC_IF_ERROR_RETURN(READ_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, hgtid,
    550                 &hg_trunk_group_entry));
    551 
    552     BCM_IF_ERROR_RETURN
    553         (bcm_td2_hg_rh_dynamic_size_encode(unit, dynamic_size, &flow_set_size));
    554     if (soc_mem_field_valid(unit, HG_TRUNK_GROUPm, ENHANCED_HASHING_ENABLEf)) {
    555         if (soc_HG_TRUNK_GROUPm_field32_get(unit, &hg_trunk_group_entry,
    556                 ENHANCED_HASHING_ENABLEf)) {
    557            /* Not expecting resilient hashing to be enabled */
    558             return BCM_E_INTERNAL;
    559         }
    560         SOC_IF_ERROR_RETURN(READ_RH_HGT_GROUP_CONTROLm(unit, MEM_BLOCK_ANY,
    561                      hgtid, &rh_hgt_group_control_entry));
    562         soc_RH_HGT_GROUP_CONTROLm_field32_set(unit, &rh_hgt_group_control_entry,
    563                 FLOW_SET_SIZEf, flow_set_size);
    564         SOC_IF_ERROR_RETURN(WRITE_RH_HGT_GROUP_CONTROLm(unit, MEM_BLOCK_ALL,
    565                 hgtid, &rh_hgt_group_control_entry));
    566     } else {
    567         SOC_IF_ERROR_RETURN(READ_HG_TRUNK_MODEm(unit, MEM_BLOCK_ANY, hgtid,
    568                     &hg_trunk_mode_entry));
    569         if (1 == soc_HG_TRUNK_MODEm_field32_get(unit,
    570                           &hg_trunk_mode_entry, HG_TRUNK_LB_MODEf)) {
    571 
    572            /* Not expecting resilient hashing to be enabled */
    573             return BCM_E_INTERNAL;
    574         }
    575         /* Update HG_TRUNK_GROUP */
    576         soc_HG_TRUNK_GROUPm_field32_set(unit, &hg_trunk_group_entry,
    577                     RH_FLOW_SET_SIZEf, flow_set_size);
    578         SOC_IF_ERROR_RETURN(WRITE_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ALL, hgtid,
    579                     &hg_trunk_group_entry));
    580     }
    581     return BCM_E_NONE;
    582 }
    583 
    584 /*
    585  * Function:
    586  *      _bcm_td2_hg_rh_rand_get
    587  * Purpose:
    588  *      Get a random number between 0 and the given max value.
    589  * Parameters:
    590  *      unit - (IN) SOC unit number. 
    591  *      rand_max - (IN) Maximum random number.
    592  *      rand_num - (OUT) Random number.
    593  * Returns:
    594  *      BCM_E_xxx
    595  * Notes:
    596  *      This procedure uses the pseudo-random number generator algorithm
    597  *      suggested by the C standard.
    598  */
    599 STATIC int
    600 _bcm_td2_hg_rh_rand_get(int unit, int rand_max, int *rand_num)
    601 {
    602     int modulus;
    603     int rand_seed_shift;
    604 
    605     if (rand_max < 0) {
    606         return BCM_E_PARAM;
    607     }
    608 
    609     if (NULL == rand_num) {
    610         return BCM_E_PARAM;
    611     }
    612 
    613     /* Make sure the modulus does not exceed limit. For instance,
    614      * if the 32-bit rand_seed is shifted to the right by 16 bits before
    615      * the modulo operation, the modulus should not exceed 1 << 16.
    616      */
    617     modulus = rand_max + 1;
    618     rand_seed_shift = 16;
    619     if (modulus > (1 << (32 - rand_seed_shift))) {
    620         return BCM_E_PARAM;
    621     }
    622 
    623     _td2_hg_rh_info[unit]->hg_rh_rand_seed =
    624         _td2_hg_rh_info[unit]->hg_rh_rand_seed * 1103515245 + 12345;
    625 
    626     *rand_num = (_td2_hg_rh_info[unit]->hg_rh_rand_seed >> rand_seed_shift) %
    627                 modulus;
    628 
    629     return BCM_E_NONE;
    630 }
    631 
    632 /*
    633  * Function:
    634  *      _bcm_td2_hg_rh_member_choose
    635  * Purpose:
    636  *      Choose a member of the Higig trunk group.
    637  * Parameters:
    638  *      unit - (IN) SOC unit number. 
    639  *      num_members - (IN) Number of members to choose from.
    640  *      entry_count_arr   - (IN/OUT) An array keeping track of how many
    641  *                                   flow set entries have been assigned
    642  *                                   to each member.
    643  *      max_entry_count   - (IN/OUT) The maximum number of flow set entries
    644  *                                   that can be assigned to a member. 
    645  *      chosen_index      - (OUT) The index of the chosen member.
    646  * Returns:
    647  *      BCM_E_xxx
    648  */
    649 STATIC int
    650 _bcm_td2_hg_rh_member_choose(int unit, int num_members, int *entry_count_arr,
    651         int *max_entry_count, int *chosen_index)
    652 {
    653     int member_index;
    654     int next_index;
    655 
    656     *chosen_index = 0;
    657 
    658     /* Choose a random member index */
    659     BCM_IF_ERROR_RETURN(_bcm_td2_hg_rh_rand_get(unit, num_members - 1,
    660                 &member_index));
    661 
    662     if (entry_count_arr[member_index] < *max_entry_count) {
    663         entry_count_arr[member_index]++;
    664         *chosen_index = member_index;
    665     } else {
    666         /* The randomly chosen member has reached the maximum
    667          * flow set entry count. Choose the next member that
    668          * has not reached the maximum entry count.
    669          */
    670         next_index = (member_index + 1) % num_members;
    671         while (next_index != member_index) {
    672             if (entry_count_arr[next_index] < *max_entry_count) {
    673                 entry_count_arr[next_index]++;
    674                 *chosen_index = next_index;
    675                 break;
    676             } else {
    677                 next_index = (next_index + 1) % num_members;
    678             }
    679         }
    680         if (next_index == member_index) {
    681             /* All members have reached the maximum flow set entry
    682              * count. This scenario occurs when dividing the number of
    683              * flow set entries by the number of members results
    684              * in a non-zero remainder. The remainder flow set entries
    685              * will be distributed among members, at most 1 remainder
    686              * entry per member.
    687              */
    688             (*max_entry_count)++;
    689             if (entry_count_arr[member_index] < *max_entry_count) {
    690                 entry_count_arr[member_index]++;
    691                 *chosen_index = member_index;
    692             } else {
    693                 /* It's possible that the member's entry count already equals
    694                  * to the incremented value of max_entry_count.
    695                  */
    696                 next_index = (member_index + 1) % num_members;
    697                 while (next_index != member_index) {
    698                     if (entry_count_arr[next_index] < *max_entry_count) {
    699                         entry_count_arr[next_index]++;
    700                         *chosen_index = next_index;
    701                         break;
    702                     } else {
    703                         next_index = (next_index + 1) % num_members;
    704                     }
    705                 }
    706                 if (next_index == member_index) {
    707                     return BCM_E_INTERNAL;
    708                 }
    709             }
    710         }
    711     }
    712 
    713     return BCM_E_NONE;
    714 }
    715 
    716 
    717 
    718 /*
    719  * Function:
    720  *      _bcm_td2_hg_rh_delete_rebalance
    721  * Purpose:
    722  *      Re-balance flow set entries from the leaving member to the remaining
    723  *      members. For example, if the number of flow set entries is 64, and
    724  *      the number of members is 6, then each member has between 10 and 11
    725  *      entries. The entries should be re-assigned from the leaving member to
    726  *      the remaining 5 members such that each remaining member will end up
    727  *      with between 12 and 13 entries.
    728  * Parameters:
    729  *      unit - (IN) SOC unit number.
    730  *      num_entries - (IN) Number of flow set entries.
    731  *      buf_ptr     - (IN/OUT) Flow set entry buffer.
    732  *      num_members - (IN) Number of entry_count_arr/ member_arr.
    733  *      entry_count_arr - (IN/OUT) An array keeping track of how many
    734  *                                 flow set entries have been assigned
    735  *                                 to each member.
    736  *      member_arr    - (IN) Array of new members (staying, joining)
    737  *      num_leaving   - (IN) Number of leaving_port.
    738  *      leaving_port  - (IN) Array of leaving members.
    739  * Returns:
    740  *      BCM_E_xxx
    741  */
    742 STATIC int
    743 _bcm_td2_hg_rh_delete_rebalance(int unit, int num_entries, uint32 *buf_ptr,
    744                     int num_members, int *entry_count_arr, int *member_arr,
    745                     int num_leaving, int *leaving_port)
    746 {
    747 
    748     int threshold;
    749     int i,j;
    750     int chosen_index;
    751     int egress_port;
    752     rh_hgt_flowset_entry_t *flowset_entry;
    753     soc_field_t port_fld = EGRESS_PORTf;
    754 
    755     if (!soc_mem_field_valid(unit, RH_HGT_FLOWSETm, port_fld)) {
    756         port_fld = PORT_NUMf;
    757     }
    758     threshold = num_entries / num_members;
    759     for (i = 0; i < num_entries; i++) {
    760         flowset_entry = soc_mem_table_idx_to_pointer(unit,
    761                 RH_HGT_FLOWSETm, rh_hgt_flowset_entry_t *, buf_ptr, i);
    762         egress_port = soc_mem_field32_get(unit, RH_HGT_FLOWSETm, flowset_entry,
    763                 port_fld);
    764         for (j = 0; j < num_leaving ; j++ ) {
    765             if (egress_port == leaving_port[j]) {
    766                 break;
    767             }
    768         }
    769         if (j < num_leaving) {
    770             /* Randomly choose a member among the remaining members */
    771             BCM_IF_ERROR_RETURN(_bcm_td2_hg_rh_member_choose(unit, num_members,
    772                     entry_count_arr, &threshold, &chosen_index));
    773             soc_mem_field32_set(unit, RH_HGT_FLOWSETm, flowset_entry, port_fld,
    774                     member_arr[chosen_index]);
    775         }
    776     }
    777     return BCM_E_NONE;
    778 }
    779 
    780 
    781 /*
    782  * Function:
    783  *      _bcm_td2_hg_rh_add_rebalance
    784  * Purpose:
    785  *      Re-balance flow set entries from existing members to the new member.
    786  *      For example, if the number of flow set entries is 64, and the number of
    787  *      existing members is 6, then each existing member has between 10 and 11
    788  *      entries. The entries should be re-assigned from the 6 existing members
    789  *      to the new member such that each member will end up with between 9 and
    790  *      10 entries.
    791  * Parameters:
    792  *      unit - (IN) SOC unit number.
    793  *      num_entries - (IN) Number of flow set entries.
    794  *      buf_ptr     - (IN/OUT) Flow set entry buffer.
    795  *      num_members - (IN) Number of entry_count_arr,
    796  *                         including the joining member.
    797  *      entry_count_arr - (IN/OUT) An array keeping track of how many
    798  *                                 flow set entries have been assigned
    799  *                                 to each member. The last element is
    800  *                                 joining member, hence is 0.
    801  *      joining_port     - (IN) Joining member.
    802  *      member_index_arr - (IN/OUT) Array of member indexes to entry_count_arr
    803  *                                  of existing members in Flow Set table. The
    804  *                                  element of joining is to be defined.
    805  * Returns:
    806  *      BCM_E_xxx
    807  */
    808 
    809 STATIC int
    810 _bcm_td2_hg_rh_add_rebalance(int unit, int num_entries, uint32 *buf_ptr,
    811                               int num_members, int *entry_count_arr,
    812                               int joining_port, int *member_index_arr)
    813 {
    814     rh_hgt_flowset_entry_t *flowset_entry;
    815     int member_index = 0;
    816     int lower_bound, upper_bound;
    817     int threshold;
    818     int entry_index, next_entry_index;
    819     int egress_port;
    820     int num_existing_members = num_members - 1;
    821     int new_member_entry_count = 0;
    822     soc_field_t port_fld = EGRESS_PORTf;
    823 
    824     if (!soc_mem_field_valid(unit, RH_HGT_FLOWSETm, port_fld)) {
    825         port_fld = PORT_NUMf;
    826     }
    827     lower_bound = num_entries / num_members;
    828     upper_bound = (num_entries % num_members) ?
    829                   (lower_bound + 1) : lower_bound;
    830     threshold = upper_bound;
    831     while (new_member_entry_count < lower_bound) {
    832         /* Pick a random entry in the flow set buffer */
    833         BCM_IF_ERROR_RETURN(_bcm_td2_hg_rh_rand_get(
    834     unit, num_entries - 1, &entry_index));
    835 
    836         flowset_entry = soc_mem_table_idx_to_pointer(unit, RH_HGT_FLOWSETm,
    837                 rh_hgt_flowset_entry_t *, buf_ptr, entry_index);
    838         egress_port = soc_mem_field32_get(unit, RH_HGT_FLOWSETm, flowset_entry,
    839                 port_fld);
    840         member_index = member_index_arr[egress_port];
    841         if ((egress_port != joining_port) &&
    842                 (entry_count_arr[member_index] > threshold)) {
    843             soc_mem_field32_set(unit, RH_HGT_FLOWSETm, flowset_entry,
    844                     port_fld, joining_port);
    845             entry_count_arr[member_index]--;
    846             new_member_entry_count++;
    847         } else {
    848             /* Either the member of the randomly chosen entry is
    849              * the same as the new member, or the member is an existing
    850              * member and its entry count has decreased to threshold.
    851              * In both cases, find the next entry that contains a
    852              * member that's not the new member and whose entry count
    853              * has not decreased to threshold.
    854              */
    855             next_entry_index = (entry_index + 1) % num_entries;
    856             while (next_entry_index != entry_index) {
    857                 flowset_entry = soc_mem_table_idx_to_pointer(unit,
    858                         RH_HGT_FLOWSETm, rh_hgt_flowset_entry_t *, buf_ptr,
    859                         next_entry_index);
    860                 egress_port = soc_mem_field32_get(unit, RH_HGT_FLOWSETm,
    861                         flowset_entry, port_fld);
    862                 member_index = member_index_arr[egress_port];
    863                 if ((egress_port != joining_port) &&
    864                         (entry_count_arr[member_index] > threshold)) {
    865                     soc_mem_field32_set(unit, RH_HGT_FLOWSETm, flowset_entry,
    866                             port_fld, joining_port);
    867                     entry_count_arr[member_index]--;
    868                     new_member_entry_count++;
    869                     break;
    870                 } else {
    871                     next_entry_index = (next_entry_index + 1) % num_entries;
    872                 }
    873             }
    874             if (next_entry_index == entry_index) {
    875                 /* The entry count of all existing members has decreased
    876                  * to threshold. The entry count of the new member has
    877                  * not yet increased to lower_bound. Lower the threshold.
    878                  */
    879                 threshold--;
    880             }
    881         }
    882     }
    883     entry_count_arr[num_existing_members] = new_member_entry_count;
    884     member_index_arr[joining_port] = num_existing_members;
    885 
    886     return BCM_E_NONE;
    887 }
    888 
    889 
    890 
    891 /*
    892  * Function:
    893  *      bcm_td2_hg_rh_set
    894  * Purpose:
    895  *      Configure a Higig resilient hashing group.
    896  * Parameters:
    897  *      unit  - (IN) SOC unit number. 
    898  *      hgtid - (IN) Higig trunk group ID.
    899  *      add_info - (IN) Pointer to trunk add info structure, which contains
    900  *                      all resilient hashing eligible members of the group.
    901  * Returns:
    902  *      BCM_E_xxx
    903  */
    904 int
    905 bcm_td2_hg_rh_set(int unit,
    906         int hgtid,
    907         _esw_trunk_add_info_t *add_info)
    908 {
    909     int rv = BCM_E_NONE;
    910     int num_blocks;
    911     int total_blocks;
    912     int max_block_base_ptr;
    913     int block_base_ptr;
    914     int entry_base_ptr;
    915     SHR_BITDCL occupied;
    916     int alloc_size;
    917     uint32 *buf_ptr = NULL;
    918     int *entry_count_arr = NULL;
    919     int max_entry_count;
    920     int chosen_index;
    921     int i;
    922     rh_hgt_flowset_entry_t *flowset_entry;
    923     int index_min, index_max;
    924     rh_hgt_group_control_entry_t rh_hgt_group_control_entry;
    925     int flow_set_size;
    926     hg_trunk_group_entry_t hg_trunk_group_entry;
    927     hg_trunk_mode_entry_t hg_trunk_mode_entry;
    928 
    929     if (add_info == NULL || add_info->psc != BCM_TRUNK_PSC_DYNAMIC_RESILIENT) {
    930         return BCM_E_PARAM;
    931     }
    932 
    933     if (add_info->num_ports == 0) {
    934         /* Write the dynamic_size to hardware, so it can be
    935          * recovered during warm boot.
    936          */
    937         BCM_IF_ERROR_RETURN(bcm_td2_hg_rh_dynamic_size_set(unit,
    938                     hgtid, add_info->dynamic_size));
    939 
    940         return BCM_E_NONE;
    941     }
    942 
    943     /* Find a contiguous region of flow set table that's large
    944      * enough to hold the requested number of flow sets.
    945      * The flow set table is allocated in 64-entry blocks.
    946      */
    947     num_blocks = add_info->dynamic_size >> 6;
    948     total_blocks = soc_mem_index_count(unit, RH_HGT_FLOWSETm) >> 6;
    949     max_block_base_ptr = total_blocks - num_blocks;
    950     for (block_base_ptr = 0;
    951          block_base_ptr <= max_block_base_ptr;
    952          block_base_ptr++) {
    953         /* Check if the contiguous region of flow set table from
    954          * block_base_ptr to (block_base_ptr + num_blocks - 1) is free. 
    955          */
    956         _BCM_HG_RH_FLOWSET_BLOCK_TEST_RANGE(unit, block_base_ptr, num_blocks,
    957                 occupied); 
    958         if (!occupied) {
    959             break;
    960         }
    961     }
    962     if (block_base_ptr > max_block_base_ptr) {
    963         /* A contiguous region of the desired size could not be found in
    964          * flow set table.
    965          */
    966         return BCM_E_RESOURCE;
    967     }
    968 
    969     /* Configure flow set table */
    970     alloc_size = add_info->dynamic_size * sizeof(rh_hgt_flowset_entry_t);
    971     buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_HGT_FLOWSET entries");
    972     if (NULL == buf_ptr) {
    973         return BCM_E_MEMORY;
    974     }
    975     sal_memset(buf_ptr, 0, alloc_size);
    976 
    977     entry_count_arr = sal_alloc(sizeof(int) * add_info->num_ports,
    978             "RH entry count array");
    979     if (NULL == entry_count_arr) {
    980         soc_cm_sfree(unit, buf_ptr);
    981         return BCM_E_MEMORY;
    982     }
    983     sal_memset(entry_count_arr, 0, sizeof(int) * add_info->num_ports);
    984     max_entry_count = add_info->dynamic_size / add_info->num_ports;
    985 
    986     for (i = 0; i < add_info->dynamic_size; i++) {
    987         /* Choose a member of the Higig trunk group */
    988         rv = _bcm_td2_hg_rh_member_choose(unit, add_info->num_ports,
    989                 entry_count_arr, &max_entry_count, &chosen_index);
    990         if (BCM_FAILURE(rv)) {
    991             soc_cm_sfree(unit, buf_ptr);
    992             sal_free(entry_count_arr);
    993             return rv;
    994         }
    995 
    996         /* Set flow set entry */
    997         flowset_entry = soc_mem_table_idx_to_pointer(unit,
    998                 RH_HGT_FLOWSETm, rh_hgt_flowset_entry_t *, buf_ptr, i);
    999         soc_mem_field32_set(unit, RH_HGT_FLOWSETm, flowset_entry, VALIDf, 1);
   1000         if (soc_mem_field_valid(unit, RH_HGT_FLOWSETm, EGRESS_PORTf)) {
   1001             soc_mem_field32_set(unit, RH_HGT_FLOWSETm, flowset_entry, EGRESS_PORTf,
   1002                     add_info->tp[chosen_index]);
   1003         } else {
   1004             soc_mem_field32_set(unit, RH_HGT_FLOWSETm, flowset_entry, PORT_NUMf,
   1005                     add_info->tp[chosen_index]);
   1006         }
   1007     }
   1008 
   1009     entry_base_ptr = block_base_ptr << 6;
   1010     index_min = entry_base_ptr;
   1011     index_max = index_min + add_info->dynamic_size - 1;
   1012     rv = soc_mem_write_range(unit, RH_HGT_FLOWSETm, MEM_BLOCK_ALL,
   1013             index_min, index_max, buf_ptr);
   1014     if (SOC_FAILURE(rv)) {
   1015         soc_cm_sfree(unit, buf_ptr);
   1016         sal_free(entry_count_arr);
   1017         return rv;
   1018     }
   1019     soc_cm_sfree(unit, buf_ptr);
   1020     sal_free(entry_count_arr);
   1021 
   1022     _BCM_HG_RH_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr, num_blocks);
   1023     BCM_IF_ERROR_RETURN(bcm_td2_hg_rh_dynamic_size_encode(unit,
   1024                 add_info->dynamic_size, &flow_set_size));
   1025 
   1026     /* Update HG_TRUNK_GROUP */
   1027     SOC_IF_ERROR_RETURN(READ_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, hgtid,
   1028                 &hg_trunk_group_entry));
   1029     /* Update Higig RH group control table */
   1030     if (soc_feature(unit, soc_feature_td3_style_dlb_rh)) {
   1031         soc_HG_TRUNK_GROUPm_field32_set(unit, &hg_trunk_group_entry,
   1032                     RH_FLOW_SET_BASEf, entry_base_ptr);
   1033         soc_HG_TRUNK_GROUPm_field32_set(unit, &hg_trunk_group_entry,
   1034                     RH_FLOW_SET_SIZEf, flow_set_size);
   1035 
   1036         sal_memset(&hg_trunk_mode_entry, 0, sizeof(hg_trunk_mode_entry_t));
   1037         soc_HG_TRUNK_MODEm_field32_set(unit, &hg_trunk_mode_entry,
   1038             HG_TRUNK_LB_MODEf, 1);
   1039         SOC_IF_ERROR_RETURN(WRITE_HG_TRUNK_MODEm(unit, MEM_BLOCK_ALL, hgtid,
   1040                    &hg_trunk_mode_entry));
   1041     } else {
   1042         sal_memset(&rh_hgt_group_control_entry, 0,
   1043                    sizeof(rh_hgt_group_control_entry_t));
   1044         soc_RH_HGT_GROUP_CONTROLm_field32_set(unit, &rh_hgt_group_control_entry,
   1045                    FLOW_SET_BASEf, entry_base_ptr);
   1046         BCM_IF_ERROR_RETURN(bcm_td2_hg_rh_dynamic_size_encode(unit,
   1047                     add_info->dynamic_size, &flow_set_size));
   1048         soc_RH_HGT_GROUP_CONTROLm_field32_set(unit, &rh_hgt_group_control_entry,
   1049                   FLOW_SET_SIZEf, flow_set_size);
   1050         SOC_IF_ERROR_RETURN(WRITE_RH_HGT_GROUP_CONTROLm(unit, MEM_BLOCK_ALL,
   1051                 hgtid, &rh_hgt_group_control_entry));
   1052         soc_HG_TRUNK_GROUPm_field32_set(unit, &hg_trunk_group_entry,
   1053             ENHANCED_HASHING_ENABLEf, 1);
   1054     }
   1055     SOC_IF_ERROR_RETURN(WRITE_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ALL, hgtid,
   1056                 &hg_trunk_group_entry));
   1057 
   1058     return BCM_E_NONE;
   1059 }
   1060 
   1061 
   1062 /*
   1063  * Function:
   1064  *      bcm_td2_hg_rh_replace
   1065  * Purpose:
   1066  *      Replace Higig resilient hashing group members without flowset table shuffle.
   1067  * Parameters:
   1068  *      unit  - (IN) SOC unit number.
   1069  *      hgtid - (IN) Higig trunk group ID.
   1070  *      add_info - (IN) Pointer to trunk add info structure, which contains
   1071  *                      all resilient hashing eligible members of the group.
   1072  *      num_existing   - (IN) Number of existing members.
   1073  *      existing_ports - (IN) Ports of existing members.
   1074  *      existing_flags - (IN) Flags of existing members.
   1075  * Returns:
   1076  *      BCM_E_xxx
   1077  */
   1078 int
   1079 bcm_td2_hg_rh_replace(int unit,
   1080                       int hgtid,
   1081                       _esw_trunk_add_info_t *add_info,
   1082                       uint16 num_existing,
   1083                       uint16 *existing_ports,
   1084                       uint32 *existing_flags)
   1085 {
   1086     int                     rv = BCM_E_NONE;
   1087     int                    *leaving_ports = NULL;
   1088     int                    *staying_ports = NULL;
   1089     int                    *joining_ports = NULL;
   1090     int                     num_leaving = 0;
   1091     int                     num_staying = 0;
   1092     int                     num_joining = 0;
   1093     int                     num_partial;
   1094     int                     num_new;
   1095     int                     *new_ports;
   1096     int                     *rearr_ports = NULL;
   1097     int                     i, j, k;
   1098     int                     index_min= 0;
   1099     int                     index_max= 0;
   1100     int                     num_entries = 0;
   1101     int                     alloc_size;
   1102     uint32                  *buf_ptr = NULL;
   1103     int                     *entry_count_arr = NULL;
   1104     int                     member;
   1105     int                     *member_index_arr = NULL;
   1106     rh_hgt_flowset_entry_t  *fs_entry;
   1107     rh_hgt_group_control_entry_t hgt_entry;
   1108     hg_trunk_group_entry_t hg_trunk_group_entry;
   1109     soc_field_t port_fld = EGRESS_PORTf;
   1110 
   1111     if (!soc_mem_field_valid(unit, RH_HGT_FLOWSETm, port_fld)) {
   1112         port_fld = PORT_NUMf;
   1113     }
   1114     if (add_info == NULL ||
   1115         add_info->psc != BCM_TRUNK_PSC_DYNAMIC_RESILIENT) {
   1116         return BCM_E_PARAM;
   1117     }
   1118 
   1119     num_new    = add_info->num_ports;
   1120     new_ports  = add_info->tp;
   1121     if (num_new > 0 && (new_ports == NULL)) {
   1122         return BCM_E_PARAM;
   1123     }
   1124     if (num_existing &&
   1125         (existing_ports == NULL || existing_flags == NULL)) {
   1126         return BCM_E_PARAM;
   1127     }
   1128 
   1129     if (num_new == 1 || num_new == 0 || num_existing == 0) {
   1130         rv = bcm_td2_hg_rh_free_resource(unit, hgtid);
   1131         rv = BCM_FAILURE(rv) ? rv :
   1132              bcm_td2_hg_rh_set(unit, hgtid, add_info);
   1133         goto cleanup;
   1134     }
   1135 
   1136     /* Figure out which members are leaving, staying or joining
   1137      * the trunk group.
   1138      * Note. For resilient hash, all members are different within a TRUNK.
   1139      */
   1140     alloc_size = sizeof(int) * num_existing;
   1141     leaving_ports = sal_alloc(alloc_size, "leaving ports");
   1142     if (leaving_ports == NULL) {
   1143         rv = BCM_E_MEMORY;
   1144         goto cleanup;
   1145     }
   1146     sal_memset(leaving_ports, 0, alloc_size);
   1147 
   1148     alloc_size = sizeof(int) * num_existing;
   1149     staying_ports = sal_alloc(alloc_size, "staying members");
   1150     if (staying_ports == NULL) {
   1151         rv = BCM_E_MEMORY;
   1152         goto cleanup;
   1153     }
   1154     sal_memset(staying_ports, 0, alloc_size);
   1155 
   1156     for (i = 0; i < num_existing; i++) {
   1157         for (j = 0; j < num_new; j++) {
   1158             if (existing_ports[i] == new_ports[j]) {
   1159                 break;
   1160             }
   1161         }
   1162         if (j == num_new) {
   1163             leaving_ports[num_leaving++] = existing_ports[i];
   1164         } else {
   1165             staying_ports[num_staying++] = existing_ports[i];
   1166         }
   1167     }
   1168 
   1169     alloc_size = sizeof(int) * num_new;
   1170     joining_ports = sal_alloc(alloc_size, "joining members");
   1171     if (joining_ports == NULL) {
   1172         rv = BCM_E_MEMORY;
   1173         goto cleanup;
   1174     }
   1175     sal_memset(joining_ports, 0, alloc_size);
   1176 
   1177     for (i = 0; i < num_new; i++) {
   1178         for (j = 0; j < num_staying; j++) {
   1179             if (new_ports[i] == staying_ports[j]) {
   1180                 break;
   1181             }
   1182         }
   1183         if (j == num_staying) {
   1184             joining_ports[num_joining++] = new_ports[i];
   1185         }
   1186     }
   1187 
   1188     if (num_staying + num_leaving != num_existing) {
   1189         rv = BCM_E_INTERNAL;
   1190         goto cleanup;
   1191     }
   1192     if (num_staying + num_joining != num_new) {
   1193         rv = BCM_E_INTERNAL;
   1194         goto cleanup;
   1195     }
   1196 
   1197     if (soc_feature(unit, soc_feature_td3_style_dlb_rh)) {
   1198         rv = READ_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, hgtid,
   1199                       &hg_trunk_group_entry);
   1200         if (SOC_FAILURE(rv)) {
   1201             goto cleanup;
   1202         }
   1203         index_min = soc_HG_TRUNK_GROUPm_field32_get(unit,
   1204                         &hg_trunk_group_entry, RH_FLOW_SET_BASEf);
   1205         num_entries = soc_HG_TRUNK_GROUPm_field32_get(unit,
   1206                         &hg_trunk_group_entry, RH_FLOW_SET_SIZEf);
   1207 
   1208     } else {
   1209         rv = READ_RH_HGT_GROUP_CONTROLm(unit, MEM_BLOCK_ANY, hgtid,
   1210               &hgt_entry);
   1211         if (SOC_FAILURE(rv)) {
   1212             goto cleanup;
   1213         }
   1214         index_min = soc_RH_HGT_GROUP_CONTROLm_field32_get(unit,
   1215                         &hgt_entry, FLOW_SET_BASEf);
   1216         num_entries = soc_RH_HGT_GROUP_CONTROLm_field32_get(unit,
   1217                         &hgt_entry, FLOW_SET_SIZEf);
   1218     }
   1219     rv = _bcm_td2_hg_rh_dynamic_size_decode(unit, num_entries, &num_entries);
   1220     if (BCM_FAILURE(rv)) {
   1221         goto cleanup;
   1222     }
   1223 
   1224     index_max = index_min + num_entries - 1;
   1225     alloc_size = num_entries * sizeof(rh_hgt_flowset_entry_t);
   1226     buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_HG_FLOWSET entries");
   1227     if (NULL == buf_ptr) {
   1228         rv = BCM_E_MEMORY;
   1229         goto cleanup;
   1230     }
   1231     sal_memset(buf_ptr, 0, alloc_size);
   1232 
   1233     /* Read various tables through DMA */
   1234     if ((rv = soc_mem_read_range(unit, RH_HGT_FLOWSETm, MEM_BLOCK_ANY,
   1235                     index_min, index_max, buf_ptr)) < 0 ) {
   1236         goto cleanup;
   1237     }
   1238 
   1239     /* Get re-arrange ports */
   1240     num_partial = num_existing > num_new ? num_new : num_existing;
   1241     alloc_size = num_partial * sizeof(int);
   1242     rearr_ports = sal_alloc(alloc_size, "rearr_ports");
   1243     if (rearr_ports == NULL) {
   1244         rv = BCM_E_MEMORY;
   1245         goto cleanup;
   1246     }
   1247     sal_memset(rearr_ports, 0, alloc_size);
   1248 
   1249     for (i = 0; i < num_staying; i++) {
   1250         rearr_ports[i] = staying_ports[i];
   1251     }
   1252     for (i = num_staying, k = 0; i < num_partial; i++) {
   1253         rearr_ports[i] = joining_ports[k];
   1254         k++;
   1255     }
   1256 
   1257     /* Get entry count for each staying member port */
   1258     alloc_size = num_new * sizeof(int);
   1259     entry_count_arr = sal_alloc(alloc_size, "RH entry count array");
   1260     if (NULL == entry_count_arr) {
   1261         rv = BCM_E_MEMORY;
   1262         goto cleanup;
   1263     }
   1264     sal_memset(entry_count_arr, 0, alloc_size);
   1265 
   1266     for (i = 0; i < num_entries; i++) {
   1267         fs_entry = soc_mem_table_idx_to_pointer(unit,
   1268                 RH_HGT_FLOWSETm, rh_hgt_flowset_entry_t *, buf_ptr, i);
   1269         if (!soc_mem_field32_get(unit, RH_HGT_FLOWSETm, fs_entry,
   1270                     VALIDf)) {
   1271             rv = BCM_E_INTERNAL;
   1272             goto cleanup;
   1273         }
   1274         member = soc_mem_field32_get(unit, RH_HGT_FLOWSETm, fs_entry, port_fld);
   1275         for (j = 0; j < num_staying; j++) {
   1276             if (member == rearr_ports[j]) {
   1277                 break;
   1278             }
   1279         }
   1280 
   1281         if (j < num_staying) {
   1282             entry_count_arr[j]++;
   1283         }
   1284     }
   1285 
   1286     /* Get member index for each partial member port */
   1287     alloc_size = SOC_MAX_NUM_PORTS * sizeof(int);
   1288     member_index_arr = sal_alloc(alloc_size, "member index array");
   1289     if (NULL == member_index_arr) {
   1290         rv = BCM_E_MEMORY;
   1291         goto cleanup;
   1292     }
   1293     for (i = 0; i < SOC_MAX_NUM_PORTS; i++) {
   1294         member_index_arr[i] = -1;
   1295     }
   1296     for (i = 0; i < num_partial; i++) {
   1297         member_index_arr[rearr_ports[i]] = i;
   1298     }
   1299 
   1300     if (num_leaving > 0) {
   1301         rv = _bcm_td2_hg_rh_delete_rebalance(unit, num_entries, buf_ptr,
   1302                          num_partial, entry_count_arr, rearr_ports,
   1303                          num_leaving, leaving_ports);
   1304         if (BCM_FAILURE(rv)) {
   1305             goto cleanup;
   1306         }
   1307     }
   1308 
   1309     for (j = num_partial; j < num_new; j++) {
   1310         rv = _bcm_td2_hg_rh_add_rebalance(unit, num_entries, buf_ptr,
   1311                         j + 1, entry_count_arr,
   1312                         joining_ports[k], member_index_arr);
   1313         if (BCM_FAILURE(rv)) {
   1314             goto cleanup;
   1315         }
   1316         k++;
   1317     }
   1318 
   1319     /* Write re-balanced flow set entries to hardware */
   1320     rv = soc_mem_write_range(unit, RH_HGT_FLOWSETm, MEM_BLOCK_ALL,
   1321             index_min, index_max, buf_ptr);
   1322 
   1323 cleanup:
   1324     if(leaving_ports) {
   1325         sal_free(leaving_ports);
   1326     }
   1327     if(staying_ports) {
   1328         sal_free(staying_ports);
   1329     }
   1330     if(joining_ports) {
   1331         sal_free(joining_ports);
   1332     }
   1333     if(rearr_ports) {
   1334         sal_free(rearr_ports);
   1335     }
   1336     if(buf_ptr) {
   1337         soc_cm_sfree(unit, buf_ptr);
   1338     }
   1339     if(entry_count_arr) {
   1340         sal_free(entry_count_arr);
   1341     }
   1342     if(member_index_arr) {
   1343         sal_free(member_index_arr);
   1344     }
   1345     return rv;
   1346 
   1347 }
   1348 
   1349 
   1350 
   1351 
   1352 /*
   1353  * Function:
   1354  *      bcm_td2_hg_rh_add
   1355  * Purpose:
   1356  *      Add a member to a Higig resilient hashing group.
   1357  * Parameters:
   1358  *      unit  - (IN) SOC unit number.
   1359  *      hgtid - (IN) Higig trunk group ID.
   1360  *      add_info - (IN) Pointer to trunk add info structure, which contains
   1361  *                      all resilient hashing eligible members of the group,
   1362  *                      including the member to be added.
   1363  *      new_member - (IN) Member to add.
   1364  * Returns:
   1365  *      BCM_E_xxx
   1366  */
   1367 int
   1368 bcm_td2_hg_rh_add(int unit,
   1369         int hgtid,
   1370         _esw_trunk_add_info_t *add_info,
   1371         bcm_trunk_member_t *new_member)
   1372 {
   1373     int rv = BCM_E_NONE;
   1374     bcm_port_t new_port;
   1375     bcm_module_t new_mod;
   1376     bcm_port_t tmp_port;
   1377     int tmp_index = -1;
   1378     int num_existing_members;
   1379     int *member_index_arr = NULL;
   1380     int i;
   1381     rh_hgt_group_control_entry_t rh_hgt_group_control_entry;
   1382     int entry_base_ptr;
   1383     int flow_set_size;
   1384     int num_entries;
   1385     int alloc_size;
   1386     uint32 *buf_ptr = NULL;
   1387     int index_min, index_max;
   1388     int *entry_count_arr = NULL;
   1389     rh_hgt_flowset_entry_t *flowset_entry;
   1390     int egress_port;
   1391     int member_index;
   1392     int lower_bound, upper_bound;
   1393     hg_trunk_group_entry_t hg_trunk_group_entry;
   1394 
   1395     soc_field_t port_fld = EGRESS_PORTf;
   1396 
   1397     if (!soc_mem_field_valid(unit, RH_HGT_FLOWSETm, port_fld)) {
   1398         port_fld = PORT_NUMf;
   1399     }
   1400     if (add_info == NULL ||
   1401         add_info->psc != BCM_TRUNK_PSC_DYNAMIC_RESILIENT ||
   1402         add_info->num_ports == 0) {
   1403         return BCM_E_PARAM;
   1404     }
   1405 
   1406     if (new_member == NULL) {
   1407         return BCM_E_PARAM;
   1408     }
   1409 
   1410     if (add_info->num_ports == 1) {
   1411         /* Adding the first member is the same as setting one member */
   1412        return bcm_td2_hg_rh_set(unit, hgtid, add_info);
   1413     }
   1414 
   1415     BCM_IF_ERROR_RETURN(_bcm_esw_trunk_gport_array_resolve(unit, TRUE, 1,
   1416                 &new_member->gport, &new_port, &new_mod));
   1417 
   1418     /* Swap new member to the last one for BCM_TRUNK_FLAG_MEMBER_SORT */
   1419     if (add_info->flags & BCM_TRUNK_FLAG_MEMBER_SORT) {
   1420         for (i = 0; i < add_info->num_ports; i++){
   1421             if (i == (add_info->num_ports - 1)) {
   1422                 break;
   1423             }
   1424             if (new_port == add_info->tp[i]) {
   1425                 tmp_port = add_info->tp[i];
   1426                 add_info->tp[i] = add_info->tp[add_info->num_ports - 1];
   1427                 add_info->tp[add_info->num_ports - 1] = tmp_port;
   1428                 tmp_index = i;
   1429                 break;
   1430             }
   1431         }
   1432     }
   1433 
   1434     /* Check that the new member is the last member of the array */
   1435     if (new_port != add_info->tp[add_info->num_ports - 1]) {
   1436         return BCM_E_PARAM;
   1437     }
   1438     num_existing_members = add_info->num_ports - 1;
   1439 
   1440     /* Get member index for each existing member port */
   1441     member_index_arr = sal_alloc(sizeof(int) * SOC_MAX_NUM_PORTS,
   1442             "member index array");
   1443     if (NULL == member_index_arr) {
   1444         rv = BCM_E_MEMORY;
   1445         goto cleanup;
   1446     }
   1447     for (i = 0; i < SOC_MAX_NUM_PORTS; i++) {
   1448         member_index_arr[i] = -1;
   1449     }
   1450     for (i = 0; i < num_existing_members; i++) {
   1451         member_index_arr[add_info->tp[i]] = i;
   1452     }
   1453 
   1454     /* Read all the flow set entries of this Higig resilient hash group,
   1455      * and compute the number of entries currently assigned to each
   1456      * existing member.
   1457      */
   1458     if (soc_feature(unit, soc_feature_td3_style_dlb_rh)) {
   1459         rv = READ_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, hgtid,
   1460                       &hg_trunk_group_entry);
   1461         if (SOC_FAILURE(rv)) {
   1462             goto cleanup;
   1463         }
   1464         entry_base_ptr = soc_HG_TRUNK_GROUPm_field32_get(unit,
   1465                         &hg_trunk_group_entry, RH_FLOW_SET_BASEf);
   1466         flow_set_size = soc_HG_TRUNK_GROUPm_field32_get(unit,
   1467                         &hg_trunk_group_entry, RH_FLOW_SET_SIZEf);
   1468 
   1469     } else {
   1470         rv = READ_RH_HGT_GROUP_CONTROLm(unit, MEM_BLOCK_ANY, hgtid,
   1471                            &rh_hgt_group_control_entry);
   1472         if (SOC_FAILURE(rv)) {
   1473             goto cleanup;
   1474         }
   1475         entry_base_ptr = soc_RH_HGT_GROUP_CONTROLm_field32_get(unit,
   1476                         &rh_hgt_group_control_entry, FLOW_SET_BASEf);
   1477         flow_set_size = soc_RH_HGT_GROUP_CONTROLm_field32_get(unit,
   1478             &rh_hgt_group_control_entry, FLOW_SET_SIZEf);
   1479     }
   1480     rv = _bcm_td2_hg_rh_dynamic_size_decode(unit, flow_set_size, &num_entries);
   1481     if (BCM_FAILURE(rv)) {
   1482         goto cleanup;
   1483     }
   1484 
   1485     alloc_size = num_entries * sizeof(rh_hgt_flowset_entry_t);
   1486     buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_HGT_FLOWSET entries");
   1487     if (NULL == buf_ptr) {
   1488         rv = BCM_E_MEMORY;
   1489         goto cleanup;
   1490     }
   1491     sal_memset(buf_ptr, 0, alloc_size);
   1492     index_min = entry_base_ptr;
   1493     index_max = index_min + num_entries - 1;
   1494     rv = soc_mem_read_range(unit, RH_HGT_FLOWSETm, MEM_BLOCK_ANY,
   1495             index_min, index_max, buf_ptr);
   1496     if (SOC_FAILURE(rv)) {
   1497         goto cleanup;
   1498     }
   1499 
   1500     alloc_size = add_info->num_ports * sizeof(int);
   1501     entry_count_arr = sal_alloc(alloc_size, "RH entry count array");
   1502     if (NULL == entry_count_arr) {
   1503         rv = BCM_E_MEMORY;
   1504         goto cleanup;
   1505     }
   1506     sal_memset(entry_count_arr, 0, alloc_size);
   1507 
   1508     for (i = 0; i < num_entries; i++) {
   1509         flowset_entry = soc_mem_table_idx_to_pointer(unit,
   1510                 RH_HGT_FLOWSETm, rh_hgt_flowset_entry_t *, buf_ptr, i);
   1511         if (!soc_mem_field32_get(unit, RH_HGT_FLOWSETm, flowset_entry,
   1512                     VALIDf)) {
   1513             rv = BCM_E_INTERNAL;
   1514             goto cleanup;
   1515         }
   1516         egress_port = soc_mem_field32_get(unit, RH_HGT_FLOWSETm, flowset_entry,
   1517                 port_fld);
   1518         member_index = member_index_arr[egress_port];
   1519         if (member_index == -1) {
   1520             rv = BCM_E_INTERNAL;
   1521             goto cleanup;
   1522         }
   1523         entry_count_arr[member_index]++;
   1524     }
   1525 
   1526     /* Check that the distribution of flow set entries among existing members
   1527      * is balanced. For instance, if the number of flow set entries is 64, and
   1528      * the number of existing members is 6, then every member should have
   1529      * between 10 and 11 entries.
   1530      */
   1531     lower_bound = num_entries / num_existing_members;
   1532     upper_bound = (num_entries % num_existing_members) ?
   1533                   (lower_bound + 1) : lower_bound;
   1534     for (i = 0; i < num_existing_members; i++) {
   1535         if (entry_count_arr[i] < lower_bound ||
   1536                 entry_count_arr[i] > upper_bound) {
   1537             rv = BCM_E_INTERNAL;
   1538             goto cleanup;
   1539         }
   1540     }
   1541 
   1542     rv = _bcm_td2_hg_rh_add_rebalance(unit, num_entries, buf_ptr,
   1543                               add_info->num_ports, entry_count_arr,
   1544                               new_port, member_index_arr);
   1545     if (SOC_FAILURE(rv)) {
   1546         goto cleanup;
   1547     }
   1548 
   1549     /* Write re-balanced flow set entries to hardware */
   1550     rv = soc_mem_write_range(unit, RH_HGT_FLOWSETm, MEM_BLOCK_ALL,
   1551             index_min, index_max, buf_ptr);
   1552 
   1553 cleanup:
   1554     if (member_index_arr) {
   1555         sal_free(member_index_arr);
   1556     }
   1557     if (buf_ptr) {
   1558         soc_cm_sfree(unit, buf_ptr);
   1559     }
   1560     if (entry_count_arr) {
   1561         sal_free(entry_count_arr);
   1562     }
   1563 
   1564     /* Restore the order of trunk members */ 
   1565     if (tmp_index != -1) {
   1566         tmp_port = add_info->tp[tmp_index];
   1567         add_info->tp[tmp_index] = add_info->tp[add_info->num_ports - 1];
   1568         add_info->tp[add_info->num_ports - 1] = tmp_port;
   1569     }
   1570 
   1571     return rv;
   1572 }
   1573 
   1574 /*
   1575  * Function:
   1576  *      bcm_td2_hg_rh_delete
   1577  * Purpose:
   1578  *      Delete a member from a Higig resilient hashing group.
   1579  * Parameters:
   1580  *      unit  - (IN) SOC unit number. 
   1581  *      hgtid - (IN) Higig trunk group ID.
   1582  *      add_info - (IN) Pointer to trunk add info structure, which contains
   1583  *                      all resilient hashing eligible members of the group,
   1584  *                      except the member to be deleted.
   1585  *      leaving_member - (IN) Member to delete.
   1586  * Returns:
   1587  *      BCM_E_xxx
   1588  */
   1589 int
   1590 bcm_td2_hg_rh_delete(int unit,
   1591         int hgtid,
   1592         _esw_trunk_add_info_t *add_info,
   1593         bcm_trunk_member_t *leaving_member)
   1594 {
   1595     int rv = BCM_E_NONE;
   1596     bcm_port_t leaving_port;
   1597     bcm_module_t leaving_mod;
   1598     int num_remaining_members;
   1599     int *member_index_arr = NULL;
   1600     int i;
   1601     rh_hgt_group_control_entry_t rh_hgt_group_control_entry;
   1602     int entry_base_ptr;
   1603     int flow_set_size;
   1604     int num_entries;
   1605     int alloc_size;
   1606     uint32 *buf_ptr = NULL;
   1607     int index_min, index_max;
   1608     int leaving_member_entry_count;
   1609     int *entry_count_arr = NULL;
   1610     rh_hgt_flowset_entry_t *flowset_entry;
   1611     int egress_port;
   1612     int member_index;
   1613     int lower_bound, upper_bound;
   1614     soc_field_t port_fld = EGRESS_PORTf;
   1615     hg_trunk_group_entry_t hg_trunk_group_entry;
   1616 
   1617     if (!soc_mem_field_valid(unit, RH_HGT_FLOWSETm, port_fld)) {
   1618         port_fld = PORT_NUMf;
   1619     }
   1620 
   1621     if (add_info == NULL || add_info->psc != BCM_TRUNK_PSC_DYNAMIC_RESILIENT) {
   1622         return BCM_E_PARAM;
   1623     }
   1624 
   1625     if (leaving_member == NULL) {
   1626         return BCM_E_PARAM;
   1627     }
   1628 
   1629     if (add_info->num_ports == 0) {
   1630         /* Deleting the last member is the same as freeing all resources */
   1631         BCM_IF_ERROR_RETURN(bcm_td2_hg_rh_free_resource(unit, hgtid));
   1632 
   1633         /* Write the dynamic_size to hardware, so it can be recovered
   1634          * during warm boot.
   1635          */
   1636         BCM_IF_ERROR_RETURN(bcm_td2_hg_rh_dynamic_size_set(unit, hgtid,
   1637                     add_info->dynamic_size));
   1638 
   1639         return BCM_E_NONE;
   1640     }
   1641 
   1642     /* Check that the leaving member is not a member of the array */
   1643     BCM_IF_ERROR_RETURN(_bcm_esw_trunk_gport_array_resolve(unit, TRUE, 1,
   1644                 &leaving_member->gport, &leaving_port, &leaving_mod));
   1645     for (i = 0; i < add_info->num_ports; i++) {
   1646         if (leaving_port == add_info->tp[i]) {
   1647             return BCM_E_PARAM;
   1648         }
   1649     }
   1650     num_remaining_members = add_info->num_ports;
   1651 
   1652     /* Get member index for each remaining member port */
   1653     member_index_arr = sal_alloc(sizeof(int) * SOC_MAX_NUM_PORTS,
   1654             "member index array");
   1655     if (NULL == member_index_arr) {
   1656         rv = BCM_E_MEMORY;
   1657         goto cleanup;
   1658     }
   1659     for (i = 0; i < SOC_MAX_NUM_PORTS; i++) {
   1660         member_index_arr[i] = -1;
   1661     }
   1662     for (i = 0; i < num_remaining_members; i++) {
   1663         member_index_arr[add_info->tp[i]] = i;
   1664     }
   1665 
   1666     /* Read all the flow set entries of this Higig resilient hash group,
   1667      * and compute the number of entries currently assigned to each
   1668      * member, including the leaving member.
   1669      */
   1670     if (soc_feature(unit, soc_feature_td3_style_dlb_rh)) {
   1671         rv = READ_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, hgtid,
   1672                       &hg_trunk_group_entry);
   1673         if (SOC_FAILURE(rv)) {
   1674             goto cleanup;
   1675         }
   1676         entry_base_ptr = soc_HG_TRUNK_GROUPm_field32_get(unit,
   1677                         &hg_trunk_group_entry, RH_FLOW_SET_BASEf);
   1678         flow_set_size = soc_HG_TRUNK_GROUPm_field32_get(unit,
   1679                         &hg_trunk_group_entry, RH_FLOW_SET_SIZEf);
   1680 
   1681     } else {
   1682         rv = READ_RH_HGT_GROUP_CONTROLm(unit, MEM_BLOCK_ANY, hgtid,
   1683             &rh_hgt_group_control_entry);
   1684         if (SOC_FAILURE(rv)) {
   1685             goto cleanup;
   1686         }
   1687         entry_base_ptr = soc_RH_HGT_GROUP_CONTROLm_field32_get(unit,
   1688                &rh_hgt_group_control_entry, FLOW_SET_BASEf);
   1689         flow_set_size = soc_RH_HGT_GROUP_CONTROLm_field32_get(unit,
   1690                  &rh_hgt_group_control_entry, FLOW_SET_SIZEf);
   1691     }
   1692     rv = _bcm_td2_hg_rh_dynamic_size_decode(unit, flow_set_size, &num_entries);
   1693     if (BCM_FAILURE(rv)) {
   1694         goto cleanup;
   1695     }
   1696 
   1697     alloc_size = num_entries * sizeof(rh_hgt_flowset_entry_t);
   1698     buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_HGT_FLOWSET entries");
   1699     if (NULL == buf_ptr) {
   1700         rv = BCM_E_MEMORY;
   1701         goto cleanup;
   1702     }
   1703     sal_memset(buf_ptr, 0, alloc_size);
   1704     index_min = entry_base_ptr;
   1705     index_max = index_min + num_entries - 1;
   1706     rv = soc_mem_read_range(unit, RH_HGT_FLOWSETm, MEM_BLOCK_ANY,
   1707             index_min, index_max, buf_ptr);
   1708     if (SOC_FAILURE(rv)) {
   1709         goto cleanup;
   1710     }
   1711 
   1712     alloc_size = num_remaining_members * sizeof(int);
   1713     entry_count_arr = sal_alloc(alloc_size, "RH entry count array");
   1714     if (NULL == entry_count_arr) {
   1715         rv = BCM_E_MEMORY;
   1716         goto cleanup;
   1717     }
   1718     sal_memset(entry_count_arr, 0, alloc_size);
   1719 
   1720     leaving_member_entry_count = 0;
   1721     for (i = 0; i < num_entries; i++) {
   1722         flowset_entry = soc_mem_table_idx_to_pointer(unit,
   1723                 RH_HGT_FLOWSETm, rh_hgt_flowset_entry_t *, buf_ptr, i);
   1724         if (!soc_mem_field32_get(unit, RH_HGT_FLOWSETm, flowset_entry,
   1725                     VALIDf)) {
   1726             rv = BCM_E_INTERNAL;
   1727             goto cleanup;
   1728         }
   1729         egress_port = soc_mem_field32_get(unit, RH_HGT_FLOWSETm, flowset_entry,
   1730                 port_fld);
   1731         if (egress_port == leaving_port) {
   1732             leaving_member_entry_count++;
   1733         } else {
   1734             member_index = member_index_arr[egress_port];
   1735             if (member_index == -1) {
   1736                 rv = BCM_E_INTERNAL;
   1737                 goto cleanup;
   1738             }
   1739             entry_count_arr[member_index]++;
   1740         }
   1741     }
   1742 
   1743     /* Check that the distribution of flow set entries among all members
   1744      * is balanced. For instance, if the number of flow set entries is 64, and
   1745      * the number of members is 6, then every member should have
   1746      * between 10 and 11 entries. 
   1747      */ 
   1748     lower_bound = num_entries / (num_remaining_members + 1);
   1749     upper_bound = (num_entries % (num_remaining_members + 1)) ?
   1750                   (lower_bound + 1) : lower_bound;
   1751     for (i = 0; i < num_remaining_members; i++) {
   1752         if (entry_count_arr[i] < lower_bound ||
   1753                 entry_count_arr[i] > upper_bound) {
   1754             rv = BCM_E_INTERNAL;
   1755             goto cleanup;
   1756         }
   1757     }
   1758     if (leaving_member_entry_count < lower_bound ||
   1759             leaving_member_entry_count > upper_bound) {
   1760         rv = BCM_E_INTERNAL;
   1761         goto cleanup;
   1762     }
   1763 
   1764     rv = _bcm_td2_hg_rh_delete_rebalance(unit, num_entries, buf_ptr,
   1765                  num_remaining_members, entry_count_arr, add_info->tp,
   1766                          1, &leaving_port);
   1767     if (SOC_FAILURE(rv)) {
   1768         goto cleanup;
   1769     }
   1770 
   1771     /* Write re-balanced flow set entries to hardware */
   1772     rv = soc_mem_write_range(unit, RH_HGT_FLOWSETm, MEM_BLOCK_ALL,
   1773             index_min, index_max, buf_ptr);
   1774 cleanup:
   1775     if (member_index_arr) {
   1776         sal_free(member_index_arr);
   1777     }
   1778     if (buf_ptr) {
   1779         soc_cm_sfree(unit, buf_ptr);
   1780     }
   1781     if (entry_count_arr) {
   1782         sal_free(entry_count_arr);
   1783     }
   1784 
   1785     return rv;
   1786 }
   1787 
   1788 /*
   1789  * Function:
   1790  *      bcm_td2_hg_rh_ethertype_set
   1791  * Purpose:
   1792  *      Set the Ethertypes that are eligible or ineligible for
   1793  *      Higig resilient hashing.
   1794  * Parameters:
   1795  *      unit - (IN) Unit number.
   1796  *      flags - (IN) BCM_TRUNK_DYNAMIC_ETHERTYPE_xxx flags.
   1797  *      ethertype_count - (IN) Number of elements in ethertype_array.
   1798  *      ethertype_array - (IN) Array of Ethertypes.
   1799  * Returns:
   1800  *      BCM_E_XXX
   1801  */
   1802 int 
   1803 bcm_td2_hg_rh_ethertype_set(
   1804     int unit, 
   1805     uint32 flags, 
   1806     int ethertype_count, 
   1807     int *ethertype_array)
   1808 {
   1809     uint32 control_reg;
   1810     int i, j;
   1811     rh_hgt_ethertype_eligibility_map_entry_t ethertype_entry;
   1812 
   1813     /* Input check */
   1814     if (ethertype_count > soc_mem_index_count(unit,
   1815                 RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm)) {
   1816         return BCM_E_RESOURCE;
   1817     }
   1818 
   1819     /* Update ethertype eligibility control register */
   1820     SOC_IF_ERROR_RETURN
   1821         (READ_RH_HGT_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, &control_reg));
   1822     soc_reg_field_set(unit, RH_HGT_ETHERTYPE_ELIGIBILITY_CONTROLr,
   1823             &control_reg, ETHERTYPE_ELIGIBILITY_CONFIGf,
   1824             flags & BCM_TRUNK_DYNAMIC_ETHERTYPE_ELIGIBLE ? 1 : 0);
   1825     soc_reg_field_set(unit, RH_HGT_ETHERTYPE_ELIGIBILITY_CONTROLr,
   1826             &control_reg, INNER_OUTER_ETHERTYPE_SELECTIONf,
   1827             flags & BCM_TRUNK_DYNAMIC_ETHERTYPE_INNER ? 1 : 0);
   1828     SOC_IF_ERROR_RETURN
   1829         (WRITE_RH_HGT_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, control_reg));
   1830 
   1831     /* Update Ethertype eligibility map table */
   1832     for (i = 0; i < ethertype_count; i++) {
   1833         sal_memset(&ethertype_entry, 0,
   1834                 sizeof(rh_hgt_ethertype_eligibility_map_entry_t));
   1835         soc_RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm_field32_set(unit,
   1836                 &ethertype_entry, VALIDf, 1);
   1837         soc_RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm_field32_set(unit,
   1838                 &ethertype_entry, ETHERTYPEf, ethertype_array[i]);
   1839         SOC_IF_ERROR_RETURN(WRITE_RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm(unit,
   1840                     MEM_BLOCK_ALL, i, &ethertype_entry));
   1841     }
   1842 
   1843     /* Zero out remaining entries of Ethertype eligibility map table */
   1844     for (j = i; j < soc_mem_index_count(unit,
   1845                 RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm); j++) {
   1846         SOC_IF_ERROR_RETURN(WRITE_RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm(unit,
   1847                     MEM_BLOCK_ALL, j, soc_mem_entry_null(unit,
   1848                         RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm)));
   1849     }
   1850 
   1851     return BCM_E_NONE;
   1852 }
   1853 
   1854 /*
   1855  * Function:
   1856  *      bcm_td2_hg_rh_ethertype_get
   1857  * Purpose:
   1858  *      Get the Ethertypes that are eligible or ineligible for
   1859  *      Higig resilient hashing.
   1860  * Parameters:
   1861  *      unit - (IN) Unit number.
   1862  *      flags - (INOUT) BCM_TRUNK_DYNAMIC_ETHERTYPE_xxx flags.
   1863  *      ethertype_max - (IN) Number of elements in ethertype_array.
   1864  *      ethertype_array - (OUT) Array of Ethertypes.
   1865  *      ethertype_count - (OUT) Number of elements returned in ethertype_array.
   1866  * Returns:
   1867  *      BCM_E_XXX
   1868  */
   1869 int 
   1870 bcm_td2_hg_rh_ethertype_get(
   1871     int unit, 
   1872     uint32 *flags, 
   1873     int ethertype_max, 
   1874     int *ethertype_array, 
   1875     int *ethertype_count)
   1876 {
   1877     uint32 control_reg;
   1878     int i;
   1879     int ethertype;
   1880     rh_hgt_ethertype_eligibility_map_entry_t ethertype_entry;
   1881 
   1882     *ethertype_count = 0;
   1883 
   1884     /* Get flags */
   1885     SOC_IF_ERROR_RETURN
   1886         (READ_RH_HGT_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, &control_reg));
   1887     if (soc_reg_field_get(unit, RH_HGT_ETHERTYPE_ELIGIBILITY_CONTROLr,
   1888                 control_reg, ETHERTYPE_ELIGIBILITY_CONFIGf)) {
   1889         *flags |= BCM_TRUNK_DYNAMIC_ETHERTYPE_ELIGIBLE;
   1890     }
   1891     if (soc_reg_field_get(unit, RH_HGT_ETHERTYPE_ELIGIBILITY_CONTROLr,
   1892                 control_reg, INNER_OUTER_ETHERTYPE_SELECTIONf)) {
   1893         *flags |= BCM_TRUNK_DYNAMIC_ETHERTYPE_INNER;
   1894     }
   1895 
   1896     /* Get Ethertypes */
   1897     for (i = 0; i < soc_mem_index_count(unit,
   1898                 RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm); i++) {
   1899         SOC_IF_ERROR_RETURN(READ_RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm(unit,
   1900                     MEM_BLOCK_ANY, i, &ethertype_entry));
   1901         if (soc_RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm_field32_get(unit,
   1902                     &ethertype_entry, VALIDf)) {
   1903             ethertype = soc_RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm_field32_get(unit,
   1904                     &ethertype_entry, ETHERTYPEf);
   1905             if (NULL != ethertype_array) {
   1906                 ethertype_array[*ethertype_count] = ethertype;
   1907             }
   1908             (*ethertype_count)++;
   1909             if ((ethertype_max > 0) && (*ethertype_count == ethertype_max)) {
   1910                 break;
   1911             }
   1912         }
   1913     }
   1914 
   1915     return BCM_E_NONE;
   1916 }
   1917 
   1918 /*
   1919  * Function:
   1920  *      bcm_td2_lag_rh_deinit
   1921  * Purpose:
   1922  *      Deallocate LAG resilient hashing internal data structures
   1923  * Parameters:
   1924  *      unit - (IN) SOC unit number.
   1925  * Returns:
   1926  *      BCM_E_xxx
   1927  */
   1928 void
   1929 bcm_td2_lag_rh_deinit(int unit)
   1930 {
   1931     if (_td2_lag_rh_info[unit]) {
   1932         if (_td2_lag_rh_info[unit]->lag_rh_flowset_block_bitmap) {
   1933             sal_free(_td2_lag_rh_info[unit]->lag_rh_flowset_block_bitmap);
   1934             _td2_lag_rh_info[unit]->lag_rh_flowset_block_bitmap = NULL;
   1935         }
   1936         sal_free(_td2_lag_rh_info[unit]);
   1937         _td2_lag_rh_info[unit] = NULL;
   1938     }
   1939 }
   1940 
   1941 /*
   1942  * Function:
   1943  *      bcm_td2_lag_rh_init
   1944  * Purpose:
   1945  *      Initialize LAG resilient hashing internal data structures
   1946  * Parameters:
   1947  *      unit - (IN) SOC unit number.
   1948  * Returns:
   1949  *      BCM_E_xxx
   1950  */
   1951 int
   1952 bcm_td2_lag_rh_init(int unit)
   1953 {
   1954     int num_lag_rh_flowset_entries;
   1955 
   1956     if (_td2_lag_rh_info[unit] == NULL) {
   1957         _td2_lag_rh_info[unit] = sal_alloc(sizeof(_td2_lag_rh_info_t),
   1958                 "_td2_lag_rh_info");
   1959         if (_td2_lag_rh_info[unit] == NULL) {
   1960             return BCM_E_MEMORY;
   1961         }
   1962         sal_memset(_td2_lag_rh_info[unit], 0, sizeof(_td2_lag_rh_info_t));
   1963     }
   1964 
   1965     /* The LAG and ECMP resilient hash features share the same flow set table.
   1966      * The table can be configured in one of 3 modes:
   1967      * - dedicated to LAG resilient hashing,
   1968      * - dedicated to ECMP resilient hashing,
   1969      * - split evenly between LAG and ECMP resilient hashing.
   1970      * The mode was configured during Trident2 initialization.
   1971      */
   1972     num_lag_rh_flowset_entries = soc_mem_index_count(unit, RH_LAG_FLOWSETm);
   1973 
   1974     /* Each bit in lag_rh_flowset_block_bitmap corresponds to a block of 64
   1975      * resilient hashing flow set table entries.
   1976      */
   1977     _td2_lag_rh_info[unit]->num_lag_rh_flowset_blocks =
   1978         num_lag_rh_flowset_entries / 64;
   1979     if (_td2_lag_rh_info[unit]->num_lag_rh_flowset_blocks > 0) {
   1980         if (_td2_lag_rh_info[unit]->lag_rh_flowset_block_bitmap == NULL) {
   1981             _td2_lag_rh_info[unit]->lag_rh_flowset_block_bitmap = 
   1982                 sal_alloc(SHR_BITALLOCSIZE(_td2_lag_rh_info[unit]->
   1983                             num_lag_rh_flowset_blocks),
   1984                         "lag_rh_flowset_block_bitmap");
   1985             if (_td2_lag_rh_info[unit]->lag_rh_flowset_block_bitmap == NULL) {
   1986                 bcm_td2_lag_rh_deinit(unit);
   1987                 return BCM_E_MEMORY;
   1988             }
   1989             sal_memset(_td2_lag_rh_info[unit]->lag_rh_flowset_block_bitmap, 0,
   1990                     SHR_BITALLOCSIZE(_td2_lag_rh_info[unit]->
   1991                         num_lag_rh_flowset_blocks));
   1992         }
   1993     }
   1994 
   1995     /* Set the seed for the pseudo-random number generator */
   1996     _td2_lag_rh_info[unit]->lag_rh_rand_seed = sal_time_usecs();
   1997 
   1998     return BCM_E_NONE;
   1999 }
   2000 
   2001 /*
   2002  * Function:
   2003  *      bcm_td2_lag_rh_dynamic_size_encode
   2004  * Purpose:
   2005  *      Encode LAG trunk resilient hashing flow set size.
   2006  * Parameters:
   2007  *      dynamic_size - (IN) Number of flow sets.
   2008  *      encoded_value - (OUT) Encoded value.
   2009  * Returns:
   2010  *      BCM_E_xxx
   2011  */
   2012 int
   2013 bcm_td2_lag_rh_dynamic_size_encode(int unit, int dynamic_size,
   2014                                    int *encoded_value)
   2015 {
   2016 #ifdef BCM_HELIX5_SUPPORT
   2017     if (SOC_IS_HELIX5(unit)) {
   2018         return _bcm_hx5_lag_rh_dynamic_size_encode(dynamic_size, encoded_value);
   2019     }
   2020 #endif /* BCM_HELIX5_SUPPORT */
   2021     switch (dynamic_size) {
   2022         case 64:
   2023             *encoded_value = 1;
   2024             break;
   2025         case 128:
   2026             *encoded_value = 2;
   2027             break;
   2028         case 256:
   2029             *encoded_value = 3;
   2030             break;
   2031         case 512:
   2032             *encoded_value = 4;
   2033             break;
   2034         case 1024:
   2035             *encoded_value = 5;
   2036             break;
   2037         case 2048:
   2038             *encoded_value = 6;
   2039             break;
   2040         case 4096:
   2041             *encoded_value = 7;
   2042             break;
   2043         case 8192:
   2044             *encoded_value = 8;
   2045             break;
   2046         case 16384:
   2047             *encoded_value = 9;
   2048             break;
   2049         case 32768:
   2050             *encoded_value = 10;
   2051             break;
   2052         case 65536:
   2053             *encoded_value = 11;
   2054             break;
   2055         default:
   2056             return BCM_E_PARAM;
   2057     }
   2058 
   2059     return BCM_E_NONE;
   2060 }
   2061 
   2062 /*
   2063  * Function:
   2064  *      _bcm_td2_lag_rh_dynamic_size_decode
   2065  * Purpose:
   2066  *      Decode LAG trunk resilient hashing flow set size.
   2067  * Parameters:
   2068  *      encoded_value - (IN) Encoded value.
   2069  *      dynamic_size - (OUT) Number of flow sets.
   2070  * Returns:
   2071  *      BCM_E_xxx
   2072  */
   2073 STATIC int
   2074 _bcm_td2_lag_rh_dynamic_size_decode(int unit, int encoded_value,
   2075                                     int *dynamic_size)
   2076 {   
   2077 #ifdef BCM_HELIX5_SUPPORT
   2078     if (SOC_IS_HELIX5(unit)) {
   2079         return _bcm_hx5_lag_rh_dynamic_size_decode(encoded_value, dynamic_size);
   2080     }
   2081 #endif /* BCM_HELIX5_SUPPORT */
   2082     switch (encoded_value) {
   2083         case 1:
   2084             *dynamic_size = 64;
   2085             break;
   2086         case 2:
   2087             *dynamic_size = 128;
   2088             break;
   2089         case 3:
   2090             *dynamic_size = 256;
   2091             break;
   2092         case 4:
   2093             *dynamic_size = 512;
   2094             break;
   2095         case 5:
   2096             *dynamic_size = 1024;
   2097             break;
   2098         case 6:
   2099             *dynamic_size = 2048;
   2100             break;
   2101         case 7:
   2102             *dynamic_size = 4096;
   2103             break;
   2104         case 8:
   2105             *dynamic_size = 8192;
   2106             break;
   2107         case 9:
   2108             *dynamic_size = 16384;
   2109             break;
   2110         case 10:
   2111             *dynamic_size = 32768;
   2112             break;
   2113         case 11:
   2114             *dynamic_size = 65536;
   2115             break;
   2116         default:
   2117             return BCM_E_INTERNAL;
   2118     }
   2119 
   2120     return BCM_E_NONE;
   2121 }
   2122 
   2123 /*
   2124  * Function:
   2125  *      bcm_td2_lag_rh_free_resource
   2126  * Purpose:
   2127  *      Free resources for a LAG resilient hashing.
   2128  * Parameters:
   2129  *      unit  - (IN) SOC unit number. 
   2130  *      tid - (IN) LAG group ID.
   2131  * Returns:
   2132  *      BCM_E_xxx
   2133  */
   2134 int
   2135 bcm_td2_lag_rh_free_resource(int unit, int tid)
   2136 {
   2137     int rv = BCM_E_NONE;
   2138     trunk_group_entry_t trunk_group_entry;
   2139     int entry_base_ptr;
   2140     int flow_set_size;
   2141     int num_entries;
   2142     int alloc_size;
   2143     uint32 *buf_ptr = NULL;
   2144     int index_min, index_max;
   2145     int block_base_ptr;
   2146     int num_blocks, rh_enable = 0;
   2147     soc_field_t lbmode_fld = ENHANCED_HASHING_ENABLEf;
   2148     uint32 rval;
   2149 
   2150     if (soc_reg_field_valid(unit, ENHANCED_HASHING_CONTROL_2r, RH_DLB_SELECTIONf)) {
   2151         SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROL_2r(unit, &rval));
   2152         if (0 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROL_2r, rval,
   2153                 RH_DLB_SELECTIONf)) {
   2154            /* LAG resilient hashing is not enabled chip-wide. */
   2155             return BCM_E_NONE;
   2156         }
   2157     }
   2158 
   2159     if (!soc_mem_field_valid(unit, TRUNK_GROUPm, lbmode_fld)) {
   2160         lbmode_fld = TRUNK_MODEf;
   2161     }
   2162 
   2163     SOC_IF_ERROR_RETURN(READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY,
   2164                 tid, &trunk_group_entry));
   2165 
   2166     if (lbmode_fld == ENHANCED_HASHING_ENABLEf) {
   2167         rh_enable =  soc_TRUNK_GROUPm_field32_get(unit, &trunk_group_entry,
   2168                    lbmode_fld);
   2169     } else {
   2170         rh_enable = (soc_TRUNK_GROUPm_field32_get(unit,
   2171                           &trunk_group_entry, lbmode_fld) == 3) ? 1 :0;
   2172     }
   2173 
   2174     if (rh_enable == 0) {
   2175         /* Either (1) resilient hashing is not enabled on this trunk
   2176          * group, or (2) resilient hahsing is enabled with no members.
   2177          * In case (2), TRUNK_GROUP.FLOW_SET_SIZE needs to be cleared. 
   2178          */
   2179         soc_TRUNK_GROUPm_field32_set(unit, &trunk_group_entry,
   2180                 RH_FLOW_SET_SIZEf, 0);
   2181         SOC_IF_ERROR_RETURN(WRITE_TRUNK_GROUPm(unit, MEM_BLOCK_ALL, tid,
   2182                     &trunk_group_entry));
   2183         return BCM_E_NONE;
   2184     }
   2185     flow_set_size = soc_TRUNK_GROUPm_field32_get(unit,
   2186             &trunk_group_entry, RH_FLOW_SET_SIZEf);
   2187     entry_base_ptr = soc_TRUNK_GROUPm_field32_get(unit,
   2188             &trunk_group_entry, RH_FLOW_SET_BASEf);
   2189 
   2190     /* Clear resilient hashing fields in TRUNK_GROUP */
   2191     soc_TRUNK_GROUPm_field32_set(unit, &trunk_group_entry,
   2192                  lbmode_fld, 0);
   2193     soc_TRUNK_GROUPm_field32_set(unit, &trunk_group_entry,
   2194             RH_FLOW_SET_BASEf, 0);
   2195     soc_TRUNK_GROUPm_field32_set(unit, &trunk_group_entry,
   2196             RH_FLOW_SET_SIZEf, 0);
   2197     SOC_IF_ERROR_RETURN(WRITE_TRUNK_GROUPm(unit, MEM_BLOCK_ALL, tid,
   2198                 &trunk_group_entry));
   2199 
   2200     /* Clear flow set table entries */
   2201     BCM_IF_ERROR_RETURN
   2202         (_bcm_td2_lag_rh_dynamic_size_decode(unit, flow_set_size,
   2203                                              &num_entries));
   2204     alloc_size = num_entries * sizeof(rh_lag_flowset_entry_t);
   2205     buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_LAG_FLOWSET entries");
   2206     if (NULL == buf_ptr) {
   2207         return BCM_E_MEMORY;
   2208     }
   2209     sal_memset(buf_ptr, 0, alloc_size);
   2210     index_min = entry_base_ptr;
   2211     index_max = index_min + num_entries - 1;
   2212     rv = soc_mem_write_range(unit, RH_LAG_FLOWSETm, MEM_BLOCK_ALL,
   2213             index_min, index_max, buf_ptr);
   2214     if (SOC_FAILURE(rv)) {
   2215         soc_cm_sfree(unit, buf_ptr);
   2216         return rv;
   2217     }
   2218     soc_cm_sfree(unit, buf_ptr);
   2219 
   2220     /* Free flow set table resources */
   2221     block_base_ptr = entry_base_ptr >> 6;
   2222     num_blocks = num_entries >> 6; 
   2223     _BCM_LAG_RH_FLOWSET_BLOCK_USED_CLR_RANGE(unit, block_base_ptr, num_blocks);
   2224 
   2225     return BCM_E_NONE;
   2226 }
   2227 
   2228 /*
   2229  * Function:
   2230  *      bcm_td2_lag_rh_dynamic_size_set
   2231  * Purpose:
   2232  *      Set the dynamic size for a LAG resilient hashing group with
   2233  *      no members, so it can be recovered from hardware during warm boot.
   2234  * Parameters:
   2235  *      unit  - (IN) SOC unit number. 
   2236  *      tid - (IN) Trunk group ID.
   2237  *      dynamic_size - (IN) Number of flow sets.
   2238  * Returns:
   2239  *      BCM_E_xxx
   2240  */
   2241 int
   2242 bcm_td2_lag_rh_dynamic_size_set(int unit, int tid, int dynamic_size)
   2243 {
   2244     trunk_group_entry_t trunk_group_entry;
   2245     int flow_set_size, lb_enabled =1;
   2246     soc_field_t lb_fld = ENHANCED_HASHING_ENABLEf;
   2247 
   2248     if (!soc_mem_field_valid(unit, TRUNK_GROUPm, lb_fld)) {
   2249         lb_fld = TRUNK_MODEf;
   2250         lb_enabled = 3;
   2251     }
   2252     SOC_IF_ERROR_RETURN(READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, tid,
   2253                 &trunk_group_entry));
   2254     if (soc_TRUNK_GROUPm_field32_get(unit, &trunk_group_entry,
   2255             lb_fld) == lb_enabled) {
   2256         /* Not expecting resilient hashing to be enabled */
   2257         return BCM_E_INTERNAL;
   2258     }
   2259 
   2260     BCM_IF_ERROR_RETURN
   2261         (bcm_td2_lag_rh_dynamic_size_encode(unit, dynamic_size,
   2262                                             &flow_set_size));
   2263     soc_TRUNK_GROUPm_field32_set(unit, &trunk_group_entry, RH_FLOW_SET_SIZEf,
   2264             flow_set_size);
   2265     SOC_IF_ERROR_RETURN(WRITE_TRUNK_GROUPm(unit, MEM_BLOCK_ALL, tid,
   2266                 &trunk_group_entry));
   2267 
   2268     return BCM_E_NONE;
   2269 }
   2270 
   2271 /*
   2272  * Function:
   2273  *      _bcm_td2_lag_rh_rand_get
   2274  * Purpose:
   2275  *      Get a random number between 0 and the given max value.
   2276  * Parameters:
   2277  *      unit - (IN) SOC unit number. 
   2278  *      rand_max - (IN) Maximum random number.
   2279  *      rand_num - (OUT) Random number.
   2280  * Returns:
   2281  *      BCM_E_xxx
   2282  * Notes:
   2283  *      This procedure uses the pseudo-random number generator algorithm
   2284  *      suggested by the C standard.
   2285  */
   2286 STATIC int
   2287 _bcm_td2_lag_rh_rand_get(int unit, int rand_max, int *rand_num)
   2288 {
   2289     int modulus;
   2290     int rand_seed_shift;
   2291 
   2292     if (rand_max < 0) {
   2293         return BCM_E_PARAM;
   2294     }
   2295 
   2296     if (NULL == rand_num) {
   2297         return BCM_E_PARAM;
   2298     }
   2299 
   2300     /* Make sure the modulus does not exceed limit. For instance,
   2301      * if the 32-bit rand_seed is shifted to the right by 16 bits before
   2302      * the modulo operation, the modulus should not exceed 1 << 16.
   2303      */
   2304     modulus = rand_max + 1;
   2305     rand_seed_shift = 16;
   2306     if (modulus > (1 << (32 - rand_seed_shift))) {
   2307         return BCM_E_PARAM;
   2308     }
   2309 
   2310     _td2_lag_rh_info[unit]->lag_rh_rand_seed =
   2311         _td2_lag_rh_info[unit]->lag_rh_rand_seed * 1103515245 + 12345;
   2312 
   2313     *rand_num = (_td2_lag_rh_info[unit]->lag_rh_rand_seed >> rand_seed_shift) %
   2314                 modulus;
   2315 
   2316     return BCM_E_NONE;
   2317 }
   2318 
   2319 /*
   2320  * Function:
   2321  *      _bcm_td2_lag_rh_member_choose
   2322  * Purpose:
   2323  *      Choose a member of the LAG trunk group.
   2324  * Parameters:
   2325  *      unit - (IN) SOC unit number. 
   2326  *      num_members - (IN) Number of members to choose from.
   2327  *      entry_count_arr   - (IN/OUT) An array keeping track of how many
   2328  *                                   flow set entries have been assigned
   2329  *                                   to each member.
   2330  *      max_entry_count   - (IN/OUT) The maximum number of flow set entries
   2331  *                                   that can be assigned to a member. 
   2332  *      chosen_index      - (OUT) The index of the chosen member.
   2333  * Returns:
   2334  *      BCM_E_xxx
   2335  */
   2336 STATIC int
   2337 _bcm_td2_lag_rh_member_choose(int unit, int num_members, int *entry_count_arr,
   2338         int *max_entry_count, int *chosen_index)
   2339 {
   2340     int member_index;
   2341     int next_index;
   2342 
   2343     *chosen_index = 0;
   2344 
   2345     /* Choose a random member index */
   2346     BCM_IF_ERROR_RETURN(_bcm_td2_lag_rh_rand_get(unit, num_members - 1,
   2347                 &member_index));
   2348 
   2349     if (entry_count_arr[member_index] < *max_entry_count) {
   2350         entry_count_arr[member_index]++;
   2351         *chosen_index = member_index;
   2352     } else {
   2353         /* The randomly chosen member has reached the maximum
   2354          * flow set entry count. Choose the next member that
   2355          * has not reached the maximum entry count.
   2356          */
   2357         next_index = (member_index + 1) % num_members;
   2358         while (next_index != member_index) {
   2359             if (entry_count_arr[next_index] < *max_entry_count) {
   2360                 entry_count_arr[next_index]++;
   2361                 *chosen_index = next_index;
   2362                 break;
   2363             } else {
   2364                 next_index = (next_index + 1) % num_members;
   2365             }
   2366         }
   2367         if (next_index == member_index) {
   2368             /* All members have reached the maximum flow set entry
   2369              * count. This scenario occurs when dividing the number of
   2370              * flow set entries by the number of members results
   2371              * in a non-zero remainder. The remainder flow set entries
   2372              * will be distributed among members, at most 1 remainder
   2373              * entry per member.
   2374              */
   2375             (*max_entry_count)++;
   2376             if (entry_count_arr[member_index] < *max_entry_count) {
   2377                 entry_count_arr[member_index]++;
   2378                 *chosen_index = member_index;
   2379             } else {
   2380                 /* It's possible that the member's entry count already equals
   2381                  * to the incremented value of max_entry_count.
   2382                  */
   2383                 next_index = (member_index + 1) % num_members;
   2384                 while (next_index != member_index) {
   2385                     if (entry_count_arr[next_index] < *max_entry_count) {
   2386                         entry_count_arr[next_index]++;
   2387                         *chosen_index = next_index;
   2388                         break;
   2389                     } else {
   2390                         next_index = (next_index + 1) % num_members;
   2391                     }
   2392                 }
   2393                 if (next_index == member_index) {
   2394                     return BCM_E_INTERNAL;
   2395                 }
   2396             }
   2397         }
   2398     }
   2399 
   2400     return BCM_E_NONE;
   2401 }
   2402 
   2403 
   2404 /*
   2405  * Function:
   2406  *      _bcm_td2_lag_rh_delete_rebalance
   2407  * Purpose:
   2408  *      Re-balance flow set entries from the leaving member to the remaining
   2409  *      members. For example, if the number of flow set entries is 64, and
   2410  *      the number of members is 6, then each member has between 10 and 11
   2411  *      entries. The entries should be re-assigned from the leaving member to
   2412  *      the remaining 5 members such that each remaining member will end up
   2413  *      with between 12 and 13 entries.
   2414  * Parameters:
   2415  *      unit - (IN) SOC unit number.
   2416  *      num_entries - (IN) Number of flow set entries.
   2417  *      buf_ptr     - (IN/OUT) Flow set entry buffer.
   2418  *      num_members - (IN) Number of mod_arr/ port_arr/ entry_count_arr.
   2419  *      entry_count_arr - (IN/OUT) An array keeping track of how many
   2420  *                                 flow set entries have been assigned
   2421  *                                 to each member.
   2422  *      mod_arr    - (IN) Array of module IDs of new members (staying, joining)
   2423  *      port_arr   - (IN) Array of port IDs of new members (staying, joining)
   2424  *      num_leaving   - (IN) Number of leaving_gport.
   2425  *      leaving_gport - (IN) Array of leaving members.
   2426  * Returns:
   2427  *      BCM_E_xxx
   2428  */
   2429 STATIC int
   2430 _bcm_td2_lag_rh_delete_rebalance(int unit, int num_entries, uint32 *buf_ptr,
   2431         int num_members, int *entry_count_arr, int *mod_arr, int *port_arr,
   2432         int num_leaving, bcm_gport_t *leaving_gport)
   2433 {
   2434 
   2435     int threshold;
   2436     int i,j;
   2437     int mod, port;
   2438     bcm_gport_t gport;
   2439     int chosen_index;
   2440     rh_lag_flowset_entry_t *flowset_entry;
   2441 
   2442     threshold = num_entries / num_members;
   2443     for (i = 0; i < num_entries; i++) {
   2444         flowset_entry = soc_mem_table_idx_to_pointer(unit,
   2445                 RH_LAG_FLOWSETm, rh_lag_flowset_entry_t *, buf_ptr, i);
   2446         mod = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry,
   2447                 MODULE_IDf);
   2448         port = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry,
   2449                 PORT_NUMf);
   2450         BCM_GPORT_MODPORT_SET(gport, mod, port);
   2451         for (j = 0; j < num_leaving ; j++ ) {
   2452             if (gport == leaving_gport[j]) {
   2453                 break;
   2454             }
   2455         }
   2456         /* Replace the ones are leaving */
   2457         if (j < num_leaving)  {
   2458             /* Randomly choose a gport among the remaining members */
   2459             BCM_IF_ERROR_RETURN( _bcm_td2_lag_rh_member_choose(
   2460                                 unit, num_members, entry_count_arr,
   2461                                 &threshold, &chosen_index));
   2462             soc_mem_field32_set(unit, RH_LAG_FLOWSETm, flowset_entry, MODULE_IDf,
   2463                     mod_arr[chosen_index]);
   2464             soc_mem_field32_set(unit, RH_LAG_FLOWSETm, flowset_entry, PORT_NUMf,
   2465                     port_arr[chosen_index]);
   2466         }
   2467     }
   2468     return BCM_E_NONE;
   2469 }
   2470 
   2471 /*
   2472  * Function:
   2473  *      _bcm_td2_lag_rh_add_rebalance
   2474  * Purpose:
   2475  *      Re-balance flow set entries from existing members to the new member.
   2476  *      For example, if the number of flow set entries is 64, and the number of
   2477  *      existing members is 6, then each existing member has between 10 and 11
   2478  *      entries. The entries should be re-assigned from the 6 existing members
   2479  *      to the new member such that each member will end up with between 9 and
   2480  *      10 entries.
   2481  * Parameters:
   2482  *      unit - (IN) SOC unit number.
   2483  *      num_entries - (IN) Number of flow set entries.
   2484  *      buf_ptr     - (IN/OUT) Flow set entry buffer.
   2485  *      num_members - (IN) Number of mod_arr/ port_arr/ entry_count_arr.
   2486  *      entry_count_arr - (IN/OUT) An array keeping track of how many
   2487  *                                 flow set entries have been assigned
   2488  *                                 to each member.
   2489  *      mod_arr    - (IN) Array of module IDs of new members (staying, joining)
   2490  *      port_arr   - (IN) Array of port IDs of new members (staying, joining)
   2491  * Returns:
   2492  *      BCM_E_xxx
   2493  */
   2494 
   2495 STATIC int
   2496 _bcm_td2_lag_rh_add_rebalance(int unit, int num_entries, uint32 *buf_ptr,
   2497                               int num_members, int *entry_count_arr,
   2498                               int *mod_arr, int *port_arr)
   2499 {
   2500     int i;
   2501     int new_mod, new_port;
   2502     int mod, port;
   2503     rh_lag_flowset_entry_t *flowset_entry;
   2504     int member_index = 0;
   2505     int lower_bound, upper_bound;
   2506     int threshold;
   2507     int entry_index, next_entry_index;
   2508     int is_new_member;
   2509     int num_existing_members = num_members - 1;
   2510     int new_member_entry_count = 0;
   2511 
   2512     new_mod = mod_arr[num_members - 1];
   2513     new_port = port_arr[num_members - 1];
   2514     lower_bound = num_entries / num_members;
   2515     upper_bound = (num_entries % num_members) ?
   2516                   (lower_bound + 1) : lower_bound;
   2517     threshold = upper_bound;
   2518     while (new_member_entry_count < lower_bound) {
   2519         /* Pick a random entry in the flow set buffer */
   2520         BCM_IF_ERROR_RETURN(_bcm_td2_lag_rh_rand_get(
   2521             unit, num_entries - 1, &entry_index));
   2522         flowset_entry = soc_mem_table_idx_to_pointer(unit, RH_LAG_FLOWSETm,
   2523                 rh_lag_flowset_entry_t *, buf_ptr, entry_index);
   2524         mod = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry,
   2525                 MODULE_IDf);
   2526         port = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry,
   2527                 PORT_NUMf);
   2528 
   2529         /* Determine if the randomly picked entry contains the new member.
   2530          * If not, determine the existing member index.
   2531          */
   2532         if (mod == new_mod && port == new_port) {
   2533             is_new_member = TRUE;
   2534         } else {
   2535             is_new_member = FALSE;
   2536         }
   2537         if (!is_new_member) {
   2538             for (i = 0; i < num_existing_members; i++) {
   2539                 if (mod == mod_arr[i] && port == port_arr[i]) {
   2540                     break;
   2541                 }
   2542             }
   2543             if (i == num_existing_members) {
   2544                 return BCM_E_INTERNAL;
   2545             }
   2546             member_index = i;
   2547         }
   2548 
   2549         if (!is_new_member && (entry_count_arr[member_index] > threshold)) {
   2550             soc_mem_field32_set(unit, RH_LAG_FLOWSETm, flowset_entry,
   2551                     MODULE_IDf, new_mod);
   2552             soc_mem_field32_set(unit, RH_LAG_FLOWSETm, flowset_entry,
   2553                     PORT_NUMf, new_port);
   2554             entry_count_arr[member_index]--;
   2555             new_member_entry_count++;
   2556         } else {
   2557             /* Either the member of the randomly chosen entry is
   2558              * the same as the new member, or the member is an existing
   2559              * member and its entry count has decreased to threshold.
   2560              * In both cases, find the next entry that contains a
   2561              * member that's not the new member and whose entry count
   2562              * has not decreased to threshold.
   2563              */
   2564             next_entry_index = (entry_index + 1) % num_entries;
   2565             while (next_entry_index != entry_index) {
   2566                 flowset_entry = soc_mem_table_idx_to_pointer(unit,
   2567                         RH_LAG_FLOWSETm, rh_lag_flowset_entry_t *, buf_ptr,
   2568                         next_entry_index);
   2569                 mod = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry,
   2570                         MODULE_IDf);
   2571                 port = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry,
   2572                         PORT_NUMf);
   2573 
   2574                 /* Determine if the entry contains the new member.
   2575                  * If not, determine the existing member index.
   2576                  */
   2577                 if (mod == new_mod && port == new_port) {
   2578                     is_new_member = TRUE;
   2579                 } else {
   2580                     is_new_member = FALSE;
   2581                 }
   2582                 if (!is_new_member) {
   2583                     for (i = 0; i < num_existing_members; i++) {
   2584                         if (mod == mod_arr[i] && port == port_arr[i]) {
   2585                             break;
   2586                         }
   2587                     }
   2588                     if (i == num_existing_members) {
   2589                         return BCM_E_INTERNAL;
   2590                     }
   2591                     member_index = i;
   2592                 }
   2593 
   2594                 if (!is_new_member &&
   2595                         (entry_count_arr[member_index] > threshold)) {
   2596                     soc_mem_field32_set(unit, RH_LAG_FLOWSETm, flowset_entry,
   2597                             MODULE_IDf, new_mod);
   2598                     soc_mem_field32_set(unit, RH_LAG_FLOWSETm, flowset_entry,
   2599                             PORT_NUMf, new_port);
   2600                     entry_count_arr[member_index]--;
   2601                     new_member_entry_count++;
   2602                     break;
   2603                 } else {
   2604                     next_entry_index = (next_entry_index + 1) % num_entries;
   2605                 }
   2606             }
   2607             if (next_entry_index == entry_index) {
   2608                 /* The entry count of all existing members has decreased
   2609                  * to threshold. The entry count of the new member has
   2610                  * not yet increased to lower_bound. Lower the threshold.
   2611                  */
   2612                 threshold--;
   2613             }
   2614         }
   2615     }
   2616     entry_count_arr[num_existing_members] = new_member_entry_count;
   2617 
   2618     return BCM_E_NONE;
   2619 }
   2620 
   2621 
   2622 /*
   2623  * Function:
   2624  *      bcm_td2_lag_rh_set
   2625  * Purpose:
   2626  *      Configure a LAG resilient hashing group.
   2627  * Parameters:
   2628  *      unit         - (IN) SOC unit number.
   2629  *      tid          - (IN) LAG trunk group ID.
   2630  *      add_info     - (IN) Pointer to trunk add info structure.
   2631  *      num_rh_ports - (IN) Number of resilient hashing eligible members in
   2632  *                          the group.
   2633  *      mod_array    - (IN) Array of module IDs of resilient hashing eligible
   2634  *                          members.
   2635  *      port_array   - (IN) Array of port IDs of resilient hashing eligible
   2636  *                          members.
   2637  * Returns:
   2638  *      BCM_E_xxx
   2639  */
   2640 int
   2641 bcm_td2_lag_rh_set(int unit,
   2642         int tid,
   2643         _esw_trunk_add_info_t *add_info,
   2644         int num_rh_ports,
   2645         int *mod_array,
   2646         int *port_array)
   2647 {
   2648     int rv = BCM_E_NONE;
   2649     int num_blocks;
   2650     int total_blocks;
   2651     int max_block_base_ptr;
   2652     int block_base_ptr;
   2653     int entry_base_ptr;
   2654     SHR_BITDCL occupied;
   2655     int alloc_size;
   2656     uint32 *buf_ptr = NULL;
   2657     int *entry_count_arr = NULL;
   2658     int max_entry_count;
   2659     int chosen_index;
   2660     int i;
   2661     rh_lag_flowset_entry_t *flowset_entry;
   2662     int index_min, index_max;
   2663     trunk_group_entry_t trunk_group_entry;
   2664     int flow_set_size;
   2665 
   2666 
   2667     if (add_info == NULL || add_info->psc != BCM_TRUNK_PSC_DYNAMIC_RESILIENT) {
   2668         return BCM_E_PARAM;
   2669     }
   2670 
   2671     if (num_rh_ports > 0 && (mod_array == NULL || port_array == NULL)) {
   2672         return BCM_E_PARAM;
   2673     }
   2674 
   2675     if (num_rh_ports == 0) {
   2676         /* Write the dynamic_size to hardware, so it can be
   2677          * recovered during warm boot.
   2678          */
   2679         BCM_IF_ERROR_RETURN(bcm_td2_lag_rh_dynamic_size_set(unit,
   2680                     tid, add_info->dynamic_size));
   2681         return BCM_E_NONE;
   2682     }
   2683 
   2684     /* Find a contiguous region of flow set table that's large
   2685      * enough to hold the requested number of flow sets.
   2686      * The flow set table is allocated in 64-entry blocks.
   2687      */
   2688     num_blocks = add_info->dynamic_size >> 6;
   2689     total_blocks = _td2_lag_rh_info[unit]->num_lag_rh_flowset_blocks;
   2690     if (num_blocks > total_blocks) {
   2691         return BCM_E_RESOURCE;
   2692     }
   2693     max_block_base_ptr = total_blocks - num_blocks;
   2694     for (block_base_ptr = 0;
   2695          block_base_ptr <= max_block_base_ptr;
   2696          block_base_ptr++) {
   2697         /* Check if the contiguous region of flow set table from
   2698          * block_base_ptr to (block_base_ptr + num_blocks - 1) is free.
   2699          */
   2700         _BCM_LAG_RH_FLOWSET_BLOCK_TEST_RANGE(unit, block_base_ptr, num_blocks,
   2701                 occupied);
   2702         if (!occupied) {
   2703             break;
   2704         }
   2705     }
   2706     if (block_base_ptr > max_block_base_ptr) {
   2707         /* A contiguous region of the desired size could not be found in
   2708          * flow set table.
   2709          */
   2710         return BCM_E_RESOURCE;
   2711     }
   2712 
   2713     /* Configure flow set table */
   2714     alloc_size = add_info->dynamic_size * sizeof(rh_lag_flowset_entry_t);
   2715     buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_LAG_FLOWSET entries");
   2716     if (NULL == buf_ptr) {
   2717         return BCM_E_MEMORY;
   2718     }
   2719     sal_memset(buf_ptr, 0, alloc_size);
   2720 
   2721     entry_count_arr = sal_alloc(sizeof(int) * num_rh_ports,
   2722             "RH entry count array");
   2723     if (NULL == entry_count_arr) {
   2724         soc_cm_sfree(unit, buf_ptr);
   2725         return BCM_E_MEMORY;
   2726     }
   2727     sal_memset(entry_count_arr, 0, sizeof(int) * num_rh_ports);
   2728     max_entry_count = add_info->dynamic_size / num_rh_ports;
   2729 
   2730     for (i = 0; i < add_info->dynamic_size; i++) {
   2731         /* Choose a member of the LAG */
   2732         rv = _bcm_td2_lag_rh_member_choose(unit, num_rh_ports,
   2733                 entry_count_arr, &max_entry_count, &chosen_index);
   2734         if (BCM_FAILURE(rv)) {
   2735             soc_cm_sfree(unit, buf_ptr);
   2736             sal_free(entry_count_arr);
   2737             return rv;
   2738         }
   2739 
   2740         /* Set flow set entry */
   2741         flowset_entry = soc_mem_table_idx_to_pointer(unit,
   2742                 RH_LAG_FLOWSETm, rh_lag_flowset_entry_t *, buf_ptr, i);
   2743         soc_mem_field32_set(unit, RH_LAG_FLOWSETm, flowset_entry, VALIDf, 1);
   2744         soc_mem_field32_set(unit, RH_LAG_FLOWSETm, flowset_entry, MODULE_IDf,
   2745                 mod_array[chosen_index]);
   2746         soc_mem_field32_set(unit, RH_LAG_FLOWSETm, flowset_entry, PORT_NUMf,
   2747                 port_array[chosen_index]);
   2748     }
   2749 
   2750     entry_base_ptr = block_base_ptr << 6;
   2751     index_min = entry_base_ptr;
   2752     index_max = index_min + add_info->dynamic_size - 1;
   2753     rv = soc_mem_write_range(unit, RH_LAG_FLOWSETm, MEM_BLOCK_ALL,
   2754             index_min, index_max, buf_ptr);
   2755     if (SOC_FAILURE(rv)) {
   2756         soc_cm_sfree(unit, buf_ptr);
   2757         sal_free(entry_count_arr);
   2758         return rv;
   2759     }
   2760     soc_cm_sfree(unit, buf_ptr);
   2761     sal_free(entry_count_arr);
   2762 
   2763     _BCM_LAG_RH_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr, num_blocks);
   2764 
   2765     /* Update TRUNK_GROUP */
   2766     SOC_IF_ERROR_RETURN(READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, tid,
   2767                 &trunk_group_entry));
   2768 
   2769     if (soc_mem_field_valid(unit, TRUNK_GROUPm, ENHANCED_HASHING_ENABLEf)) {
   2770         soc_TRUNK_GROUPm_field32_set(unit, &trunk_group_entry,
   2771                   ENHANCED_HASHING_ENABLEf, 1);
   2772     } else {
   2773         soc_TRUNK_GROUPm_field32_set(unit, &trunk_group_entry,
   2774                   TRUNK_MODEf, 3);
   2775     }
   2776     soc_TRUNK_GROUPm_field32_set(unit, &trunk_group_entry,
   2777             RH_FLOW_SET_BASEf, entry_base_ptr);
   2778     BCM_IF_ERROR_RETURN(bcm_td2_lag_rh_dynamic_size_encode(unit,
   2779                 add_info->dynamic_size, &flow_set_size));
   2780     soc_TRUNK_GROUPm_field32_set(unit, &trunk_group_entry,
   2781             RH_FLOW_SET_SIZEf, flow_set_size);
   2782     SOC_IF_ERROR_RETURN(WRITE_TRUNK_GROUPm(unit, MEM_BLOCK_ALL, tid,
   2783                 &trunk_group_entry));
   2784 
   2785     return BCM_E_NONE;
   2786 }
   2787 
   2788 
   2789 /*
   2790  * Function:
   2791  *      bcm_td2_lag_rh_add
   2792  * Purpose:
   2793  *      Add a member to a LAG resilient hashing group.
   2794  * Parameters:
   2795  *      unit     - (IN) SOC unit number. 
   2796  *      tid      - (IN) LAG trunk group ID.
   2797  *      add_info - (IN) Pointer to trunk add info structure.
   2798  *      num_rh_ports - (IN) Number of resilient hashing eligible members in
   2799  *                          the group, including the member to be added.
   2800  *      mod_array    - (IN) Array of module IDs of resilient hashing eligible
   2801  *                          members, including the member to be added.
   2802  *      port_array   - (IN) Array of port IDs of resilient hashing eligible
   2803  *                          members, including the member to be added.
   2804  *      new_member   - (IN) Member to add.
   2805  * Returns:
   2806  *      BCM_E_xxx
   2807  */
   2808 int
   2809 bcm_td2_lag_rh_add(int unit,
   2810         int tid,
   2811         _esw_trunk_add_info_t *add_info,
   2812         int num_rh_ports,
   2813         int *mod_array,
   2814         int *port_array,
   2815         bcm_trunk_member_t *new_member)
   2816 {
   2817     int rv = BCM_E_NONE;
   2818     bcm_port_t new_port;
   2819     bcm_module_t new_mod;
   2820     int num_existing_members;
   2821     int i, j;
   2822     trunk_group_entry_t trunk_group_entry;
   2823     int entry_base_ptr;
   2824     int flow_set_size;
   2825     int num_entries;
   2826     int alloc_size;
   2827     uint32 *buf_ptr = NULL;
   2828     int index_min, index_max;
   2829     int *entry_count_arr = NULL;
   2830     rh_lag_flowset_entry_t *flowset_entry;
   2831     bcm_module_t mod;
   2832     bcm_port_t port;
   2833     int lower_bound, upper_bound;
   2834 
   2835     if (add_info == NULL || add_info->psc != BCM_TRUNK_PSC_DYNAMIC_RESILIENT) {
   2836         return BCM_E_PARAM;
   2837     }
   2838 
   2839     if (num_rh_ports == 0 || mod_array == NULL || port_array == NULL) {
   2840         return BCM_E_PARAM;
   2841     }
   2842 
   2843     if (new_member == NULL) {
   2844         return BCM_E_PARAM;
   2845     }
   2846 
   2847     if (num_rh_ports == 1) {
   2848         /* Adding the first member is the same as setting one member */
   2849         return bcm_td2_lag_rh_set(unit, tid, add_info, num_rh_ports, mod_array,
   2850                 port_array);
   2851     }
   2852 
   2853     BCM_IF_ERROR_RETURN(_bcm_esw_trunk_gport_array_resolve(unit, FALSE, 1,
   2854                 &new_member->gport, &new_port, &new_mod));
   2855 
   2856     /* Swap new member to the last one for BCM_TRUNK_FLAG_MEMBER_SORT */
   2857     if (add_info->flags & BCM_TRUNK_FLAG_MEMBER_SORT) {
   2858         for (i = 0; i < num_rh_ports; i++){
   2859             if (i == (num_rh_ports - 1)) {
   2860                 break;
   2861             }
   2862             if (new_mod == mod_array[i] &&
   2863                 new_port == port_array[i]) {
   2864                 mod = mod_array[i];
   2865                 port = port_array[i];
   2866                 mod_array[i] = mod_array[num_rh_ports - 1];
   2867                 port_array[i] = port_array[num_rh_ports - 1];
   2868                 mod_array[num_rh_ports - 1] = mod;
   2869                 port_array[num_rh_ports - 1] = port;
   2870                 break;
   2871             }    
   2872         }
   2873     }
   2874 
   2875     /* Check that the new member is the last element of the array of
   2876      * resilient hashing eligible members.
   2877      */
   2878     if (new_mod != mod_array[num_rh_ports - 1] ||
   2879         new_port != port_array[num_rh_ports - 1]) {
   2880         return BCM_E_PARAM;
   2881     }
   2882     num_existing_members = num_rh_ports - 1;
   2883 
   2884     /* Read all the flow set entries of this LAG resilient hash group,
   2885      * and compute the number of entries currently assigned to each
   2886      * existing member.
   2887      */
   2888     SOC_IF_ERROR_RETURN
   2889         (READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, tid, &trunk_group_entry));
   2890     entry_base_ptr = soc_TRUNK_GROUPm_field32_get(unit, &trunk_group_entry,
   2891             RH_FLOW_SET_BASEf);
   2892     flow_set_size = soc_TRUNK_GROUPm_field32_get(unit, &trunk_group_entry,
   2893             RH_FLOW_SET_SIZEf);
   2894     BCM_IF_ERROR_RETURN
   2895         (_bcm_td2_lag_rh_dynamic_size_decode(unit, flow_set_size,
   2896                                              &num_entries));
   2897 
   2898     alloc_size = num_entries * sizeof(rh_lag_flowset_entry_t);
   2899     buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_LAG_FLOWSET entries");
   2900     if (NULL == buf_ptr) {
   2901         return BCM_E_MEMORY;
   2902     }
   2903     sal_memset(buf_ptr, 0, alloc_size);
   2904     index_min = entry_base_ptr;
   2905     index_max = index_min + num_entries - 1;
   2906     rv = soc_mem_read_range(unit, RH_LAG_FLOWSETm, MEM_BLOCK_ANY,
   2907             index_min, index_max, buf_ptr);
   2908     if (SOC_FAILURE(rv)) {
   2909         goto cleanup;
   2910     }
   2911 
   2912     alloc_size = num_rh_ports * sizeof(int);
   2913     entry_count_arr = sal_alloc(alloc_size, "LAG RH entry count array");
   2914     if (NULL == entry_count_arr) {
   2915         rv = BCM_E_MEMORY;
   2916         goto cleanup;
   2917     }
   2918     sal_memset(entry_count_arr, 0, alloc_size);
   2919 
   2920     for (i = 0; i < num_entries; i++) {
   2921         flowset_entry = soc_mem_table_idx_to_pointer(unit,
   2922                 RH_LAG_FLOWSETm, rh_lag_flowset_entry_t *, buf_ptr, i);
   2923         if (!soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry,
   2924                     VALIDf)) {
   2925             rv = BCM_E_INTERNAL;
   2926             goto cleanup;
   2927         }
   2928         mod = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry,
   2929                 MODULE_IDf);
   2930         port = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry,
   2931                 PORT_NUMf);
   2932         for (j = 0; j < num_existing_members; j++) {
   2933             if (mod == mod_array[j] && port == port_array[j]) {
   2934                 break;
   2935             }
   2936         }
   2937         if (j == num_existing_members) {
   2938             rv = BCM_E_INTERNAL;
   2939             goto cleanup;
   2940         }
   2941         entry_count_arr[j]++;
   2942     }
   2943 
   2944     /* Check that the distribution of flow set entries among existing members
   2945      * is balanced. For instance, if the number of flow set entries is 64, and
   2946      * the number of existing members is 6, then every member should have
   2947      * between 10 and 11 entries.
   2948      */
   2949     lower_bound = num_entries / num_existing_members;
   2950     upper_bound = (num_entries % num_existing_members) ?
   2951                   (lower_bound + 1) : lower_bound;
   2952     for (i = 0; i < num_existing_members; i++) {
   2953         if (entry_count_arr[i] < lower_bound ||
   2954                 entry_count_arr[i] > upper_bound) {
   2955             rv = BCM_E_INTERNAL;
   2956             goto cleanup;
   2957         }
   2958     }
   2959 
   2960     rv = _bcm_td2_lag_rh_add_rebalance(unit, num_entries, buf_ptr,
   2961                       num_rh_ports, entry_count_arr, mod_array, port_array);
   2962     if (SOC_FAILURE(rv)) {
   2963         goto cleanup;
   2964     }
   2965 
   2966     /* Write re-balanced flow set entries to hardware */
   2967     rv = soc_mem_write_range(unit, RH_LAG_FLOWSETm, MEM_BLOCK_ALL,
   2968             index_min, index_max, buf_ptr);
   2969 
   2970 cleanup:
   2971     if (buf_ptr) {
   2972         soc_cm_sfree(unit, buf_ptr);
   2973     }
   2974     if (entry_count_arr) {
   2975         sal_free(entry_count_arr);
   2976     }
   2977 
   2978     return rv;
   2979 }
   2980 
   2981 /*
   2982  * Function:
   2983  *      bcm_td2_lag_rh_delete
   2984  * Purpose:
   2985  *      Delete a member from a LAG resilient hashing group.
   2986  * Parameters:
   2987  *      unit  - (IN) SOC unit number. 
   2988  *      tid - (IN) LAG trunk group ID.
   2989  *      add_info - (IN) Pointer to trunk add info structure.
   2990  *      num_rh_ports - (IN) Number of resilient hashing eligible members in
   2991  *                          the group, except the member to be deleted.
   2992  *      mod_array    - (IN) Array of module IDs of resilient hashing eligible
   2993  *                          members, except the member to be deleted.
   2994  *      port_array   - (IN) Array of port IDs of resilient hashing eligible
   2995  *                          members, except the member to be deleted.
   2996  *      leaving_member - (IN) Member to delete.
   2997  * Returns:
   2998  *      BCM_E_xxx
   2999  */
   3000 int
   3001 bcm_td2_lag_rh_delete(int unit,
   3002         int tid,
   3003         _esw_trunk_add_info_t *add_info,
   3004         int num_rh_ports,
   3005         int *mod_array,
   3006         int *port_array,
   3007         bcm_trunk_member_t *leaving_member)
   3008 {
   3009     int rv = BCM_E_NONE;
   3010     bcm_port_t leaving_port;
   3011     bcm_module_t leaving_mod;
   3012     bcm_gport_t  leaving_gport;
   3013     int num_remaining_members;
   3014     int i, j;
   3015     trunk_group_entry_t trunk_group_entry;
   3016     int entry_base_ptr;
   3017     int flow_set_size;
   3018     int num_entries;
   3019     int alloc_size;
   3020     uint32 *buf_ptr = NULL;
   3021     int index_min, index_max;
   3022     int leaving_member_entry_count;
   3023     int *entry_count_arr = NULL;
   3024     rh_lag_flowset_entry_t *flowset_entry;
   3025     bcm_module_t mod;
   3026     bcm_port_t port;
   3027     int lower_bound, upper_bound;
   3028 
   3029     if (add_info == NULL || add_info->psc != BCM_TRUNK_PSC_DYNAMIC_RESILIENT) {
   3030         return BCM_E_PARAM;
   3031     }
   3032 
   3033     if (num_rh_ports > 0 && (mod_array == NULL || port_array == NULL)) {
   3034         return BCM_E_PARAM;
   3035     }
   3036 
   3037     if (leaving_member == NULL) {
   3038         return BCM_E_PARAM;
   3039     }
   3040 
   3041     if (num_rh_ports == 0) {
   3042         /* Deleting the last member is the same as freeing all resources */
   3043         BCM_IF_ERROR_RETURN(bcm_td2_lag_rh_free_resource(unit, tid));
   3044 
   3045         /* Write the dynamic_size to hardware, so it can be recovered
   3046          * during warm boot.
   3047          */
   3048         BCM_IF_ERROR_RETURN(bcm_td2_lag_rh_dynamic_size_set(unit, tid,
   3049                     add_info->dynamic_size));
   3050 
   3051         return BCM_E_NONE;
   3052     }
   3053 
   3054     /* Check that the leaving member is not a member of the array */
   3055     BCM_IF_ERROR_RETURN(_bcm_esw_trunk_gport_array_resolve(unit, FALSE, 1,
   3056                 &leaving_member->gport, &leaving_port, &leaving_mod));
   3057     for (i = 0; i < num_rh_ports; i++) {
   3058         if (leaving_mod == mod_array[i] && leaving_port == port_array[i]) {
   3059             return BCM_E_PARAM;
   3060         }
   3061     }
   3062     num_remaining_members = num_rh_ports;
   3063 
   3064     /* Read all the flow set entries of this LAG resilient hash group,
   3065      * and compute the number of entries currently assigned to each
   3066      * member, including the leaving member.
   3067      */
   3068     SOC_IF_ERROR_RETURN
   3069         (READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, tid, &trunk_group_entry));
   3070     entry_base_ptr = soc_TRUNK_GROUPm_field32_get(unit, &trunk_group_entry,
   3071             RH_FLOW_SET_BASEf);
   3072     flow_set_size = soc_TRUNK_GROUPm_field32_get(unit, &trunk_group_entry,
   3073             RH_FLOW_SET_SIZEf);
   3074     BCM_IF_ERROR_RETURN
   3075         (_bcm_td2_lag_rh_dynamic_size_decode(unit, flow_set_size,
   3076                                              &num_entries));
   3077 
   3078     alloc_size = num_entries * sizeof(rh_lag_flowset_entry_t);
   3079     buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_LAG_FLOWSET entries");
   3080     if (NULL == buf_ptr) {
   3081         return BCM_E_MEMORY;
   3082     }
   3083     sal_memset(buf_ptr, 0, alloc_size);
   3084     index_min = entry_base_ptr;
   3085     index_max = index_min + num_entries - 1;
   3086     rv = soc_mem_read_range(unit, RH_LAG_FLOWSETm, MEM_BLOCK_ANY,
   3087             index_min, index_max, buf_ptr);
   3088     if (SOC_FAILURE(rv)) {
   3089         goto cleanup;
   3090     }
   3091 
   3092     alloc_size = num_remaining_members * sizeof(int);
   3093     entry_count_arr = sal_alloc(alloc_size, "RH entry count array");
   3094     if (NULL == entry_count_arr) {
   3095         rv = BCM_E_MEMORY;
   3096         goto cleanup;
   3097     }
   3098     sal_memset(entry_count_arr, 0, alloc_size);
   3099 
   3100     leaving_member_entry_count = 0;
   3101     for (i = 0; i < num_entries; i++) {
   3102         flowset_entry = soc_mem_table_idx_to_pointer(unit,
   3103                 RH_LAG_FLOWSETm, rh_lag_flowset_entry_t *, buf_ptr, i);
   3104         if (!soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry,
   3105                     VALIDf)) {
   3106             rv = BCM_E_INTERNAL;
   3107             goto cleanup;
   3108         }
   3109         mod = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry,
   3110                 MODULE_IDf);
   3111         port = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry,
   3112                 PORT_NUMf);
   3113         if (mod == leaving_mod && port == leaving_port) {
   3114             leaving_member_entry_count++;
   3115         } else {
   3116             for (j = 0; j < num_remaining_members; j++) {
   3117                 if (mod == mod_array[j] && port == port_array[j]) {
   3118                     break;
   3119                 }
   3120             }
   3121             if (j == num_remaining_members) {
   3122                 rv = BCM_E_INTERNAL;
   3123                 goto cleanup;
   3124             }
   3125             entry_count_arr[j]++;
   3126         }
   3127     }
   3128 
   3129     /* Check that the distribution of flow set entries among all members
   3130      * is balanced. For instance, if the number of flow set entries is 64, and
   3131      * the number of members is 6, then every member should have
   3132      * between 10 and 11 entries. 
   3133      */ 
   3134     lower_bound = num_entries / (num_remaining_members + 1);
   3135     upper_bound = (num_entries % (num_remaining_members + 1)) ?
   3136                   (lower_bound + 1) : lower_bound;
   3137     for (i = 0; i < num_remaining_members; i++) {
   3138         if (entry_count_arr[i] < lower_bound ||
   3139                 entry_count_arr[i] > upper_bound) {
   3140             rv = BCM_E_INTERNAL;
   3141             goto cleanup;
   3142         }
   3143     }
   3144     if (leaving_member_entry_count < lower_bound ||
   3145             leaving_member_entry_count > upper_bound) {
   3146         rv = BCM_E_INTERNAL;
   3147         goto cleanup;
   3148     }
   3149 
   3150     BCM_GPORT_MODPORT_SET(leaving_gport, leaving_mod, leaving_port);
   3151     rv = _bcm_td2_lag_rh_delete_rebalance(unit, num_entries, buf_ptr,
   3152                 num_remaining_members, entry_count_arr, mod_array,port_array,
   3153                 1, &leaving_gport);
   3154     if (SOC_FAILURE(rv)) {
   3155         goto cleanup;
   3156     }
   3157 
   3158     /* Write re-balanced flow set entries to hardware */
   3159     rv = soc_mem_write_range(unit, RH_LAG_FLOWSETm, MEM_BLOCK_ALL,
   3160             index_min, index_max, buf_ptr);
   3161 
   3162 cleanup:
   3163     if (buf_ptr) {
   3164         soc_cm_sfree(unit, buf_ptr);
   3165     }
   3166     if (entry_count_arr) {
   3167         sal_free(entry_count_arr);
   3168     }
   3169 
   3170     return rv;
   3171 }
   3172 
   3173 
   3174 
   3175 
   3176 /*
   3177  * Function:
   3178  *      bcm_td2_lag_rh_replace
   3179  * Purpose:
   3180  *      Replace TRUNK resilient hashing group members without flowset table shuffle.
   3181  * Parameters:
   3182  *      unit         - (IN) SOC unit number.
   3183  *      tid          - (IN) LAG trunk group ID.
   3184  *      add_info     - (IN) Pointer to trunk add info structure.
   3185  *      num_rh_ports - (IN) Number of resilient hashing eligible members in
   3186  *                          the group, except the member to be deleted.
   3187  *      mod_array    - (IN) Array of module IDs of resilient hashing eligible
   3188  *                          members, except the member to be deleted.
   3189  *      port_array   - (IN) Array of port IDs of resilient hashing eligible
   3190  *                          members, except the member to be deleted.
   3191  *      num_existing   - (IN) Number of existing members.
   3192  *      existing_ports - (IN) Ports of existing members.
   3193  *      existing_flags - (IN) Flags of existing members.
   3194  * Returns:
   3195  *      BCM_E_xxx
   3196  */
   3197 int
   3198 bcm_td2_lag_rh_replace(int unit,
   3199                        int tid,
   3200                        _esw_trunk_add_info_t *add_info,
   3201                        int num_rh_ports,
   3202                        int *mod_array,
   3203                        int *port_array,
   3204                        uint16  num_existing,
   3205                        uint16 *existing_modports,
   3206                        uint32 *existing_flags)
   3207 {
   3208     int                     rv = BCM_E_NONE;
   3209     bcm_gport_t             gport;
   3210     bcm_gport_t             *existing_gports = NULL;
   3211     bcm_gport_t             *leaving_gports = NULL;
   3212     bcm_gport_t             *staying_gports = NULL;
   3213     bcm_gport_t             *joining_gports = NULL;
   3214     int                     num_leaving = 0;
   3215     int                     num_staying = 0;
   3216     int                     num_joining = 0;
   3217     int                     num_partial;
   3218     int                     *rearr_mod  = NULL;
   3219     int                     *rearr_port = NULL;
   3220     int                     i, j, k;
   3221     int                     index_min= 0;
   3222     int                     index_max= 0;
   3223     int                     num_entries = 0;
   3224     int                     alloc_size;
   3225     uint32                  *buf_ptr         = NULL;
   3226     int                     *entry_count_arr = NULL;
   3227     int                     mod;
   3228     int                     port;
   3229     rh_lag_flowset_entry_t  *fs_entry;
   3230     trunk_group_entry_t     tg_entry;
   3231 
   3232     if (add_info == NULL ||
   3233         add_info->psc != BCM_TRUNK_PSC_DYNAMIC_RESILIENT) {
   3234         return BCM_E_PARAM;
   3235     }
   3236 
   3237     if (num_rh_ports > 0 && (mod_array == NULL || port_array == NULL)) {
   3238         return BCM_E_PARAM;
   3239     }
   3240 
   3241     if (num_existing > 0 &&
   3242         (existing_modports == NULL || existing_flags == NULL)) {
   3243         return BCM_E_PARAM;
   3244     }
   3245 
   3246     /* Get gports of existing members */
   3247     alloc_size = sizeof(bcm_gport_t) * num_existing;
   3248     existing_gports = sal_alloc(alloc_size, "existing_gports");
   3249     if (existing_gports == NULL) {
   3250         rv = BCM_E_MEMORY;
   3251         goto cleanup;
   3252     }
   3253     sal_memset(existing_gports, 0, alloc_size);
   3254     for (i = 0, j = 0; i < num_existing; i++) {
   3255         mod = existing_modports[i] >> 8;
   3256         port = existing_modports[i] & 0xff;
   3257 
   3258         if ((existing_flags[i] & BCM_TRUNK_MEMBER_EGRESS_DISABLE) ||
   3259             (existing_flags[i] & BCM_TRUNK_MEMBER_UNICAST_EGRESS_DISABLE)) {
   3260             continue;
   3261         }
   3262         BCM_GPORT_MODPORT_SET(existing_gports[j], mod, port);
   3263         j++;
   3264     }
   3265     num_existing = j;
   3266 
   3267     if (num_rh_ports == 0 || num_rh_ports == 1 || num_existing == 0) {
   3268         rv = bcm_td2_lag_rh_free_resource(unit, tid);
   3269         rv = BCM_FAILURE(rv) ? rv :
   3270              bcm_td2_lag_rh_set(unit, tid, add_info, num_rh_ports, mod_array,
   3271                 port_array);
   3272         goto cleanup;
   3273     }
   3274 
   3275     /* Figure out which members are leaving, staying or joining
   3276      * the trunk group.
   3277      * Note. For resilient hash, all members are different within a TRUNK.
   3278      */
   3279     alloc_size = sizeof(bcm_gport_t) * num_existing;
   3280     leaving_gports = sal_alloc(alloc_size, "leaving members");
   3281     if (leaving_gports == NULL) {
   3282         rv = BCM_E_MEMORY;
   3283         goto cleanup;
   3284     }
   3285     sal_memset(leaving_gports, 0, alloc_size);
   3286 
   3287     alloc_size = sizeof(bcm_gport_t) * num_existing;
   3288     staying_gports = sal_alloc(alloc_size, "staying members");
   3289     if (staying_gports == NULL) {
   3290         rv = BCM_E_MEMORY;
   3291         goto cleanup;
   3292     }
   3293     sal_memset(staying_gports, 0, alloc_size);
   3294 
   3295     for (i = 0; i < num_existing; i++) {
   3296         mod = BCM_GPORT_MODPORT_MODID_GET(existing_gports[i]);
   3297         port = BCM_GPORT_MODPORT_PORT_GET(existing_gports[i]);
   3298         for (j = 0; j < num_rh_ports; j++) {
   3299             if (mod == mod_array[j] && port == port_array[j]) {
   3300                 break;
   3301             }
   3302         }
   3303         if (j == num_rh_ports) {
   3304             leaving_gports[num_leaving++] = existing_gports[i];
   3305         } else {
   3306             staying_gports[num_staying++] = existing_gports[i];
   3307         }
   3308     }
   3309 
   3310     alloc_size = sizeof(bcm_gport_t) * num_rh_ports;
   3311     joining_gports = sal_alloc(alloc_size, "joining members");
   3312     if (joining_gports == NULL) {
   3313         rv = BCM_E_MEMORY;
   3314         goto cleanup;
   3315     }
   3316     sal_memset(joining_gports, 0, alloc_size);
   3317     for (i = 0; i < num_rh_ports; i++) {
   3318         BCM_GPORT_MODPORT_SET(gport, mod_array[i], port_array[i]);
   3319         for (j = 0; j < num_staying; j++) {
   3320             if (gport == staying_gports[j]) {
   3321                 break;
   3322             }
   3323         }
   3324         if (j == num_staying) {
   3325             joining_gports[num_joining++] = gport;
   3326         }
   3327     }
   3328 
   3329     if (num_staying + num_leaving != num_existing) {
   3330         rv = BCM_E_INTERNAL;
   3331         goto cleanup;
   3332     }
   3333 
   3334     if (num_staying + num_joining != num_rh_ports) {
   3335         rv = BCM_E_INTERNAL;
   3336         goto cleanup;
   3337     }
   3338 
   3339     rv = READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, tid, &tg_entry);
   3340     if (BCM_FAILURE(rv)) {
   3341         goto cleanup;
   3342     }
   3343     index_min = soc_TRUNK_GROUPm_field32_get(unit, &tg_entry,
   3344             RH_FLOW_SET_BASEf);
   3345     num_entries = soc_TRUNK_GROUPm_field32_get(unit, &tg_entry,
   3346             RH_FLOW_SET_SIZEf);
   3347     rv = _bcm_td2_lag_rh_dynamic_size_decode(unit, num_entries, &num_entries);
   3348     if (BCM_FAILURE(rv)) {
   3349         goto cleanup;
   3350     }
   3351 
   3352     index_max = index_min + num_entries - 1;
   3353 
   3354     alloc_size = num_entries * sizeof(rh_lag_flowset_entry_t);
   3355     buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_LAG_FLOWSET entries");
   3356     if (NULL == buf_ptr) {
   3357         rv = BCM_E_MEMORY;
   3358         goto cleanup;
   3359     }
   3360     sal_memset(buf_ptr, 0, alloc_size);
   3361 
   3362     /* Read various tables through DMA */
   3363     if ((rv = soc_mem_read_range(unit, RH_LAG_FLOWSETm, MEM_BLOCK_ANY,
   3364                     index_min, index_max, buf_ptr)) < 0 ) {
   3365         goto cleanup;
   3366     }
   3367 
   3368     alloc_size = num_rh_ports * sizeof(int);
   3369     rearr_mod = sal_alloc(alloc_size, "rearr_mod");
   3370     if (rearr_mod == NULL) {
   3371         rv = BCM_E_MEMORY;
   3372         goto cleanup;
   3373     }
   3374     sal_memset(rearr_mod, 0, alloc_size);
   3375 
   3376     rearr_port = sal_alloc(alloc_size, "rearr_port");
   3377     if (rearr_port == NULL) {
   3378         rv = BCM_E_MEMORY;
   3379         goto cleanup;
   3380     }
   3381     sal_memset(rearr_port, 0, alloc_size);
   3382 
   3383 
   3384     for (i = 0; i < num_staying; i++) {
   3385         rearr_mod[i] = BCM_GPORT_MODPORT_MODID_GET(staying_gports[i]);
   3386         rearr_port[i] = BCM_GPORT_MODPORT_PORT_GET(staying_gports[i]);
   3387     }
   3388 
   3389     num_partial = num_existing > num_rh_ports ? num_rh_ports : num_existing;
   3390     for (i = num_staying, k = 0; i < num_partial; i++) {
   3391         rearr_mod[i] = BCM_GPORT_MODPORT_MODID_GET(joining_gports[k]);
   3392         rearr_port[i] = BCM_GPORT_MODPORT_PORT_GET(joining_gports[k]);
   3393         k++;
   3394     }
   3395 
   3396     /* Get entry count for each staying member port */
   3397     alloc_size = num_rh_ports * sizeof(int);
   3398     entry_count_arr = sal_alloc(alloc_size, "RH entry count array");
   3399     if (NULL == entry_count_arr) {
   3400         rv = BCM_E_MEMORY;
   3401         goto cleanup;
   3402     }
   3403     sal_memset(entry_count_arr, 0, alloc_size);
   3404 
   3405     for (i = 0; i < num_entries; i++) {
   3406         fs_entry = soc_mem_table_idx_to_pointer(unit,
   3407                 RH_LAG_FLOWSETm, rh_lag_flowset_entry_t *, buf_ptr, i);
   3408         if (!soc_mem_field32_get(unit, RH_LAG_FLOWSETm, fs_entry,
   3409                     VALIDf)) {
   3410             rv = BCM_E_INTERNAL;
   3411             goto cleanup;
   3412         }
   3413         mod = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, fs_entry,
   3414                 MODULE_IDf);
   3415         port = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, fs_entry,
   3416                 PORT_NUMf);
   3417         for (j = 0; j < num_staying; j++) {
   3418             if (mod == rearr_mod[j] && port == rearr_port[j]) {
   3419                 break;
   3420             }
   3421         }
   3422 
   3423         if (j < num_staying) {
   3424             entry_count_arr[j]++;
   3425         }
   3426     }
   3427 
   3428     if (num_leaving > 0) {
   3429         rv = _bcm_td2_lag_rh_delete_rebalance(unit, num_entries, buf_ptr,
   3430                          num_partial, entry_count_arr,rearr_mod,rearr_port,
   3431                          num_leaving, leaving_gports);
   3432         if (BCM_FAILURE(rv)) {
   3433             goto cleanup;
   3434         }
   3435     }
   3436 
   3437     for (j = num_partial; j < num_rh_ports; j++) {
   3438         rearr_mod[j] = BCM_GPORT_MODPORT_MODID_GET(joining_gports[k]);
   3439         rearr_port[j] = BCM_GPORT_MODPORT_PORT_GET(joining_gports[k]);
   3440 
   3441         rv = _bcm_td2_lag_rh_add_rebalance(unit, num_entries, buf_ptr,
   3442                         j + 1, entry_count_arr, rearr_mod, rearr_port);
   3443         if (BCM_FAILURE(rv)) {
   3444             goto cleanup;
   3445         }
   3446         k++;
   3447     }
   3448 
   3449     /* Write re-balanced flow set entries to hardware */
   3450     rv = soc_mem_write_range(unit, RH_LAG_FLOWSETm, MEM_BLOCK_ALL,
   3451             index_min, index_max, buf_ptr);
   3452 
   3453 cleanup:
   3454     if(existing_gports) {
   3455         sal_free(existing_gports);
   3456     }
   3457     if(leaving_gports) {
   3458         sal_free(leaving_gports);
   3459     }
   3460     if(staying_gports) {
   3461         sal_free(staying_gports);
   3462     }
   3463     if(joining_gports) {
   3464         sal_free(joining_gports);
   3465     }
   3466     if(rearr_mod) {
   3467         sal_free(rearr_mod);
   3468     }
   3469     if(rearr_port) {
   3470         sal_free(rearr_port);
   3471     }
   3472     if(buf_ptr) {
   3473         soc_cm_sfree(unit, buf_ptr);
   3474     }
   3475     if(entry_count_arr) {
   3476         sal_free(entry_count_arr);
   3477     }
   3478     return rv;
   3479 
   3480 }
   3481 
   3482 
   3483 /*
   3484  * Function:
   3485  *      bcm_td2_lag_rh_ethertype_set
   3486  * Purpose:
   3487  *      Set the Ethertypes that are eligible or ineligible for
   3488  *      LAG resilient hashing.
   3489  * Parameters:
   3490  *      unit - (IN) Unit number.
   3491  *      flags - (IN) BCM_TRUNK_DYNAMIC_ETHERTYPE_xxx flags.
   3492  *      ethertype_count - (IN) Number of elements in ethertype_array.
   3493  *      ethertype_array - (IN) Array of Ethertypes.
   3494  * Returns:
   3495  *      BCM_E_XXX
   3496  */
   3497 int 
   3498 bcm_td2_lag_rh_ethertype_set(
   3499     int unit, 
   3500     uint32 flags, 
   3501     int ethertype_count, 
   3502     int *ethertype_array)
   3503 {
   3504     uint32 control_reg;
   3505     int i, j;
   3506     rh_lag_ethertype_eligibility_map_entry_t ethertype_entry;
   3507 
   3508     /* Input check */
   3509     if (ethertype_count > soc_mem_index_count(unit,
   3510                 RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm)) {
   3511         return BCM_E_RESOURCE;
   3512     }
   3513 
   3514     /* Update ethertype eligibility control register */
   3515     SOC_IF_ERROR_RETURN
   3516         (READ_RH_LAG_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, &control_reg));
   3517     soc_reg_field_set(unit, RH_LAG_ETHERTYPE_ELIGIBILITY_CONTROLr,
   3518             &control_reg, ETHERTYPE_ELIGIBILITY_CONFIGf,
   3519             flags & BCM_TRUNK_DYNAMIC_ETHERTYPE_ELIGIBLE ? 1 : 0);
   3520     soc_reg_field_set(unit, RH_LAG_ETHERTYPE_ELIGIBILITY_CONTROLr,
   3521             &control_reg, INNER_OUTER_ETHERTYPE_SELECTIONf,
   3522             flags & BCM_TRUNK_DYNAMIC_ETHERTYPE_INNER ? 1 : 0);
   3523     SOC_IF_ERROR_RETURN
   3524         (WRITE_RH_LAG_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, control_reg));
   3525 
   3526     /* Update Ethertype eligibility map table */
   3527     for (i = 0; i < ethertype_count; i++) {
   3528         sal_memset(&ethertype_entry, 0,
   3529                 sizeof(rh_lag_ethertype_eligibility_map_entry_t));
   3530         soc_RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm_field32_set(unit,
   3531                 &ethertype_entry, VALIDf, 1);
   3532         soc_RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm_field32_set(unit,
   3533                 &ethertype_entry, ETHERTYPEf, ethertype_array[i]);
   3534         SOC_IF_ERROR_RETURN(WRITE_RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm(unit,
   3535                     MEM_BLOCK_ALL, i, &ethertype_entry));
   3536     }
   3537 
   3538     /* Zero out remaining entries of Ethertype eligibility map table */
   3539     for (j = i; j < soc_mem_index_count(unit,
   3540                 RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm); j++) {
   3541         SOC_IF_ERROR_RETURN(WRITE_RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm(unit,
   3542                     MEM_BLOCK_ALL, j, soc_mem_entry_null(unit,
   3543                         RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm)));
   3544     }
   3545 
   3546     return BCM_E_NONE;
   3547 }
   3548 
   3549 /*
   3550  * Function:
   3551  *      bcm_td2_lag_rh_ethertype_get
   3552  * Purpose:
   3553  *      Get the Ethertypes that are eligible or ineligible for
   3554  *      LAG resilient hashing.
   3555  * Parameters:
   3556  *      unit - (IN) Unit number.
   3557  *      flags - (INOUT) BCM_TRUNK_DYNAMIC_ETHERTYPE_xxx flags.
   3558  *      ethertype_max - (IN) Number of elements in ethertype_array.
   3559  *      ethertype_array - (OUT) Array of Ethertypes.
   3560  *      ethertype_count - (OUT) Number of elements returned in ethertype_array.
   3561  * Returns:
   3562  *      BCM_E_XXX
   3563  */
   3564 int 
   3565 bcm_td2_lag_rh_ethertype_get(
   3566     int unit, 
   3567     uint32 *flags, 
   3568     int ethertype_max, 
   3569     int *ethertype_array, 
   3570     int *ethertype_count)
   3571 {
   3572     uint32 control_reg;
   3573     int i;
   3574     int ethertype;
   3575     rh_lag_ethertype_eligibility_map_entry_t ethertype_entry;
   3576 
   3577     *ethertype_count = 0;
   3578 
   3579     /* Get flags */
   3580     SOC_IF_ERROR_RETURN
   3581         (READ_RH_LAG_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, &control_reg));
   3582     if (soc_reg_field_get(unit, RH_LAG_ETHERTYPE_ELIGIBILITY_CONTROLr,
   3583                 control_reg, ETHERTYPE_ELIGIBILITY_CONFIGf)) {
   3584         *flags |= BCM_TRUNK_DYNAMIC_ETHERTYPE_ELIGIBLE;
   3585     }
   3586     if (soc_reg_field_get(unit, RH_LAG_ETHERTYPE_ELIGIBILITY_CONTROLr,
   3587                 control_reg, INNER_OUTER_ETHERTYPE_SELECTIONf)) {
   3588         *flags |= BCM_TRUNK_DYNAMIC_ETHERTYPE_INNER;
   3589     }
   3590 
   3591     /* Get Ethertypes */
   3592     for (i = 0; i < soc_mem_index_count(unit,
   3593                 RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm); i++) {
   3594         SOC_IF_ERROR_RETURN(READ_RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm(unit,
   3595                     MEM_BLOCK_ANY, i, &ethertype_entry));
   3596         if (soc_RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm_field32_get(unit,
   3597                     &ethertype_entry, VALIDf)) {
   3598             ethertype = soc_RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm_field32_get(unit,
   3599                     &ethertype_entry, ETHERTYPEf);
   3600             if (NULL != ethertype_array) {
   3601                 ethertype_array[*ethertype_count] = ethertype;
   3602             }
   3603             (*ethertype_count)++;
   3604             if ((ethertype_max > 0) && (*ethertype_count == ethertype_max)) {
   3605                 break;
   3606             }
   3607         }
   3608     }
   3609 
   3610     return BCM_E_NONE;
   3611 }
   3612 
   3613 #ifdef BCM_WARM_BOOT_SUPPORT
   3614 
   3615 /*
   3616  * Function:
   3617  *      bcm_td2_hg_rh_recover
   3618  * Purpose:
   3619  *      Recover Higig resilient hashing software state.
   3620  * Parameters:
   3621  *      unit - (IN) SOC unit number.
   3622  *      hgtid - (IN) Higig trunk ID.
   3623  *      trunk_info - (OUT) Pointer to trunk info.
   3624  * Returns:
   3625  *      BCM_E_xxx
   3626  */
   3627 int
   3628 bcm_td2_hg_rh_recover(int unit, int hgtid, trunk_private_t *trunk_info)
   3629 {
   3630     rh_hgt_group_control_entry_t rh_hgt_group_control_entry;
   3631     hg_trunk_group_entry_t hg_trunk_group_entry;
   3632     int flow_set_size;
   3633     int entry_base_ptr;
   3634     int num_entries;
   3635     int block_base_ptr;
   3636     int num_blocks;
   3637     hg_trunk_mode_entry_t hg_trunk_mode_entry;
   3638     uint32 rval;
   3639 
   3640     if (soc_feature(unit, soc_feature_td3_style_dlb_rh)) {
   3641         SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROL_2r(unit, &rval));
   3642         if (0 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROL_2r, rval,
   3643                 RH_DLB_SELECTIONf)) {
   3644            /* trunk resilient hashing is not enabled chip-wide. */
   3645             return BCM_E_NONE;
   3646         }
   3647     }
   3648 
   3649     /* A Higig trunk group can be in one of 3 resilient hashing states:
   3650      * (1) RH not enabled: RH_HGT_GROUP_CONTROL.FLOW_SET_SIZE = 0.
   3651      * (2) RH enabled but without any members:
   3652      *     RH_HGT_GROUP_CONTROL.FLOW_SET_SIZE is non-zero,
   3653      *     HG_TRUNK_GROUP.ENHANCED_HASHING_ENABLE = 0.
   3654      * (3) RH enabled with members:
   3655      *     RH_HGT_GROUP_CONTROL.FLOW_SET_SIZE is non-zero,
   3656      *     HG_TRUNK_GROUP.ENHANCED_HASHING_ENABLE = 1.
   3657      */
   3658 
   3659     SOC_IF_ERROR_RETURN(READ_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, hgtid,
   3660                 &hg_trunk_group_entry));
   3661     if (soc_feature(unit, soc_feature_td3_style_dlb_rh)) {
   3662         flow_set_size = soc_HG_TRUNK_GROUPm_field32_get(unit,
   3663                        &hg_trunk_group_entry, RH_FLOW_SET_SIZEf);
   3664     } else {
   3665         SOC_IF_ERROR_RETURN(READ_RH_HGT_GROUP_CONTROLm(unit, MEM_BLOCK_ANY,
   3666                 hgtid, &rh_hgt_group_control_entry));
   3667         flow_set_size = soc_RH_HGT_GROUP_CONTROLm_field32_get(unit,
   3668             &rh_hgt_group_control_entry, FLOW_SET_SIZEf);
   3669     }
   3670     if (0 == flow_set_size) {
   3671         /* Resilient hashing is not enabled on this Higig trunk group.
   3672          * Nothing to do.
   3673          */
   3674         return BCM_E_NONE;
   3675     }
   3676 
   3677     /* Recover dynamic size */
   3678     BCM_IF_ERROR_RETURN
   3679         (_bcm_td2_hg_rh_dynamic_size_decode(unit, flow_set_size, &num_entries));
   3680     trunk_info->dynamic_size = num_entries;
   3681 
   3682     /* Recover PSC */
   3683     trunk_info->psc = BCM_TRUNK_PSC_DYNAMIC_RESILIENT;
   3684 
   3685     /* Recover Higig resilient hashing flow set block usage */
   3686 
   3687     if (soc_feature(unit, soc_feature_td3_style_dlb_rh)) {
   3688         SOC_IF_ERROR_RETURN(READ_HG_TRUNK_MODEm(unit, MEM_BLOCK_ANY,
   3689                 hgtid, &hg_trunk_mode_entry));
   3690         if (1 == soc_HG_TRUNK_MODEm_field32_get(unit,
   3691                           &hg_trunk_mode_entry, HG_TRUNK_LB_MODEf)) {
   3692             entry_base_ptr = soc_HG_TRUNK_GROUPm_field32_get(unit,
   3693                        &hg_trunk_group_entry, RH_FLOW_SET_BASEf);
   3694             block_base_ptr = entry_base_ptr >> 6;
   3695             num_blocks = num_entries >> 6;
   3696             _BCM_HG_RH_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr, num_blocks);
   3697         }
   3698     } else {
   3699         if (soc_HG_TRUNK_GROUPm_field32_get(unit, &hg_trunk_group_entry,
   3700                 ENHANCED_HASHING_ENABLEf)) {
   3701             entry_base_ptr = soc_RH_HGT_GROUP_CONTROLm_field32_get(unit,
   3702                  &rh_hgt_group_control_entry, FLOW_SET_BASEf);
   3703             block_base_ptr = entry_base_ptr >> 6;
   3704             num_blocks = num_entries >> 6;
   3705             _BCM_HG_RH_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr, num_blocks);
   3706         }
   3707     }
   3708     return BCM_E_NONE;
   3709 }
   3710 
   3711 /*
   3712  * Function:
   3713  *      bcm_td2_lag_rh_recover
   3714  * Purpose:
   3715  *      Recover LAG resilient hashing software state.
   3716  * Parameters:
   3717  *      unit - (IN) SOC unit number.
   3718  *      tid - (IN) Trunk group ID.
   3719  *      trunk_info - (OUT) Pointer to trunk info.
   3720  * Returns:
   3721  *      BCM_E_xxx
   3722  */
   3723 int
   3724 bcm_td2_lag_rh_recover(int unit, int tid, trunk_private_t *trunk_info)
   3725 {
   3726     trunk_group_entry_t trunk_group_entry;
   3727     int flow_set_size;
   3728     int entry_base_ptr;
   3729     int num_entries;
   3730     int block_base_ptr;
   3731     int num_blocks;
   3732     int members_any = 0;
   3733     uint32 rval;
   3734 
   3735     if (soc_feature(unit, soc_feature_td3_style_dlb_rh)) {
   3736         SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROL_2r(unit, &rval));
   3737         if (0 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROL_2r, rval,
   3738                 RH_DLB_SELECTIONf)) {
   3739            /* trunk resilient hashing is not enabled chip-wide. */
   3740             return BCM_E_NONE;
   3741         }
   3742     }
   3743 
   3744     /* A trunk group can be in one of 3 resilient hashing states:
   3745      * (1) RH not enabled: TRUNK_GROUP.RH_FLOW_SET_SIZE = 0.
   3746      * (2) RH enabled but without any members:
   3747      *     TRUNK_GROUP.RH_FLOW_SET_SIZE is non-zero,
   3748      *     TRUNK_GROUP.ENHANCED_HASHING_ENABLE = 0.
   3749      * (3) RH enabled with members:
   3750      *     TRUNK_GROUP.RH_FLOW_SET_SIZE is non-zero,
   3751      *     TRUNK_GROUP.ENHANCED_HASHING_ENABLE = 1.
   3752      */
   3753 
   3754     SOC_IF_ERROR_RETURN(READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY,
   3755                 tid, &trunk_group_entry));
   3756     flow_set_size = soc_TRUNK_GROUPm_field32_get(unit,
   3757             &trunk_group_entry, RH_FLOW_SET_SIZEf);
   3758     if (0 == flow_set_size) {
   3759         /* Resilient hashing is not enabled on this LAG.
   3760          * Nothing to do.
   3761          */
   3762         return BCM_E_NONE;
   3763     }
   3764 
   3765     /* Recover dynamic size */
   3766     BCM_IF_ERROR_RETURN
   3767         (_bcm_td2_lag_rh_dynamic_size_decode(unit, flow_set_size,
   3768                                              &num_entries));
   3769     trunk_info->dynamic_size = num_entries;
   3770 
   3771     /* Recover PSC */
   3772     trunk_info->psc = BCM_TRUNK_PSC_DYNAMIC_RESILIENT;
   3773 
   3774     if (soc_feature(unit, soc_feature_td3_style_dlb_rh)) {
   3775         if ((soc_TRUNK_GROUPm_field32_get(unit, &trunk_group_entry,
   3776                 TRUNK_MODEf) == 3)) {
   3777             members_any = 1;
   3778         }
   3779     } else {
   3780         members_any = soc_TRUNK_GROUPm_field32_get(unit, &trunk_group_entry,
   3781               ENHANCED_HASHING_ENABLEf);
   3782     }
   3783     if (members_any > 0) {
   3784         /* Recover LAG resilient hashing flow set block usage */
   3785         entry_base_ptr = soc_TRUNK_GROUPm_field32_get(unit,
   3786                 &trunk_group_entry, RH_FLOW_SET_BASEf);
   3787         block_base_ptr = entry_base_ptr >> 6;
   3788         num_blocks = num_entries >> 6;
   3789         _BCM_LAG_RH_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr, num_blocks);
   3790     }
   3791 
   3792     return BCM_E_NONE;
   3793 }
   3794 
   3795 #endif /* BCM_WARM_BOOT_SUPPORT */
   3796 
   3797 #ifndef BCM_SW_STATE_DUMP_DISABLE
   3798 
   3799 /*
   3800  * Function:
   3801  *     bcm_td2_hg_rh_sw_dump
   3802  * Purpose:
   3803  *     Displays Higig resilient hashing state maintained by software.
   3804  * Parameters:
   3805  *     unit - Device unit number
   3806  * Returns:
   3807  *     None
   3808  */
   3809 void bcm_td2_hg_rh_sw_dump(int unit)
   3810 {
   3811     int i, j;
   3812 
   3813     LOG_CLI((BSL_META_U(unit,
   3814                         "Higig Resilient Hashing Info -\n")));
   3815 
   3816     /* Print Higig RH flowset table usage */
   3817     LOG_CLI((BSL_META_U(unit,
   3818                         "    Higig RH Flowset Table Blocks Used:")));
   3819     j = 0;
   3820     for (i = 0; i < soc_mem_index_count(unit, RH_HGT_FLOWSETm) >> 6; i++) {
   3821         if (_BCM_HG_RH_FLOWSET_BLOCK_USED_GET(unit, i)) {
   3822             j++;
   3823             if (j % 15 == 1) {
   3824                 LOG_CLI((BSL_META_U(unit,
   3825                                     "\n     ")));
   3826             }
   3827             LOG_CLI((BSL_META_U(unit,
   3828                                 " %4d"), i));
   3829         }
   3830     }
   3831     LOG_CLI((BSL_META_U(unit,
   3832                         "\n")));
   3833 
   3834     return;
   3835 }
   3836 
   3837 /*
   3838  * Function:
   3839  *     bcm_td2_lag_rh_sw_dump
   3840  * Purpose:
   3841  *     Displays LAG resilient hashing state maintained by software.
   3842  * Parameters:
   3843  *     unit - Device unit number
   3844  * Returns:
   3845  *     None
   3846  */
   3847 void bcm_td2_lag_rh_sw_dump(int unit)
   3848 {
   3849     int i, j;
   3850 
   3851     LOG_CLI((BSL_META_U(unit,
   3852                         "LAG Resilient Hashing Info -\n")));
   3853     LOG_CLI((BSL_META_U(unit,
   3854                         "    LAG RH Flowset Table Blocks Total: %d\n"),
   3855              _td2_lag_rh_info[unit]->num_lag_rh_flowset_blocks));
   3856 
   3857     /* Print LAG RH flowset table usage */
   3858     LOG_CLI((BSL_META_U(unit,
   3859                         "    LAG RH Flowset Table Blocks Used:")));
   3860     j = 0;
   3861     for (i = 0; i < _td2_lag_rh_info[unit]->num_lag_rh_flowset_blocks; i++) {
   3862         if (_BCM_LAG_RH_FLOWSET_BLOCK_USED_GET(unit, i)) {
   3863             j++;
   3864             if (j % 15 == 1) {
   3865                 LOG_CLI((BSL_META_U(unit,
   3866                                     "\n     ")));
   3867             }
   3868             LOG_CLI((BSL_META_U(unit,
   3869                                 " %4d"), i));
   3870         }
   3871     }
   3872     LOG_CLI((BSL_META_U(unit,
   3873                         "\n")));
   3874 
   3875     return;
   3876 }
   3877 
   3878 #endif /* BCM_SW_STATE_DUMP_DISABLE */
   3879 
   3880 #ifdef INCLUDE_L3
   3881 
   3882 /*
   3883  * Function:
   3884  *      bcm_td2_vp_lag_deinit
   3885  * Purpose:
   3886  *      Deallocate internal data structures
   3887  * Parameters:
   3888  *      unit - (IN) SOC unit number.
   3889  * Returns:
   3890  *      BCM_E_xxx
   3891  */
   3892 void
   3893 bcm_td2_vp_lag_deinit(int unit)
   3894 {
   3895     if (_td2_vp_lag_info[unit]) {
   3896         if (_td2_vp_lag_info[unit]->vp_lag_used_bitmap) {
   3897             sal_free(_td2_vp_lag_info[unit]->vp_lag_used_bitmap);
   3898             _td2_vp_lag_info[unit]->vp_lag_used_bitmap = NULL;
   3899         }
   3900         if (_td2_vp_lag_info[unit]->vp_lag_egr_member_bitmap) {
   3901             sal_free(_td2_vp_lag_info[unit]->vp_lag_egr_member_bitmap);
   3902             _td2_vp_lag_info[unit]->vp_lag_egr_member_bitmap = NULL;
   3903         }
   3904         if (_td2_vp_lag_info[unit]->group_info) {
   3905             sal_free(_td2_vp_lag_info[unit]->group_info);
   3906             _td2_vp_lag_info[unit]->group_info = NULL;
   3907         }
   3908         /* Destroy protection mutex. */
   3909         if (_td2_vp_lag_info[unit]->lock) {
   3910             sal_mutex_destroy(_td2_vp_lag_info[unit]->lock);
   3911             _td2_vp_lag_info[unit]->lock = NULL;
   3912         }
   3913         sal_free(_td2_vp_lag_info[unit]);
   3914         _td2_vp_lag_info[unit] = NULL;
   3915     }
   3916 }
   3917 
   3918 /*
   3919  * Function:
   3920  *      bcm_td2_vp_lag_init
   3921  * Purpose:
   3922  *      Initialize internal data structures
   3923  * Parameters:
   3924  *      unit - (IN) SOC unit number.
   3925  * Returns:
   3926  *      BCM_E_xxx
   3927  */
   3928 int
   3929 bcm_td2_vp_lag_init(int unit)
   3930 {
   3931     int rv = BCM_E_NONE;
   3932     int egr_member_table_size;
   3933 
   3934     bcm_td2_vp_lag_deinit(unit);
   3935 
   3936     if (NULL == _td2_vp_lag_info[unit]) {
   3937         _td2_vp_lag_info[unit] = sal_alloc(sizeof(_td2_vp_lag_info_t),
   3938                 "VP LAG info");
   3939         if (NULL == _td2_vp_lag_info[unit]) {
   3940             bcm_td2_vp_lag_deinit(unit);
   3941             return BCM_E_MEMORY;
   3942         }
   3943     }
   3944     sal_memset(_td2_vp_lag_info[unit], 0, sizeof(_td2_vp_lag_info_t));
   3945 
   3946     /* Get maximum number of VP LAGs configured by user */
   3947     MAX_VP_LAGS(unit) = soc_property_get(unit, spn_MAX_VP_LAGS,
   3948             soc_mem_index_count(unit, EGR_VPLAG_GROUPm));
   3949     if (0 == MAX_VP_LAGS(unit)) {
   3950         /* User configured zero VP LAGS, nothing more to do. */
   3951         return BCM_E_NONE;
   3952     }
   3953 
   3954     /* Allocate a bitmap tracking which VP LAG IDs are used */
   3955     if (NULL == _td2_vp_lag_info[unit]->vp_lag_used_bitmap) {
   3956         _td2_vp_lag_info[unit]->vp_lag_used_bitmap =
   3957             sal_alloc(SHR_BITALLOCSIZE(MAX_VP_LAGS(unit)), "VP LAG used bitmap");
   3958         if (NULL == _td2_vp_lag_info[unit]->vp_lag_used_bitmap) {
   3959             bcm_td2_vp_lag_deinit(unit);
   3960             return BCM_E_MEMORY;
   3961         }
   3962     }
   3963     sal_memset(_td2_vp_lag_info[unit]->vp_lag_used_bitmap, 0,
   3964             SHR_BITALLOCSIZE(MAX_VP_LAGS(unit)));
   3965 
   3966     /* Allocate a bitmap tracking which EGR_VPLAG_MEMBER table entries are used */
   3967     egr_member_table_size = soc_mem_index_count(unit, EGR_VPLAG_MEMBERm);
   3968     if (NULL == _td2_vp_lag_info[unit]->vp_lag_egr_member_bitmap) {
   3969         _td2_vp_lag_info[unit]->vp_lag_egr_member_bitmap =
   3970             sal_alloc(SHR_BITALLOCSIZE(egr_member_table_size),
   3971                     "EGR_VPLAG_MEMBER table used bitmap");
   3972         if (NULL == _td2_vp_lag_info[unit]->vp_lag_egr_member_bitmap) {
   3973             bcm_td2_vp_lag_deinit(unit);
   3974             return BCM_E_MEMORY;
   3975         }
   3976     }
   3977     sal_memset(_td2_vp_lag_info[unit]->vp_lag_egr_member_bitmap, 0,
   3978             SHR_BITALLOCSIZE(egr_member_table_size));
   3979 
   3980 
   3981     /* Allocate an array containing info for each VP LAG */
   3982     if (NULL == _td2_vp_lag_info[unit]->group_info) {
   3983         _td2_vp_lag_info[unit]->group_info = sal_alloc
   3984             (MAX_VP_LAGS(unit) * sizeof(_td2_vp_lag_group_t),
   3985              "VP LAG group info array");
   3986         if (NULL == _td2_vp_lag_info[unit]->group_info) {
   3987             bcm_td2_vp_lag_deinit(unit);
   3988             return BCM_E_MEMORY;
   3989         }
   3990     }
   3991     sal_memset(_td2_vp_lag_info[unit]->group_info, 0,
   3992             MAX_VP_LAGS(unit) * sizeof(_td2_vp_lag_group_t));
   3993 
   3994 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   3995     /*
   3996      * In RioT flow, ECMP table is divided in half for overlay
   3997      * and underlay.
   3998      * first half is for overlay and second for underlay.
   3999      * All the vp_lag ECMP groups will fall in underlay.
   4000      * therefore, base_offset is added here to make sure
   4001      * that all the vp_lag groups go to underlay space.
   4002      */
   4003     if (soc_feature(unit, soc_feature_riot) ||
   4004         soc_feature(unit, soc_feature_multi_level_ecmp)) {
   4005         int ecmp_group_count = 0;
   4006         int l3_ecmp_level = soc_property_get(unit, spn_L3_ECMP_LEVELS, 1);
   4007         if (l3_ecmp_level > BCMI_L3_ECMP_SINGLE_LEVEL) {
   4008 #if defined(BCM_TRIDENT3_SUPPORT)
   4009             if (SOC_IS_TRIDENT3X(unit)) {
   4010                 int num_banks = 0;
   4011                 int l3_ecmp_group_first_lkup_mem_size = soc_property_get(unit, spn_L3_ECMP_GROUP_FIRST_LKUP_MEM_SIZE, 0);
   4012                 num_banks = l3_ecmp_group_first_lkup_mem_size / BCMI_L3_ECMP_GROUP_PER_BANK(unit) +
   4013                                          ((l3_ecmp_group_first_lkup_mem_size % BCMI_L3_ECMP_GROUP_PER_BANK(unit))?1:0);
   4014 
   4015                 _td2_vp_lag_info[unit]->base_ecmp_idx = num_banks * BCMI_L3_ECMP_GROUP_PER_BANK(unit);
   4016             }
   4017 
   4018             if (_td2_vp_lag_info[unit]->base_ecmp_idx == 0)
   4019 #endif
   4020             {
   4021                 if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) {
   4022                     ecmp_group_count = soc_mem_index_count(unit, L3_ECMP_COUNTm);
   4023                 }
   4024                 _td2_vp_lag_info[unit]->base_ecmp_idx = ecmp_group_count/2;
   4025             }
   4026         }
   4027     } else 
   4028 #endif
   4029     {
   4030         _td2_vp_lag_info[unit]->base_ecmp_idx = 0;
   4031     }
   4032 
   4033     /* Create protection mutex. */
   4034     if (NULL == _td2_vp_lag_info[unit]->lock) {
   4035         _td2_vp_lag_info[unit]->lock = sal_mutex_create("VP LAG mutex");
   4036     }
   4037     return rv;
   4038 }
   4039 
   4040 /*
   4041  * Function:
   4042  *	bcm_td2_vp_lag_info_get
   4043  * Purpose:
   4044  *      Get VP LAG info.
   4045  * Parameters:
   4046  *      unit  - SOC unit number
   4047  *      ngroups_vp_lag - (OUT) Number of VP LAGs
   4048  *      nports_vp_lag  - (OUT) Maximum number of VPs per VP LAG
   4049  * Returns:
   4050  *      BCM_E_xxx
   4051  */
   4052 int
   4053 bcm_td2_vp_lag_info_get(int unit, int *ngroups_vp_lag, int *nports_vp_lag)
   4054 {
   4055     VP_LAG_INIT_CHECK(unit);
   4056 
   4057     *ngroups_vp_lag = MAX_VP_LAGS(unit);
   4058     *nports_vp_lag = 1 << soc_mem_field_length(unit, EGR_VPLAG_GROUPm, COUNTf);
   4059 
   4060     return BCM_E_NONE;
   4061 }
   4062 
   4063 /*
   4064  * Function:
   4065  *	_bcm_td2_tid_to_vp_lag_id
   4066  * Purpose:
   4067  *      Convert trunk ID to VP LAG ID.
   4068  * Parameters:
   4069  *      unit  - SOC unit number
   4070  *      tid   - Trunk ID
   4071  *      vp_lag_id - (OUT) VP LAG ID
   4072  * Returns:
   4073  *      BCM_E_xxx
   4074  */
   4075 STATIC int
   4076 _bcm_td2_tid_to_vp_lag_id(int unit, bcm_trunk_t tid, int *vp_lag_id)
   4077 {
   4078     int vp_id_min = -1, vp_id_max = -1;
   4079 
   4080     if (tid < 0) {
   4081         return BCM_E_PARAM;
   4082     }
   4083 
   4084     BCM_IF_ERROR_RETURN(
   4085         _bcm_esw_trunk_chip_info_vp_resource_get(unit, &vp_id_min,
   4086                                                  &vp_id_max, NULL));
   4087 
   4088     if (tid >= vp_id_min && tid <= vp_id_max) {
   4089         *vp_lag_id = tid - vp_id_min;
   4090     } else {
   4091         return BCM_E_PARAM;
   4092     }
   4093 
   4094     return BCM_E_NONE;
   4095 }
   4096 
   4097 /*
   4098  * Function:
   4099  *	bcm_td2_vp_lag_create
   4100  * Purpose:
   4101  *      Create a VP LAG.
   4102  * Parameters:
   4103  *      unit  - SOC unit number
   4104  *      flags - Flags
   4105  *      tid   - (IN/OUT) Trunk ID
   4106  * Returns:
   4107  *      BCM_E_xxx
   4108  */
   4109 int
   4110 bcm_td2_vp_lag_create(int unit, uint32 flags, bcm_trunk_t *tid,
   4111                       bcm_gport_t *vplag_port_id)
   4112 {
   4113     int rv = BCM_E_NONE;
   4114     int vp_lag_id = 0;
   4115     int i;
   4116     int vp;
   4117     int vp_alloc_mode = 0;
   4118     egr_vplag_group_entry_t egr_vplag_group_entry;
   4119     ecmp_count_entry_t l3_ecmp_count_entry;
   4120     initial_l3_ecmp_group_entry_t initial_l3_ecmp_group_entry;
   4121     ing_dvp_2_table_entry_t ing_dvp_2_entry;
   4122     ing_dvp_table_entry_t ing_dvp_entry;
   4123     source_vp_entry_t svp_entry;
   4124     int cml_default_enable = 0, cml_default_new = 0, cml_default_move = 0;
   4125     int vp_id_min = -1;
   4126     _bcm_vp_info_t vp_info;
   4127 
   4128     int ecmp_idx = 0;
   4129     VP_LAG_INIT_CHECK(unit);
   4130 
   4131     if (MAX_VP_LAGS(unit) == 0) {
   4132         return BCM_E_FULL;
   4133     }
   4134 
   4135     if (flags & BCM_TRUNK_FLAG_WITH_ID) {
   4136         BCM_IF_ERROR_RETURN(_bcm_td2_tid_to_vp_lag_id(unit, *tid, &vp_lag_id)); 
   4137         if (soc_feature(unit, soc_feature_reserve_vp_lag_resource_index_zero) &&
   4138             (0 == vp_lag_id)) {
   4139             /*
   4140              * EGR_VPLAG_GROUP 0 is reserved for passing LAG resolution
   4141              * of DVP 0.
   4142              */
   4143             return BCM_E_PARAM;
   4144         }
   4145         if (VP_LAG_USED_GET(unit, vp_lag_id)) {
   4146             return BCM_E_EXISTS;
   4147         }
   4148         VP_LAG_USED_SET(unit, vp_lag_id);
   4149     } else if (flags & BCM_TRUNK_FLAG_VP) {
   4150         if (soc_feature(unit, soc_feature_reserve_vp_lag_resource_index_zero)) {
   4151             /*
   4152              * EGR_VPLAG_GROUP 0 is reserved for passing LAG resolution
   4153              * of DVP 0.
   4154              */
   4155             i = 1;
   4156         } else {
   4157             i = 0;
   4158         }
   4159         for (; i < MAX_VP_LAGS(unit); i++) {
   4160             if (!VP_LAG_USED_GET(unit, i)) {
   4161                 vp_lag_id = i;
   4162                 VP_LAG_USED_SET(unit, i);
   4163                 break;
   4164             }
   4165         }
   4166         if (i == MAX_VP_LAGS(unit)) {
   4167             return BCM_E_FULL;
   4168         }
   4169     } else {
   4170         return BCM_E_PARAM;
   4171     }
   4172 
   4173     /* In Trident2, VP LAGs and VPs share the same namespace.
   4174      * A VP value needs to be allocated to represent a VP LAG, and this
   4175      * VP value is not available to be used as a VP.
   4176      */
   4177     vp_alloc_mode = soc_property_get(unit, spn_VPLAG_VP_ALLOC_MODE, 0);
   4178     _bcm_vp_info_init(&vp_info);
   4179     vp_info.vp_type = _bcmVpTypeVpLag;
   4180     if ((flags & BCM_TRUNK_FLAG_WITH_VPLAG_ID) && (vplag_port_id != NULL)) {
   4181         /* Cannot have both - vp allocation from bottom of SVP table and
   4182          * also use the vp Id passed at same time */
   4183         if (vp_alloc_mode) {
   4184             return BCM_E_PARAM;
   4185         }
   4186         vp = BCM_GPORT_VPLAG_PORT_ID_GET(*vplag_port_id);
   4187         rv = _bcm_vp_alloc(unit, vp, vp, 1, SOURCE_VPm, vp_info, &vp);
   4188     } else {
   4189         if (vp_alloc_mode) {
   4190             rv = _bcm_vp_alloc(unit, soc_mem_index_count(unit, SOURCE_VPm)-1,
   4191                                0, 1, SOURCE_VPm, vp_info, &vp);
   4192             } else {
   4193             rv = _bcm_vp_alloc(unit, 0, soc_mem_index_count(unit, SOURCE_VPm)-1,
   4194                                1, SOURCE_VPm, vp_info, &vp);
   4195             }
   4196     }
   4197     if (BCM_FAILURE(rv)) {
   4198         VP_LAG_USED_CLR(unit, vp_lag_id);
   4199         return rv;
   4200     }
   4201     if (vplag_port_id != NULL) {
   4202         BCM_GPORT_VPLAG_PORT_ID_SET(*vplag_port_id, vp);
   4203     }
   4204     VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id = vp;
   4205 
   4206     /* Configure SVP table */
   4207     sal_memset(&svp_entry, 0, sizeof(source_vp_entry_t));
   4208     /* Set the CML */
   4209     rv = _bcm_vp_default_cml_mode_get(unit, &cml_default_enable,
   4210                                       &cml_default_new, &cml_default_move);
   4211     if (BCM_FAILURE(rv)) {
   4212         VP_LAG_USED_CLR(unit, vp_lag_id);
   4213         (void) _bcm_vp_free(unit, _bcmVpTypeVpLag, 1, vp);
   4214         return rv;
   4215     }
   4216     if (cml_default_enable) {
   4217         /* Set the CML to default values */
   4218         soc_SOURCE_VPm_field32_set(unit, &svp_entry, CML_FLAGS_NEWf,
   4219                                    cml_default_new);
   4220         soc_SOURCE_VPm_field32_set(unit, &svp_entry, CML_FLAGS_MOVEf,
   4221                                    cml_default_move);
   4222     } else {
   4223         /* Set the CML to PVP_CML_SWITCH by default (hw learn and forward) */
   4224         soc_SOURCE_VPm_field32_set(unit, &svp_entry, CML_FLAGS_NEWf, 0x8);
   4225         soc_SOURCE_VPm_field32_set(unit, &svp_entry, CML_FLAGS_MOVEf, 0x8);
   4226     }
   4227     rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp_entry);
   4228     if (BCM_FAILURE(rv)) {
   4229         VP_LAG_USED_CLR(unit, vp_lag_id);
   4230         (void) _bcm_vp_free(unit, _bcmVpTypeVpLag, 1, vp);
   4231         return rv;
   4232     }
   4233 
   4234     /* Trident2 supports up to 256 VP LAGs that are capable of performing
   4235      * both unicast and multicast VP LAG resolution. Trident2 supports an
   4236      * additional 768 VP LAGs that are capable of performing only unicast
   4237      * VP LAG resolution. The VP LAG tables responsible for multicast
   4238      * resolution are located in the egress pipeline; these tables
   4239      * should be configured only for VP LAGs < 256. The VP LAGs tables
   4240      * responsible for unicast resolution are located in the ingress
   4241      * pipeline; these tables should be configured for all VP LAGs.
   4242      */
   4243 
   4244     /* Configure EGR_VP_LAG_GROUP entry. Set base pointer and count
   4245      * fields to all ones, indicating no members.
   4246      */
   4247     if (vp_lag_id < soc_mem_index_count(unit, EGR_VPLAG_GROUPm)) {
   4248         SOC_IF_ERROR_RETURN(READ_EGR_VPLAG_GROUPm(unit, MEM_BLOCK_ANY, vp_lag_id,
   4249                     &egr_vplag_group_entry));
   4250         soc_EGR_VPLAG_GROUPm_field32_set(unit, &egr_vplag_group_entry,
   4251                 DVP_LAG_IDf, vp);
   4252         soc_EGR_VPLAG_GROUPm_field32_set(unit, &egr_vplag_group_entry, BASE_PTRf,
   4253                 (1 << soc_mem_field_length(unit, EGR_VPLAG_GROUPm, BASE_PTRf)) - 1);
   4254         soc_EGR_VPLAG_GROUPm_field32_set(unit, &egr_vplag_group_entry, COUNTf,
   4255                 (1 << soc_mem_field_length(unit, EGR_VPLAG_GROUPm, COUNTf)) - 1);
   4256         rv = WRITE_EGR_VPLAG_GROUPm(unit, MEM_BLOCK_ALL, vp_lag_id,
   4257                 &egr_vplag_group_entry);
   4258         if (BCM_FAILURE(rv)) {
   4259             VP_LAG_USED_CLR(unit, vp_lag_id);
   4260             (void) _bcm_vp_free(unit, _bcmVpTypeVpLag, 1, vp);
   4261             return rv;
   4262         }
   4263     }
   4264 
   4265     /* Set base pointer and count fields in L3_ECMP_COUNT
   4266      * to all ones, to indicate there are no members in this VP LAG.
   4267      */
   4268     ecmp_idx = _td2_vp_lag_info[unit]->base_ecmp_idx + vp_lag_id; 
   4269     SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_idx,
   4270                 &l3_ecmp_count_entry));
   4271     soc_L3_ECMP_COUNTm_field32_set(unit, &l3_ecmp_count_entry, BASE_PTRf,
   4272             (1 << soc_mem_field_length(unit, L3_ECMP_COUNTm, BASE_PTRf)) - 1);
   4273     soc_L3_ECMP_COUNTm_field32_set(unit, &l3_ecmp_count_entry, COUNTf,
   4274             (1 << soc_mem_field_length(unit, L3_ECMP_COUNTm, COUNTf)) - 1);
   4275     rv = WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL, ecmp_idx,
   4276             &l3_ecmp_count_entry);
   4277     if (BCM_FAILURE(rv)) {
   4278         VP_LAG_USED_CLR(unit, vp_lag_id);
   4279         (void) _bcm_vp_free(unit, _bcmVpTypeVpLag, 1, vp);
   4280         return rv;
   4281     }
   4282 
   4283     /* Set base pointer and count fields in INITIAL_L3_ECMP_GROUP
   4284      * to all ones, to indicate there are no members in this VP LAG.
   4285      */
   4286     SOC_IF_ERROR_RETURN(READ_INITIAL_L3_ECMP_GROUPm(unit, MEM_BLOCK_ANY,
   4287                 ecmp_idx, &initial_l3_ecmp_group_entry));
   4288     soc_INITIAL_L3_ECMP_GROUPm_field32_set(unit, &initial_l3_ecmp_group_entry,
   4289             BASE_PTRf, (1 << soc_mem_field_length(unit, INITIAL_L3_ECMP_GROUPm,
   4290                     BASE_PTRf)) - 1);
   4291     soc_INITIAL_L3_ECMP_GROUPm_field32_set(unit, &initial_l3_ecmp_group_entry,
   4292             COUNTf, (1 << soc_mem_field_length(unit, INITIAL_L3_ECMP_GROUPm,
   4293                     COUNTf)) - 1);
   4294     rv = WRITE_INITIAL_L3_ECMP_GROUPm(unit, MEM_BLOCK_ALL,
   4295             ecmp_idx, &initial_l3_ecmp_group_entry);
   4296     if (BCM_FAILURE(rv)) {
   4297         VP_LAG_USED_CLR(unit, vp_lag_id);
   4298         (void) _bcm_vp_free(unit, _bcmVpTypeVpLag, 1, vp);
   4299         return rv;
   4300     }
   4301 
   4302     /* Configure ING_DVP_2_TABLE */
   4303     SOC_IF_ERROR_RETURN(READ_ING_DVP_2_TABLEm(unit, MEM_BLOCK_ANY, vp,
   4304                 &ing_dvp_2_entry));
   4305     soc_ING_DVP_2_TABLEm_field32_set(unit, &ing_dvp_2_entry,
   4306             ENABLE_VPLAG_RESOLUTIONf, 1);
   4307     soc_ING_DVP_2_TABLEm_field32_set(unit, &ing_dvp_2_entry,
   4308             DVP_GROUP_PTRf, ecmp_idx);
   4309     rv = WRITE_ING_DVP_2_TABLEm(unit, MEM_BLOCK_ALL, vp, &ing_dvp_2_entry);
   4310     if (BCM_FAILURE(rv)) {
   4311         VP_LAG_USED_CLR(unit, vp_lag_id);
   4312         (void) _bcm_vp_free(unit, _bcmVpTypeVpLag, 1, vp);
   4313         return rv;
   4314     }
   4315 
   4316     /* Configure ING_DVP_TABLE */
   4317     SOC_IF_ERROR_RETURN(READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp,
   4318                 &ing_dvp_entry));
   4319     soc_ING_DVP_TABLEm_field32_set(unit, &ing_dvp_entry,
   4320             ENABLE_VPLAG_RESOLUTIONf, 1);
   4321     soc_ING_DVP_TABLEm_field32_set(unit, &ing_dvp_entry,
   4322             DVP_GROUP_PTRf, ecmp_idx);
   4323     rv = WRITE_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp, &ing_dvp_entry);
   4324     if (BCM_FAILURE(rv)) {
   4325         VP_LAG_USED_CLR(unit, vp_lag_id);
   4326         (void) _bcm_vp_free(unit, _bcmVpTypeVpLag, 1, vp);
   4327         return rv;
   4328     }
   4329 
   4330     /* Convert VP LAG ID to trunk ID */
   4331     BCM_IF_ERROR_RETURN(
   4332         _bcm_esw_trunk_chip_info_vp_resource_get(unit, &vp_id_min,
   4333                                                  NULL, NULL));
   4334     *tid = vp_lag_id + vp_id_min;
   4335 
   4336     return BCM_E_NONE;
   4337 }
   4338 
   4339 /*
   4340  * Function:
   4341  *	_bcm_td2_vp_lag_member_ingress_set
   4342  * Purpose:
   4343  *      Set members of a VP LAG in ingress pipeline.
   4344  * Parameters:
   4345  *      unit - SOC unit number.
   4346  *      vp_lag_id - VP LAG ID.
   4347  *      trunk_info - Information on the trunk group.
   4348  *      vp_count - Number of VPs.
   4349  *      vp_array - Array of VPs.
   4350  * Returns:
   4351  *      BCM_E_XXX
   4352  */
   4353 STATIC int
   4354 _bcm_td2_vp_lag_member_ingress_set(int unit, int vp_lag_id,
   4355         bcm_trunk_info_t *trunk_info, int vp_count, int *vp_array)
   4356 {
   4357     _bcm_l3_tbl_op_t tbl_op_data;
   4358     int base_ptr;
   4359     int i;
   4360     ing_dvp_table_entry_t ing_dvp_entry;
   4361     int next_hop_index;
   4362     ecmp_entry_t l3_ecmp_entry;
   4363     initial_l3_ecmp_entry_t initial_l3_ecmp_entry;
   4364     ecmp_count_entry_t l3_ecmp_count_entry;
   4365     int old_base_ptr, old_vp_count;
   4366     initial_l3_ecmp_group_entry_t initial_l3_ecmp_group_entry;
   4367     int ecmp_idx = 0;
   4368 #if defined(BCM_TOMAHAWK_SUPPORT)
   4369     int ecmp_flag = 0;
   4370     int hi_ecmp_mode = 0;
   4371     int ecmp_ptr = -1;
   4372 #endif
   4373     int vp_type = 0, lag_vp = 0;
   4374     ing_dvp_table_entry_t lag_ing_dvp_entry;
   4375     ing_dvp_2_table_entry_t lag_ing_dvp_2_entry;
   4376     int rv = BCM_E_NONE;
   4377 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
   4378 #if defined(BCM_TRIDENT3_SUPPORT)
   4379     uint8 protected_ecmp = 0;
   4380     uint32 alloc_sz = 0;
   4381     soc_esw_ecmp_group_info_t grp_info = {0};
   4382     soc_esw_ecmp_member_info_t *mem_array = NULL;
   4383 #endif /* BCM_TRIDENT3_SUPPORT */
   4384 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
   4385 
   4386     /* Find a contiguous region of L3_ECMP table that's large
   4387      * enough to hold all of the members.
   4388      */
   4389     sal_memset(&tbl_op_data, 0, sizeof(_bcm_l3_tbl_op_t));
   4390     tbl_op_data.width = vp_count;
   4391     tbl_op_data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 
   4392     tbl_op_data.oper_flags = _BCM_L3_SHR_TABLE_TRAVERSE_CONTROL; 
   4393     tbl_op_data.entry_index = -1;
   4394 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
   4395 #if defined(BCM_TRIDENT3_SUPPORT)
   4396     if (soc_esw_ecmp_protected_enabled(unit)) {
   4397         protected_ecmp = 1;
   4398         SOC_ESW_ECMP_LOCK(unit);
   4399         rv = bcm_td3x_l3_ecmp_free_idx_get(unit,
   4400                                            socEswEcmpBankLkupLevelUnderlay,
   4401                                            vp_count,
   4402                                            &tbl_op_data.entry_index);
   4403         if (BCM_FAILURE(rv)) {
   4404             goto exit;
   4405         }
   4406 
   4407         alloc_sz = (vp_count * sizeof(soc_esw_ecmp_member_info_t));
   4408         mem_array = sal_alloc(alloc_sz, "NH array");
   4409         if (NULL == mem_array) {
   4410             rv = BCM_E_MEMORY;
   4411             goto exit;
   4412         }
   4413         sal_memset(mem_array, 0, alloc_sz);
   4414     } else
   4415 #endif /* BCM_TRIDENT3_SUPPORT */
   4416 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
   4417     {
   4418         rv = _bcm_xgs3_tbl_free_idx_get(unit, &tbl_op_data);
   4419         if (BCM_FAILURE(rv)) {
   4420             goto exit;
   4421         }
   4422     }
   4423     base_ptr = tbl_op_data.entry_index;
   4424     BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_op_data.tbl_ptr, base_ptr, vp_count);
   4425 
   4426     /* Write members to L3_ECMP and INITIAL_L3_ECMP tables */
   4427     for (i = 0; i < vp_count; i++) {
   4428         /* Get VP's next hop index */
   4429         rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY,
   4430                                  vp_array[i], &ing_dvp_entry);
   4431         if (BCM_FAILURE(rv)) {
   4432             goto exit;
   4433         }
   4434         next_hop_index = soc_ING_DVP_TABLEm_field32_get(unit, &ing_dvp_entry,
   4435                 NEXT_HOP_INDEXf);
   4436 #if defined(BCM_TOMAHAWK_SUPPORT)
   4437         if (soc_feature(unit, soc_feature_hierarchical_ecmp) &&
   4438             (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
   4439                                           ecmp_mode_hierarchical)) {
   4440             hi_ecmp_mode = 0;
   4441             ecmp_flag = soc_ING_DVP_TABLEm_field32_get(unit, &ing_dvp_entry,
   4442                                                        ECMPf);
   4443             if (ecmp_flag) {
   4444                 _bcm_l3_tbl_t *tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
   4445                 ecmp_ptr = soc_ING_DVP_TABLEm_field32_get(unit, &ing_dvp_entry,
   4446                                                           ECMP_PTRf);
   4447                 if (!BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp),
   4448                                              ecmp_ptr)) {
   4449                     rv = BCM_E_NOT_FOUND;
   4450                     goto exit;
   4451                 }
   4452                 if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, ecmp_ptr,
   4453                                                         BCM_L3_ECMP_OVERLAY)) {
   4454                     rv = BCM_E_PARAM;
   4455                     goto exit;
   4456                 }
   4457                 if (ecmp_ptr < (tbl_ptr->idx_max/2 + 1)) {
   4458                     rv = BCM_E_PARAM;
   4459                     goto exit;
   4460                 }
   4461                 hi_ecmp_mode = 1;
   4462                 next_hop_index = ecmp_ptr;
   4463             }
   4464         }
   4465 #endif
   4466 
   4467         if (i == 0 && (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeVxlan) ||
   4468             _bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeL2Gre) ||
   4469             _bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeFlow))) {
   4470             vp_type = soc_ING_DVP_TABLEm_field32_get(unit, &ing_dvp_entry,
   4471                                                      VP_TYPEf);
   4472             lag_vp = VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id;
   4473 
   4474             /* For Vxlan VP lag, inherit VP_TYPE from member, ortherwise DVP
   4475              * cann't be passed to EPIPE. Assumed that all members has the same
   4476              * vp_type.
   4477              */
   4478             rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY,
   4479                                      lag_vp, &lag_ing_dvp_entry);
   4480             if (BCM_FAILURE(rv)) {
   4481                 goto exit;
   4482             }
   4483             soc_ING_DVP_TABLEm_field32_set(unit, &lag_ing_dvp_entry,
   4484                                            VP_TYPEf, vp_type);
   4485             rv = WRITE_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL,
   4486                                       lag_vp, &lag_ing_dvp_entry);
   4487             if (BCM_FAILURE(rv)) {
   4488                 goto exit;
   4489             }
   4490             rv = READ_ING_DVP_2_TABLEm(unit, MEM_BLOCK_ANY,
   4491                                        lag_vp, &lag_ing_dvp_2_entry);
   4492             if (BCM_FAILURE(rv)) {
   4493                 goto exit;
   4494             }
   4495             soc_ING_DVP_2_TABLEm_field32_set(unit, &lag_ing_dvp_2_entry,
   4496                                              VP_TYPEf, vp_type);
   4497             rv = WRITE_ING_DVP_2_TABLEm(unit, MEM_BLOCK_ALL,
   4498                                         lag_vp, &lag_ing_dvp_2_entry);
   4499             if (BCM_FAILURE(rv)) {
   4500                 goto exit;
   4501             }
   4502         }
   4503 
   4504 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
   4505 #if defined(BCM_TRIDENT3_SUPPORT)
   4506         if (protected_ecmp == 1) {
   4507             mem_array[i].nh = next_hop_index;
   4508             mem_array[i].dvp = vp_array[i];
   4509         } else
   4510 #endif /* BCM_TRIDENT3_SUPPORT */
   4511 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
   4512         {
   4513             /* Write L3_ECMP table */
   4514             sal_memset(&l3_ecmp_entry, 0, sizeof(l3_ecmp_entry));
   4515             soc_L3_ECMPm_field32_set(unit, &l3_ecmp_entry, DVPf,
   4516                                      vp_array[i]);
   4517             if (soc_feature(unit, soc_feature_generic_dest)) {
   4518 #if defined(BCM_TOMAHAWK_SUPPORT)
   4519                 if (hi_ecmp_mode) {
   4520                     soc_mem_field32_dest_set(unit, L3_ECMPm, &l3_ecmp_entry, DESTINATIONf,
   4521                                              SOC_MEM_FIF_DEST_ECMP, next_hop_index);
   4522                 } else {
   4523                     soc_mem_field32_dest_set(unit, L3_ECMPm, &l3_ecmp_entry, DESTINATIONf,
   4524                                              SOC_MEM_FIF_DEST_NEXTHOP, next_hop_index);
   4525                 }
   4526 #endif
   4527             } else {
   4528                 soc_L3_ECMPm_field32_set(unit, &l3_ecmp_entry, NEXT_HOP_INDEXf,
   4529                                          next_hop_index);
   4530 #if defined(BCM_TOMAHAWK_SUPPORT)
   4531                 if (hi_ecmp_mode) {
   4532                     soc_L3_ECMPm_field32_set(unit, &l3_ecmp_entry, ECMP_FLAGf, 1);
   4533                 }
   4534 #endif
   4535             }
   4536             rv = WRITE_L3_ECMPm(unit, MEM_BLOCK_ALL,
   4537                                 base_ptr + i, &l3_ecmp_entry);
   4538             if (BCM_FAILURE(rv)) {
   4539                 goto exit;
   4540             }
   4541 
   4542             /* Write INITIAL_L3_ECMP table */
   4543             if (soc_feature(unit, soc_feature_generic_dest)) {
   4544                 sal_memset(&initial_l3_ecmp_entry, 0, sizeof(initial_l3_ecmp_entry));
   4545 #if defined(BCM_TOMAHAWK_SUPPORT)
   4546                 if (hi_ecmp_mode) {
   4547                     soc_mem_field32_dest_set(unit, INITIAL_L3_ECMPm, &initial_l3_ecmp_entry, DESTINATIONf,
   4548                                              SOC_MEM_FIF_DEST_ECMP, next_hop_index);
   4549                 } else {
   4550                     soc_mem_field32_dest_set(unit, INITIAL_L3_ECMPm, &initial_l3_ecmp_entry, DESTINATIONf,
   4551                                              SOC_MEM_FIF_DEST_NEXTHOP, next_hop_index);
   4552                 }
   4553 #endif
   4554             } else {
   4555                 sal_memset(&initial_l3_ecmp_entry, 0, sizeof(initial_l3_ecmp_entry));
   4556                 soc_INITIAL_L3_ECMPm_field32_set(unit, &initial_l3_ecmp_entry,
   4557                                                  NEXT_HOP_INDEXf, next_hop_index);
   4558 #if defined(BCM_TOMAHAWK_SUPPORT)
   4559                 if (hi_ecmp_mode) {
   4560                     soc_INITIAL_L3_ECMPm_field32_set(unit, &initial_l3_ecmp_entry,
   4561                                                      ECMP_FLAGf, 1);
   4562                 }
   4563 #endif
   4564             }
   4565             rv = WRITE_INITIAL_L3_ECMPm(unit, MEM_BLOCK_ALL,
   4566                                         base_ptr + i, &initial_l3_ecmp_entry);
   4567             if (BCM_FAILURE(rv)) {
   4568                 goto exit;
   4569             }
   4570         }
   4571     }
   4572 
   4573     ecmp_idx = _td2_vp_lag_info[unit]->base_ecmp_idx + vp_lag_id; 
   4574 
   4575 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
   4576 #if defined(BCM_TRIDENT3_SUPPORT)
   4577     if (protected_ecmp == 1) {
   4578         grp_info.ecmp_grp = ecmp_idx;
   4579         grp_info.ecmp_member_base = base_ptr;
   4580         grp_info.max_paths = vp_count;
   4581         grp_info.vp_lag = 1;
   4582         rv = soc_esw_ecmp_protected_grp_add(unit, &grp_info, mem_array);
   4583         if (BCM_FAILURE(rv)) {
   4584             BCM_XGS3_L3_ENT_REF_CNT_DEC(tbl_op_data.tbl_ptr, base_ptr, vp_count);
   4585             goto exit;
   4586         }
   4587         sal_free(mem_array);
   4588         mem_array = NULL;
   4589         if (base_ptr != grp_info.ecmp_member_base) {
   4590             BCM_XGS3_L3_ENT_REF_CNT_DEC(tbl_op_data.tbl_ptr, base_ptr, vp_count);
   4591             base_ptr = grp_info.ecmp_member_base;
   4592             BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_op_data.tbl_ptr, base_ptr, vp_count);
   4593         }
   4594     }
   4595 #endif /* BCM_TRIDENT3_SUPPORT */
   4596 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
   4597 
   4598     /* Write base pointer and counter to L3_ECMP_COUNT table */
   4599     rv = READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_idx,
   4600                              &l3_ecmp_count_entry);
   4601     if (BCM_FAILURE(rv)) {
   4602         goto exit;
   4603     }
   4604     old_base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit,
   4605             &l3_ecmp_count_entry, BASE_PTRf);
   4606     old_vp_count = 1 + soc_L3_ECMP_COUNTm_field32_get(unit,
   4607             &l3_ecmp_count_entry, COUNTf);
   4608     soc_L3_ECMP_COUNTm_field32_set(unit, &l3_ecmp_count_entry, BASE_PTRf,
   4609             base_ptr);
   4610     soc_L3_ECMP_COUNTm_field32_set(unit, &l3_ecmp_count_entry, COUNTf,
   4611             vp_count - 1);
   4612     rv = WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL, ecmp_idx,
   4613                               &l3_ecmp_count_entry);
   4614     if (BCM_FAILURE(rv)) {
   4615         goto exit;
   4616     }
   4617 
   4618     /* Write base pointer and counter to INITIAL_L3_ECMP_GROUP table */
   4619     rv = READ_INITIAL_L3_ECMP_GROUPm(unit, MEM_BLOCK_ANY,
   4620                                      ecmp_idx, &initial_l3_ecmp_group_entry);
   4621     if (BCM_FAILURE(rv)) {
   4622         goto exit;
   4623     }
   4624     soc_INITIAL_L3_ECMP_GROUPm_field32_set(unit, &initial_l3_ecmp_group_entry,
   4625             BASE_PTRf, base_ptr);
   4626     soc_INITIAL_L3_ECMP_GROUPm_field32_set(unit, &initial_l3_ecmp_group_entry,
   4627             COUNTf, vp_count - 1);
   4628     rv = WRITE_INITIAL_L3_ECMP_GROUPm(unit, MEM_BLOCK_ALL,
   4629                 ecmp_idx, &initial_l3_ecmp_group_entry);
   4630     if (BCM_FAILURE(rv)) {
   4631         goto exit;
   4632     }
   4633 
   4634     /* If VP LAG had members, free old entries in L3_ECMP and
   4635      * INITIAL_L3_ECMP tables. 
   4636      */
   4637     if (VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member) {
   4638         BCM_XGS3_L3_ENT_REF_CNT_DEC(tbl_op_data.tbl_ptr, old_base_ptr,
   4639                 old_vp_count);
   4640     }
   4641 
   4642 exit:
   4643 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
   4644 #if defined(BCM_TRIDENT3_SUPPORT)
   4645     if (soc_esw_ecmp_protected_enabled(unit)) {
   4646         if (mem_array != NULL) {
   4647             sal_free(mem_array);
   4648         }
   4649         SOC_ESW_ECMP_UNLOCK(unit);
   4650     }
   4651 #endif
   4652 #endif
   4653     return rv;
   4654 }
   4655 
   4656 /*
   4657  * Function:
   4658  *	_bcm_td2_vp_lag_member_egress_set
   4659  * Purpose:
   4660  *      Set members of a VP LAG in egress pipeline.
   4661  * Parameters:
   4662  *      unit - SOC unit number.
   4663  *      vp_lag_id - VP LAG ID.
   4664  *      trunk_info - Information on the trunk group.
   4665  *      vp_count - Number of VPs.
   4666  *      vp_array - Array of VPs.
   4667  * Returns:
   4668  *      BCM_E_XXX
   4669  */
   4670 STATIC int
   4671 _bcm_td2_vp_lag_member_egress_set(int unit, int vp_lag_id,
   4672         bcm_trunk_info_t *trunk_info, int vp_count, int *vp_array)
   4673 {
   4674     int num_entries;
   4675     int max_base_ptr, base_ptr;
   4676     SHR_BITDCL occupied;
   4677     int i;
   4678     egr_vplag_member_entry_t egr_member_entry;
   4679     egr_vplag_group_entry_t egr_vplag_group_entry;
   4680     egr_dvp_attribute_entry_t egr_dvp_attr_entry;
   4681     int old_base_ptr, old_num_entries;
   4682 
   4683     if (trunk_info->dlf_index != BCM_TRUNK_UNSPEC_INDEX) {
   4684         /* Only one member of the VP LAG is eligible to receive non-unicast 
   4685          * traffic.
   4686          */
   4687         if (trunk_info->dlf_index >= vp_count) {
   4688             return BCM_E_PARAM;
   4689         }
   4690         num_entries = 1;
   4691     } else {
   4692         num_entries = vp_count;
   4693     }
   4694 
   4695     /* Find a contiguous region of EGR_VPLAG_MEMBER table that's large
   4696      * enough to hold all of the members.
   4697      */
   4698     max_base_ptr = soc_mem_index_count(unit, EGR_VPLAG_MEMBERm) - num_entries;
   4699     if (soc_feature(unit, soc_feature_reserve_vp_lag_resource_index_zero)) {
   4700         /*
   4701          * EGR_VPLAG_MEMBER 0 is reserved for passing LAG resolution
   4702          * of DVP 0.
   4703          */
   4704         base_ptr = 1;
   4705     } else {
   4706         base_ptr = 0;
   4707     }
   4708     for (; base_ptr <= max_base_ptr; base_ptr++) {
   4709         /* Check if the contiguous region from base_ptr to
   4710          * (base_ptr + num_entries - 1) is free. 
   4711          */
   4712         VP_LAG_EGR_MEMBER_TEST_RANGE(unit, base_ptr, num_entries, occupied); 
   4713         if (!occupied) {
   4714             break;
   4715         }
   4716     }
   4717     if (base_ptr > max_base_ptr) {
   4718         /* A contiguous region of the desired size could not be found. */
   4719         return BCM_E_RESOURCE;
   4720     }
   4721 
   4722     /* Write members to EGR_VPLAG_MEMBER table */
   4723     for (i = 0; i < num_entries; i++) {
   4724         sal_memset(&egr_member_entry, 0, sizeof(egr_member_entry));
   4725         if (trunk_info->dlf_index != BCM_TRUNK_UNSPEC_INDEX) {
   4726             soc_EGR_VPLAG_MEMBERm_field32_set(unit, &egr_member_entry, DVPf,
   4727                     vp_array[trunk_info->dlf_index]);
   4728         } else {
   4729             soc_EGR_VPLAG_MEMBERm_field32_set(unit, &egr_member_entry, DVPf,
   4730                     vp_array[i]);
   4731         }
   4732         SOC_IF_ERROR_RETURN(WRITE_EGR_VPLAG_MEMBERm(unit, MEM_BLOCK_ALL,
   4733                     base_ptr + i, &egr_member_entry)); 
   4734     }
   4735 
   4736     /* Set vp_lag_egr_member_bitmap */
   4737     VP_LAG_EGR_MEMBER_USED_SET_RANGE(unit, base_ptr, num_entries);
   4738 
   4739     /* Write base pointer and count to EGR_VPLAG_GROUP table */
   4740     SOC_IF_ERROR_RETURN(READ_EGR_VPLAG_GROUPm(unit, MEM_BLOCK_ANY, vp_lag_id,
   4741                 &egr_vplag_group_entry));
   4742     old_base_ptr = soc_EGR_VPLAG_GROUPm_field32_get(unit,
   4743             &egr_vplag_group_entry, BASE_PTRf);
   4744     old_num_entries = 1 + soc_EGR_VPLAG_GROUPm_field32_get(unit,
   4745             &egr_vplag_group_entry, COUNTf);
   4746     soc_EGR_VPLAG_GROUPm_field32_set(unit, &egr_vplag_group_entry, BASE_PTRf,
   4747             base_ptr);
   4748     soc_EGR_VPLAG_GROUPm_field32_set(unit, &egr_vplag_group_entry, COUNTf,
   4749             num_entries - 1);
   4750     SOC_IF_ERROR_RETURN(WRITE_EGR_VPLAG_GROUPm(unit, MEM_BLOCK_ALL, vp_lag_id,
   4751                 &egr_vplag_group_entry));
   4752 
   4753     /* If VP LAG had members, free old entries in EGR_VPLAG_MEMBER table */
   4754     if (VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member) {
   4755         VP_LAG_EGR_MEMBER_USED_CLR_RANGE(unit, old_base_ptr, old_num_entries);
   4756     }
   4757 
   4758     /* Configure EGR_DVP_ATTRIBUTE for each vp */
   4759     for (i = 0; i < vp_count; i++) {
   4760         if (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeVxlan) ||
   4761             _bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeL2Gre) ||
   4762             _bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeMpls) ||
   4763             _bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeFlow)) {
   4764             continue;
   4765         }
   4766         SOC_IF_ERROR_RETURN(READ_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ANY,
   4767                     vp_array[i], &egr_dvp_attr_entry));
   4768         if (soc_mem_field_valid(unit, EGR_DVP_ATTRIBUTEm, DATA_TYPEf)) {
   4769             soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &egr_dvp_attr_entry,
   4770                     DATA_TYPEf, 0);
   4771         } else {
   4772             soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &egr_dvp_attr_entry,
   4773                     VP_TYPEf, 0);
   4774         }
   4775         soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &egr_dvp_attr_entry,
   4776                 COMMON__ENABLE_VPLAG_SRC_PRUNINGf, TRUE);
   4777         soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &egr_dvp_attr_entry,
   4778                 COMMON__ENABLE_VPLAG_RESOLUTIONf, TRUE);
   4779         soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &egr_dvp_attr_entry,
   4780                 COMMON__VPLAG_GROUP_PTRf, vp_lag_id);
   4781         SOC_IF_ERROR_RETURN(WRITE_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ALL,
   4782                     vp_array[i], &egr_dvp_attr_entry));
   4783     }
   4784 
   4785     return BCM_E_NONE;
   4786 }
   4787 
   4788 /*
   4789  * Function:
   4790  *	_bcm_td2_vp_lag_member_check
   4791  * Purpose:
   4792  *      Check if members of a VP LAG share the same properties.
   4793  * Parameters:
   4794  *      unit - SOC unit number.
   4795  *      member_count - Number of members.
   4796  *      member_array - Array of members.
   4797  *      member_port_info - pointer to last member's port info.
   4798  * Returns:
   4799  *      BCM_E_XXX
   4800  */
   4801 STATIC int
   4802 _bcm_td2_vp_lag_member_check(int unit, int member_count,
   4803         bcm_trunk_member_t *member_array, void *member_port_info)
   4804 {
   4805     int rv = BCM_E_NONE, i;
   4806     bcm_gport_t gport = 0;
   4807     bcm_niv_port_t niv_port;
   4808     bcm_niv_port_t *niv_port_info;
   4809     uint16 match_service_tpid = 0, match_service_tpid_temp = 0;
   4810     uint32 if_class = 0, if_class_temp = 0;
   4811 
   4812     for (i = 0; i < member_count; i++) {
   4813         gport = member_array[i].gport;
   4814 
   4815         if (BCM_GPORT_IS_NIV_PORT(gport)) {
   4816             sal_memset(&niv_port, 0, sizeof(niv_port));
   4817             niv_port.niv_port_id = gport;
   4818 
   4819             rv = bcm_esw_niv_port_get(unit, &niv_port);
   4820             if (BCM_FAILURE(rv)) {
   4821                 return rv;
   4822             }
   4823 
   4824             match_service_tpid_temp = niv_port.match_service_tpid;
   4825             if_class_temp = niv_port.if_class;
   4826 
   4827             if (i == 0) {
   4828                 match_service_tpid = match_service_tpid_temp;
   4829                 if_class = if_class_temp;
   4830             } else {
   4831                 if ((match_service_tpid_temp != match_service_tpid) ||
   4832                     (if_class_temp != if_class)) {
   4833                     return BCM_E_FAIL;
   4834                 }
   4835             }
   4836         }
   4837     }
   4838 
   4839     /*Save the member's port information*/
   4840     if (BCM_GPORT_IS_NIV_PORT(gport)) {
   4841         niv_port_info = (bcm_niv_port_t *)member_port_info;
   4842         if (niv_port_info != NULL) {
   4843             sal_memcpy(niv_port_info, &niv_port, sizeof(niv_port));
   4844         }
   4845     }
   4846 
   4847     return rv;
   4848 }
   4849 
   4850 /*
   4851  * Function:
   4852  *	_bcm_td2_vp_lag_member_set
   4853  * Purpose:
   4854  *      Set members of a VP LAG.
   4855  * Parameters:
   4856  *      unit - SOC unit number.
   4857  *      vp_lag_id - VP LAG ID.
   4858  *      trunk_info - Information on the trunk group.
   4859  *      member_count - Number of members.
   4860  *      member_array - Array of members.
   4861  * Returns:
   4862  *      BCM_E_XXX
   4863  * Notes:
   4864  *      The existing ports in the VP LAG will be replaced with new ones.
   4865  */
   4866 STATIC int
   4867 _bcm_td2_vp_lag_member_set(int unit, int vp_lag_id,
   4868         bcm_trunk_info_t *trunk_info, int member_count,
   4869         bcm_trunk_member_t *member_array)
   4870 {
   4871     int rv = BCM_E_NONE;
   4872     bcm_gport_t *vp_array = NULL;
   4873     int i, vp;
   4874     int j;
   4875     uint32 vfi = 0;
   4876     uint32 network_port = 0;
   4877     bcm_gport_t gport = 0;
   4878     source_vp_entry_t svp_entry;
   4879     source_vp_entry_t svp_entry1;
   4880     uint32 network_group = 0;
   4881 #if defined(CANCUN_SUPPORT)
   4882     uint32 svp_profile_idx = 0;
   4883 #endif
   4884     int    ent_tp_val = -1;
   4885 
   4886     /* Convert member_array to vp_array. For each member,
   4887      * convert its source VP into source VP LAG in hardware.
   4888      */
   4889     vp_array = sal_alloc(member_count * sizeof(int), "VP array");
   4890     if (NULL == vp_array) {
   4891         return BCM_E_MEMORY;
   4892     }
   4893     for (i = 0, j = 0; i < member_count; i++) {
   4894         gport = member_array[i].gport;
   4895         if (BCM_GPORT_IS_VLAN_PORT(gport)) {
   4896             vp_array[j] = BCM_GPORT_VLAN_PORT_ID_GET(gport);
   4897         } else if (BCM_GPORT_IS_NIV_PORT(gport)) {
   4898             vp_array[j] = BCM_GPORT_NIV_PORT_ID_GET(gport);
   4899         } else if (BCM_GPORT_IS_EXTENDER_PORT(gport)) {
   4900             vp_array[j] = BCM_GPORT_EXTENDER_PORT_ID_GET(gport);
   4901         } else if (BCM_GPORT_IS_VXLAN_PORT(gport)) {
   4902             vp_array[j] = BCM_GPORT_VXLAN_PORT_ID_GET(gport);
   4903         } else if (BCM_GPORT_IS_MIM_PORT(gport)) {
   4904             vp_array[j] = BCM_GPORT_MIM_PORT_ID_GET(gport);
   4905         } else if (BCM_GPORT_IS_L2GRE_PORT(gport)) {
   4906             vp_array[j] = BCM_GPORT_L2GRE_PORT_ID_GET(gport);
   4907         } else if (BCM_GPORT_IS_FLOW_PORT(gport)) {
   4908             vp_array[j] = BCM_GPORT_FLOW_PORT_ID_GET(gport);
   4909         } else if (BCM_GPORT_IS_MPLS_PORT(gport)) {
   4910             vp_array[j] = BCM_GPORT_MPLS_PORT_ID_GET(gport);
   4911         } else {
   4912             sal_free(vp_array);
   4913             return BCM_E_PARAM;
   4914         }
   4915 
   4916         if (!(member_array[i].flags & BCM_TRUNK_MEMBER_EGRESS_DISABLE)) {
   4917             j++; /* number of member VPs to be programmed to egress. */
   4918         }
   4919     }
   4920 
   4921     rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp_array[0], &svp_entry1);
   4922     if (SOC_FAILURE(rv)) {
   4923         sal_free(vp_array);
   4924         return rv;
   4925     }
   4926     vfi = soc_SOURCE_VPm_field32_get(unit, &svp_entry1, VFIf);
   4927     if (soc_mem_field_valid(unit, SOURCE_VPm, NETWORK_PORTf)) {
   4928         network_port = soc_SOURCE_VPm_field32_get(unit, &svp_entry1, NETWORK_PORTf);
   4929     }
   4930     if (soc_feature(unit, soc_feature_multiple_split_horizon_group)) {
   4931         network_group = soc_SOURCE_VPm_field32_get(unit, &svp_entry1, NETWORK_GROUPf);
   4932     }
   4933 #if defined(CANCUN_SUPPORT)
   4934     if (soc_mem_field_valid(unit, SOURCE_VPm, SVP_PROFILE_INDEXf)) {
   4935         svp_profile_idx = soc_SOURCE_VPm_field32_get(unit, &svp_entry1, SVP_PROFILE_INDEXf);
   4936     }
   4937 #endif
   4938 
   4939     /* According to the member type, set some default value for vp_lag svp */
   4940     vp = VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id;
   4941     rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp_entry);
   4942     if (SOC_FAILURE(rv)) {
   4943         sal_free(vp_array);
   4944         return rv;
   4945     }
   4946 
   4947     if (BCM_GPORT_IS_EXTENDER_PORT(gport)) {
   4948         ent_tp_val = 3;
   4949         /* Set the TPID_SOURCE based on SGLP */
   4950         if (soc_mem_field_valid(unit, SOURCE_VPm, TPID_SOURCEf)) {
   4951             soc_SOURCE_VPm_field32_set(unit, &svp_entry, TPID_SOURCEf, 2);
   4952         }
   4953     } else if (BCM_GPORT_IS_NIV_PORT(gport)) {
   4954         bcm_niv_port_t niv_port;
   4955         int tpid_index, tpid_enable=0;
   4956 
   4957         bcm_niv_port_t_init(&niv_port);
   4958         rv = _bcm_td2_vp_lag_member_check(unit, member_count, member_array, (void *)&niv_port);
   4959         if (SOC_FAILURE(rv)) {
   4960             sal_free(vp_array);
   4961             return rv;
   4962         }
   4963 
   4964         /* Set the SD-tag mode and TPID */
   4965         if (niv_port.match_service_tpid) {
   4966             rv = _bcm_fb2_outer_tpid_entry_add(unit, niv_port.match_service_tpid,
   4967                     &tpid_index);
   4968             if (SOC_FAILURE(rv)) {
   4969                 sal_free(vp_array);
   4970                 return rv;
   4971             }
   4972 
   4973             tpid_enable = 1 << tpid_index;
   4974 
   4975             if (soc_mem_field_valid(unit, SVP_ATTRS_1m, TPID_ENABLEf)) {
   4976                 rv = soc_mem_field32_modify(unit, SVP_ATTRS_1m, vp, TPID_ENABLEf,
   4977                                             tpid_enable);
   4978                 if (SOC_FAILURE(rv)) {
   4979                     sal_free(vp_array);
   4980                     return rv;
   4981                 }
   4982             }
   4983 
   4984             soc_SOURCE_VPm_field32_set(unit, &svp_entry, TPID_ENABLEf,
   4985                     tpid_enable);
   4986             soc_SOURCE_VPm_field32_set(unit, &svp_entry, SD_TAG_MODEf, 1);
   4987         } else {
   4988             soc_SOURCE_VPm_field32_set(unit, &svp_entry, SD_TAG_MODEf, 0);
   4989         }
   4990         soc_SOURCE_VPm_field32_set(unit, &svp_entry, CLASS_IDf, niv_port.if_class);
   4991         ent_tp_val = 3;
   4992     } else if (BCM_GPORT_IS_VXLAN_PORT(gport) ||
   4993                BCM_GPORT_IS_MPLS_PORT(gport)) {
   4994         uint32 tpid_enable = 0;
   4995         uint32 sd_tag_mode = 0;
   4996         ent_tp_val = 1;
   4997 
   4998         sd_tag_mode = soc_SOURCE_VPm_field32_get(unit, &svp_entry1, SD_TAG_MODEf);
   4999         soc_SOURCE_VPm_field32_set(unit, &svp_entry, SD_TAG_MODEf, sd_tag_mode);
   5000 #if defined(BCM_TRIDENT3_SUPPORT)
   5001         if (SOC_IS_TRIDENT3X(unit)) {
   5002             uint32 svp1[SOC_MAX_MEM_WORDS];
   5003             uint32 svp2[SOC_MAX_MEM_WORDS];
   5004             rv = READ_SVP_ATTRS_1m(unit, MEM_BLOCK_ANY, vp_array[0], svp1);
   5005             if (SOC_FAILURE(rv)) {
   5006                 sal_free(vp_array);
   5007                 return rv;
   5008             }
   5009             rv = READ_SVP_ATTRS_1m(unit, MEM_BLOCK_ANY, vp, svp2);
   5010             if (SOC_FAILURE(rv)) {
   5011                 sal_free(vp_array);
   5012                 return rv;
   5013             }
   5014             soc_SVP_ATTRS_1m_field_get(unit, &svp1, TPID_ENABLEf, &tpid_enable);
   5015             soc_SVP_ATTRS_1m_field_set(unit, &svp2, TPID_ENABLEf, &tpid_enable);
   5016             rv = WRITE_SVP_ATTRS_1m(unit, MEM_BLOCK_ALL, vp, &svp2);
   5017             if (SOC_FAILURE(rv)) {
   5018                 sal_free(vp_array);
   5019                 return rv;
   5020             }
   5021         } else
   5022 #endif
   5023         {
   5024             tpid_enable = soc_SOURCE_VPm_field32_get(unit, &svp_entry1, TPID_ENABLEf);
   5025             soc_SOURCE_VPm_field32_set(unit, &svp_entry, TPID_ENABLEf, tpid_enable);
   5026         }
   5027     } else if (BCM_GPORT_IS_VLAN_PORT(gport)) {
   5028         ent_tp_val = 3;
   5029     } else if (BCM_GPORT_IS_MIM_PORT(gport)) {
   5030         ent_tp_val = 1;
   5031     } else if (BCM_GPORT_IS_L2GRE_PORT(gport)) {
   5032         ent_tp_val = 1;
   5033     } else if (BCM_GPORT_IS_FLOW_PORT(gport)) {
   5034         ent_tp_val = 1;
   5035     }
   5036 
   5037     if (ent_tp_val != -1) {
   5038         soc_SOURCE_VPm_field32_set(unit, &svp_entry, ENTRY_TYPEf, ent_tp_val);
   5039     }
   5040 
   5041     soc_SOURCE_VPm_field32_set(unit, &svp_entry, VFIf, vfi);
   5042     if (soc_mem_field_valid(unit, SOURCE_VPm, NETWORK_PORTf)) {
   5043         soc_SOURCE_VPm_field32_set(unit, &svp_entry, NETWORK_PORTf, network_port);
   5044     }
   5045     if (soc_feature(unit, soc_feature_multiple_split_horizon_group)) {
   5046         soc_SOURCE_VPm_field32_set(unit, &svp_entry, NETWORK_GROUPf, network_group);
   5047     }
   5048 
   5049     rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp_entry);
   5050     if (BCM_FAILURE(rv)) {
   5051         sal_free(vp_array);
   5052         return rv;
   5053     }
   5054 
   5055 #if defined(CANCUN_SUPPORT)
   5056     if (soc_feature(unit, soc_feature_cancun) &&
   5057         (ent_tp_val == 1 || ent_tp_val == 2) &&
   5058         svp_profile_idx != 0) {
   5059         rv = soc_cancun_app_dest_entry_set(unit, SOURCE_VPm,
   5060                 vp, ENTRY_TYPEf, CANCUN_APP__SOURCE_VP__No_Control_Word,
   5061                 ent_tp_val);
   5062         if (BCM_FAILURE(rv)) {
   5063             LOG_ERROR(BSL_LS_BCM_TRUNK,
   5064                (BSL_META_U(unit,
   5065                "CANCUN_APP SVP set error, vp %d ent_ty_val %d\n"),
   5066                vp, ent_tp_val));
   5067         }
   5068     }
   5069 #endif
   5070 
   5071     /* Set members in egress pipeline for VP LAGs < 256 */
   5072     if (vp_lag_id < soc_mem_index_count(unit, EGR_VPLAG_GROUPm)) {
   5073         if (j > 0) {
   5074             rv = _bcm_td2_vp_lag_member_egress_set(unit, vp_lag_id, trunk_info,
   5075                     j, vp_array);
   5076             if (BCM_FAILURE(rv)) {
   5077                 sal_free(vp_array);
   5078                 return rv;
   5079             }
   5080         }
   5081     } else {
   5082         /* VP LAGs <= 256 can only be unicast-only VP LAGs */
   5083         if (trunk_info->dlf_index != BCM_TRUNK_UNSPEC_INDEX) {
   5084             sal_free(vp_array);
   5085             return BCM_E_PARAM;
   5086         }
   5087     }
   5088 
   5089     if (j > 0) {
   5090         rv = _bcm_td2_vp_lag_member_ingress_set(unit, vp_lag_id, trunk_info,
   5091                                                 j, vp_array);
   5092         if (BCM_FAILURE(rv)) {
   5093             sal_free(vp_array);
   5094             return rv;
   5095         }
   5096     }
   5097 
   5098     sal_free(vp_array);
   5099     return rv;
   5100 }
   5101 
   5102 /*
   5103  * Function:
   5104  *	_bcm_td2_vp_lag_member_ingress_clear
   5105  * Purpose:
   5106  *      Clear members of a VP LAG in ingress pipeline.
   5107  * Parameters:
   5108  *      unit - SOC unit number.
   5109  *      vp_lag_id - VP LAG ID.
   5110  * Returns:
   5111  *      BCM_E_XXX
   5112  */
   5113 STATIC int
   5114 _bcm_td2_vp_lag_member_ingress_clear(int unit, int vp_lag_id)
   5115 {
   5116     initial_l3_ecmp_group_entry_t initial_l3_ecmp_group_entry;
   5117     ecmp_count_entry_t l3_ecmp_count_entry;
   5118     int base_ptr, vp_count;
   5119     int i;
   5120     int ecmp_idx;
   5121 
   5122     /* Set base pointer and count fields in INITIAL_L3_ECMP_GROUP
   5123      * to all ones, to indicate that there are no members.
   5124      */
   5125     ecmp_idx = _td2_vp_lag_info[unit]->base_ecmp_idx + vp_lag_id; 
   5126     SOC_IF_ERROR_RETURN(READ_INITIAL_L3_ECMP_GROUPm(unit, MEM_BLOCK_ANY,
   5127                 ecmp_idx, &initial_l3_ecmp_group_entry));
   5128     soc_INITIAL_L3_ECMP_GROUPm_field32_set(unit, &initial_l3_ecmp_group_entry,
   5129             BASE_PTRf, (1 << soc_mem_field_length(unit, INITIAL_L3_ECMP_GROUPm,
   5130                     BASE_PTRf)) - 1);
   5131     soc_INITIAL_L3_ECMP_GROUPm_field32_set(unit, &initial_l3_ecmp_group_entry,
   5132             COUNTf, (1 << soc_mem_field_length(unit, INITIAL_L3_ECMP_GROUPm,
   5133                     COUNTf)) - 1);
   5134     SOC_IF_ERROR_RETURN(WRITE_INITIAL_L3_ECMP_GROUPm(unit, MEM_BLOCK_ALL,
   5135                 ecmp_idx, &initial_l3_ecmp_group_entry));
   5136 
   5137     /* Set base pointer and count fields in L3_ECMP_COUNT
   5138      * to all ones, to indicate that there are no members.
   5139      */
   5140     SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_idx,
   5141                 &l3_ecmp_count_entry));
   5142     base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, &l3_ecmp_count_entry,
   5143             BASE_PTRf);
   5144     vp_count = 1 + soc_L3_ECMP_COUNTm_field32_get(unit, &l3_ecmp_count_entry,
   5145             COUNTf);
   5146     soc_L3_ECMP_COUNTm_field32_set(unit, &l3_ecmp_count_entry, BASE_PTRf,
   5147             (1 << soc_mem_field_length(unit, L3_ECMP_COUNTm, BASE_PTRf)) - 1);
   5148     soc_L3_ECMP_COUNTm_field32_set(unit, &l3_ecmp_count_entry, COUNTf,
   5149             (1 << soc_mem_field_length(unit, L3_ECMP_COUNTm, COUNTf)) - 1);
   5150     SOC_IF_ERROR_RETURN(WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL, ecmp_idx,
   5151                 &l3_ecmp_count_entry));
   5152 
   5153 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
   5154 #if defined(BCM_TRIDENT3_SUPPORT)
   5155     if (soc_esw_ecmp_protected_enabled(unit)) {
   5156         int rv = BCM_E_NONE;
   5157         soc_esw_ecmp_group_info_t grp_info = {0};
   5158 
   5159         SOC_ESW_ECMP_LOCK(unit);
   5160 
   5161         grp_info.ecmp_grp = ecmp_idx;
   5162         rv = soc_esw_ecmp_protected_grp_delete(unit, &grp_info);
   5163         if (BCM_FAILURE(rv)) {
   5164             SOC_ESW_ECMP_UNLOCK(unit);
   5165             return rv;
   5166         }
   5167         SOC_ESW_ECMP_UNLOCK(unit);
   5168     } else
   5169 #endif /* BCM_TRIDENT3_SUPPORT */
   5170 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
   5171     {
   5172         /* Clear INITIAL_L3_ECMP and L3_ECMP entries */
   5173         for (i = 0; i < vp_count; i++) {
   5174             SOC_IF_ERROR_RETURN(
   5175                 WRITE_INITIAL_L3_ECMPm(unit, MEM_BLOCK_ALL,
   5176                                        base_ptr + i,
   5177                                        soc_mem_entry_null(unit,
   5178                                                           INITIAL_L3_ECMPm)));
   5179             SOC_IF_ERROR_RETURN(
   5180                 WRITE_L3_ECMPm(unit, MEM_BLOCK_ALL,
   5181                                base_ptr + i,
   5182                                soc_mem_entry_null(unit,
   5183                                                   L3_ECMPm)));
   5184         }
   5185     }
   5186 
   5187     /* Decrement reference count of INITIAL_L3_ECMP and L3_ECMP entries */
   5188     BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ecmp), base_ptr,
   5189             vp_count);
   5190 
   5191     return BCM_E_NONE;
   5192 }
   5193 
   5194 /*
   5195  * Function:
   5196  *	_bcm_td2_vp_lag_member_egress_clear
   5197  * Purpose:
   5198  *      Clear members of a VP LAG in egress pipeline.
   5199  * Parameters:
   5200  *      unit - SOC unit number.
   5201  *      vp_lag_id - VP LAG ID.
   5202  *      vp_count - Number of elements in vp_array.
   5203  *      vp_array - Array of VPs in VP LAG.
   5204  * Returns:
   5205  *      BCM_E_XXX
   5206  */
   5207 STATIC int
   5208 _bcm_td2_vp_lag_member_egress_clear(int unit, int vp_lag_id,
   5209         int vp_count, int *vp_array)
   5210 {
   5211     int i;
   5212     egr_dvp_attribute_entry_t egr_dvp_attr_entry;
   5213     egr_vplag_group_entry_t egr_vplag_group_entry;
   5214     int base_ptr, num_entries;
   5215 
   5216     /* Clear EGR_DVP_ATTRIBUTE entry for each vp */
   5217     for (i = 0; i < vp_count; i++) {
   5218         if (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeVxlan) ||
   5219             _bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeL2Gre) ||
   5220             _bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeMpls) ||
   5221             _bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeFlow)) {
   5222             continue;
   5223         }
   5224         SOC_IF_ERROR_RETURN(READ_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ANY,
   5225                     vp_array[i], &egr_dvp_attr_entry));
   5226         soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &egr_dvp_attr_entry,
   5227                 COMMON__ENABLE_VPLAG_SRC_PRUNINGf, FALSE);
   5228         soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &egr_dvp_attr_entry,
   5229                 COMMON__ENABLE_VPLAG_RESOLUTIONf, FALSE);
   5230         soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &egr_dvp_attr_entry,
   5231                 COMMON__VPLAG_GROUP_PTRf, 0);
   5232         SOC_IF_ERROR_RETURN(WRITE_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ALL,
   5233                     vp_array[i], &egr_dvp_attr_entry));
   5234     }
   5235 
   5236     /* Set base pointer and count fields in EGR_VPLAG_GROUP
   5237      * to all ones, to indicate that there are no members.
   5238      */
   5239     SOC_IF_ERROR_RETURN(READ_EGR_VPLAG_GROUPm(unit, MEM_BLOCK_ANY, vp_lag_id,
   5240                 &egr_vplag_group_entry));
   5241     base_ptr = soc_EGR_VPLAG_GROUPm_field32_get(unit,
   5242             &egr_vplag_group_entry, BASE_PTRf);
   5243     num_entries = 1 + soc_EGR_VPLAG_GROUPm_field32_get(unit,
   5244             &egr_vplag_group_entry, COUNTf);
   5245     soc_EGR_VPLAG_GROUPm_field32_set(unit, &egr_vplag_group_entry, BASE_PTRf,
   5246             (1 << soc_mem_field_length(unit, EGR_VPLAG_GROUPm, BASE_PTRf)) - 1);
   5247     soc_EGR_VPLAG_GROUPm_field32_set(unit, &egr_vplag_group_entry, COUNTf,
   5248             (1 << soc_mem_field_length(unit, EGR_VPLAG_GROUPm, COUNTf)) - 1);
   5249     SOC_IF_ERROR_RETURN(WRITE_EGR_VPLAG_GROUPm(unit, MEM_BLOCK_ALL, vp_lag_id,
   5250                 &egr_vplag_group_entry));
   5251 
   5252     /* Clear EGR_VPLAG_MEMBER entries */
   5253     for (i = 0; i < num_entries; i++) {
   5254         SOC_IF_ERROR_RETURN(WRITE_EGR_VPLAG_MEMBERm(unit, MEM_BLOCK_ALL,
   5255                     base_ptr + i, soc_mem_entry_null(unit, EGR_VPLAG_MEMBERm)));
   5256     }
   5257 
   5258     VP_LAG_EGR_MEMBER_USED_CLR_RANGE(unit, base_ptr, num_entries);
   5259 
   5260     return BCM_E_NONE;
   5261 }
   5262 
   5263 /*
   5264  * Function:
   5265  *	_bcm_td2_vp_lag_member_clear
   5266  * Purpose:
   5267  *      Clear members of a VP LAG.
   5268  * Parameters:
   5269  *      unit - SOC unit number.
   5270  *      vp_lag_id - VP LAG ID.
   5271  * Returns:
   5272  *      BCM_E_XXX
   5273  */
   5274 STATIC int
   5275 _bcm_td2_vp_lag_member_clear(int unit, int vp_lag_id)
   5276 {
   5277     int rv = BCM_E_NONE;
   5278     ecmp_entry_t l3_ecmp_entry;
   5279     ecmp_count_entry_t l3_ecmp_count_entry;
   5280     int base_ptr, vp_count;
   5281     int *vp_array = NULL;
   5282     int i, vp;
   5283     bcm_gport_t gport = 0;
   5284     source_vp_entry_t svp_entry;
   5285     int ecmp_idx;
   5286     int rv_2 = BCM_E_NONE;
   5287     bcm_gport_t *egr_dis_vp;
   5288     int num_egr_dis_vp;
   5289     int protected_ecmp = 0;
   5290 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
   5291 #if defined(BCM_TRIDENT3_SUPPORT)
   5292     uint32 alloc_sz = 0;
   5293     soc_esw_ecmp_group_info_t grp_info = {0};
   5294     soc_esw_ecmp_member_info_t *mem_array = NULL;
   5295 #endif /* BCM_TRIDENT3_SUPPORT */
   5296 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
   5297 
   5298     /* Get VP LAG's members. For each member, convert its source VP LAG back
   5299      * to source VP in hardware.
   5300      */
   5301     ecmp_idx = _td2_vp_lag_info[unit]->base_ecmp_idx + vp_lag_id; 
   5302     SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_idx,
   5303                 &l3_ecmp_count_entry));
   5304     base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, &l3_ecmp_count_entry,
   5305             BASE_PTRf);
   5306     vp_count = 1 + soc_L3_ECMP_COUNTm_field32_get(unit, &l3_ecmp_count_entry,
   5307             COUNTf);
   5308     if (vp_count < 1) {
   5309         return BCM_E_INTERNAL;
   5310     }
   5311     vp_array = sal_alloc(vp_count * sizeof(int), "VP array");
   5312     if (NULL == vp_array) {
   5313         return BCM_E_MEMORY;
   5314     }
   5315 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
   5316 #if defined(BCM_TRIDENT3_SUPPORT)
   5317     if (soc_esw_ecmp_protected_enabled(unit)) {
   5318         protected_ecmp = 1;
   5319         alloc_sz = (vp_count * sizeof(soc_esw_ecmp_member_info_t));
   5320         mem_array = sal_alloc(alloc_sz, "NH array");
   5321         if (NULL == mem_array) {
   5322             sal_free(vp_array);
   5323             return BCM_E_MEMORY;
   5324         }
   5325 
   5326         SOC_ESW_ECMP_LOCK(unit);
   5327         sal_memset(mem_array, 0, alloc_sz);
   5328         grp_info.ecmp_grp = ecmp_idx;
   5329         grp_info.vp_lag = 1;
   5330         rv = soc_esw_ecmp_protected_grp_get(unit, &grp_info, mem_array);
   5331         if (BCM_FAILURE(rv)) {
   5332             sal_free(vp_array);
   5333             sal_free(mem_array);
   5334             SOC_ESW_ECMP_UNLOCK(unit);
   5335             return rv;
   5336         }
   5337 
   5338         SOC_ESW_ECMP_UNLOCK(unit);
   5339         for (i= 0; i < vp_count; i++) {
   5340             vp_array[i] = mem_array[i].dvp;
   5341         }
   5342 
   5343         sal_free(mem_array);
   5344     }
   5345 #endif /* BCM_TRIDENT3_SUPPORT */
   5346 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
   5347 
   5348     if (VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member) {
   5349         /* processing member VPs that are really programmed in H/W L3_ECMP table */
   5350         for (i = 0; i < vp_count; i++) {
   5351             if (protected_ecmp == 0) {
   5352                 rv = READ_L3_ECMPm(unit, MEM_BLOCK_ANY, base_ptr + i,
   5353                                    &l3_ecmp_entry);
   5354                 if (BCM_FAILURE(rv)) {
   5355                     sal_free(vp_array);
   5356                     return rv;
   5357                 }
   5358                 vp_array[i] = soc_L3_ECMPm_field32_get(unit, &l3_ecmp_entry, DVPf);
   5359             }
   5360 
   5361             /* Convert source VP LAG back to source VP in harware. */
   5362             if (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeVlan)) {
   5363                 BCM_GPORT_VLAN_PORT_ID_SET(gport, vp_array[i]);
   5364                 rv = _bcm_esw_vlan_port_source_vp_lag_clear(unit, gport,
   5365                         VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id);
   5366                 if (BCM_FAILURE(rv)) {
   5367                     sal_free(vp_array);
   5368                     return rv;
   5369                 }
   5370             } else if (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeNiv)) {
   5371                 BCM_GPORT_NIV_PORT_ID_SET(gport, vp_array[i]);
   5372                 rv = _bcm_esw_niv_port_source_vp_lag_clear(unit, gport,
   5373                         VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id);
   5374                 if (BCM_FAILURE(rv)) {
   5375                     sal_free(vp_array);
   5376                     return rv;
   5377                 }
   5378             } else if (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeExtender)) {
   5379                 BCM_GPORT_EXTENDER_PORT_ID_SET(gport, vp_array[i]);
   5380                 rv = _bcm_esw_extender_port_source_vp_lag_clear(unit, gport,
   5381                         VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id);
   5382                 if (BCM_FAILURE(rv)) {
   5383                     sal_free(vp_array);
   5384                     return rv;
   5385                 }
   5386             } else if (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeVxlan)) {
   5387                 BCM_GPORT_VXLAN_PORT_ID_SET(gport, vp_array[i]);
   5388                 rv = _bcm_esw_vxlan_port_source_vp_lag_clear(unit, gport,
   5389                         VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id);
   5390                 if (BCM_FAILURE(rv)) {
   5391                     sal_free(vp_array);
   5392                     return rv;
   5393                 }
   5394             } else if (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeMim)) {
   5395                 BCM_GPORT_MIM_PORT_ID_SET(gport, vp_array[i]);
   5396                 rv = _bcm_esw_mim_port_source_vp_lag_clear(unit, gport,
   5397                          VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id);
   5398                 if (BCM_FAILURE(rv)) {
   5399                     sal_free(vp_array);
   5400                     return rv;
   5401                 }
   5402             } else if (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeL2Gre)) {
   5403                 BCM_GPORT_L2GRE_PORT_ID_SET(gport, vp_array[i]);
   5404                 rv = _bcm_esw_l2gre_port_source_vp_lag_clear(
   5405                          unit, gport, VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id);
   5406                 if (BCM_FAILURE(rv)) {
   5407                     sal_free(vp_array);
   5408                     return rv;
   5409                 }
   5410             } else if (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeMpls)) {
   5411                 BCM_GPORT_MPLS_PORT_ID_SET(gport, vp_array[i]);
   5412                 rv = _bcm_esw_mpls_port_source_vp_lag_clear(
   5413                          unit, gport, VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id);
   5414                 if (BCM_FAILURE(rv)) {
   5415                     sal_free(vp_array);
   5416                     return rv;
   5417                 }
   5418             } else if (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeFlow)) {
   5419                 BCM_GPORT_FLOW_PORT_ID_SET(gport, vp_array[i]);
   5420                 rv = _bcm_esw_flow_port_source_vp_lag_clear(
   5421                          unit, gport, VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id);
   5422                 if (BCM_FAILURE(rv)) {
   5423                     sal_free(vp_array);
   5424                     return rv;
   5425                 }
   5426             } else {
   5427                 /* in order to free vp lag when member has been deleted by mistake */
   5428                 rv_2 = BCM_E_INTERNAL;
   5429                 continue;
   5430             }
   5431         }
   5432     }
   5433     /*
   5434      * Member VPs with BCM_TRUNK_MEMBER_EGRESS_DISABLE are not programmed in H/W
   5435      * L3 ECMP table, however, their VP mappings also need to be updated.
   5436      */
   5437     egr_dis_vp = VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp;
   5438     num_egr_dis_vp = VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp;
   5439     for (i = 0; i < num_egr_dis_vp; i++) {
   5440         gport = egr_dis_vp[i];
   5441         /* Convert source VP LAG back to source VP in harware. */
   5442         if (BCM_GPORT_IS_VLAN_PORT(gport)) {
   5443             rv = _bcm_esw_vlan_port_source_vp_lag_clear(unit, gport,
   5444                     VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id);
   5445             if (BCM_FAILURE(rv)) {
   5446                 sal_free(vp_array);
   5447                 return rv;
   5448             }
   5449         } else if (BCM_GPORT_IS_NIV_PORT(gport)) {
   5450             rv = _bcm_esw_niv_port_source_vp_lag_clear(unit, gport,
   5451                     VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id);
   5452             if (BCM_FAILURE(rv)) {
   5453                 sal_free(vp_array);
   5454                 return rv;
   5455             }
   5456         } else if (BCM_GPORT_IS_EXTENDER_PORT(gport)) {
   5457             rv = _bcm_esw_extender_port_source_vp_lag_clear(unit, gport,
   5458                     VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id);
   5459             if (BCM_FAILURE(rv)) {
   5460                 sal_free(vp_array);
   5461                 return rv;
   5462             }
   5463         } else if (BCM_GPORT_IS_VXLAN_PORT(gport)) {
   5464             rv = _bcm_esw_vxlan_port_source_vp_lag_clear(unit, gport,
   5465                     VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id);
   5466             if (BCM_FAILURE(rv)) {
   5467                 sal_free(vp_array);
   5468                 return rv;
   5469             }
   5470         } else if (BCM_GPORT_IS_MIM_PORT(gport)) {
   5471             rv = _bcm_esw_mim_port_source_vp_lag_clear(unit, gport,
   5472                      VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id);
   5473             if (BCM_FAILURE(rv)) {
   5474                 sal_free(vp_array);
   5475                 return rv;
   5476             }
   5477         } else if (BCM_GPORT_IS_L2GRE_PORT(gport)) {
   5478             rv = _bcm_esw_l2gre_port_source_vp_lag_clear(
   5479                      unit, gport, VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id);
   5480             if (BCM_FAILURE(rv)) {
   5481                 sal_free(vp_array);
   5482                 return rv;
   5483             }
   5484         } else if (BCM_GPORT_IS_MPLS_PORT(gport)) {
   5485             rv = _bcm_esw_mpls_port_source_vp_lag_clear(
   5486                      unit, gport, VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id);
   5487             if (BCM_FAILURE(rv)) {
   5488                 sal_free(vp_array);
   5489                 return rv;
   5490             }
   5491         } else if (BCM_GPORT_IS_FLOW_PORT(gport)) {
   5492             rv = _bcm_esw_flow_port_source_vp_lag_clear(
   5493                      unit, gport, VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id);
   5494             if (BCM_FAILURE(rv)) {
   5495                 sal_free(vp_array);
   5496                 return rv;
   5497             }
   5498         } else {
   5499             /* in order to free vp lag when member has been deleted by mistake */
   5500             rv_2 = BCM_E_INTERNAL;
   5501             continue;
   5502         }
   5503     }
   5504 
   5505     /* According to the member type, clear some default value for vp_lag svp */
   5506     vp = VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id;
   5507     rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp_entry);
   5508     if (SOC_FAILURE(rv)) {
   5509         sal_free(vp_array);
   5510         return rv;
   5511     }
   5512 
   5513     if (BCM_GPORT_IS_EXTENDER_PORT(gport)) {
   5514         soc_SOURCE_VPm_field32_set(unit, &svp_entry, ENTRY_TYPEf, 0);
   5515         /* Set the TPID_SOURCE based on SGLP */
   5516         if (soc_mem_field_valid(unit, SOURCE_VPm, TPID_SOURCEf)) {
   5517             soc_SOURCE_VPm_field32_set(unit, &svp_entry, TPID_SOURCEf, 0);
   5518         }
   5519     } else if (BCM_GPORT_IS_NIV_PORT(gport)) {
   5520         int tpid_enb_len;
   5521         int old_tpid_enable, j;
   5522         svp_attrs_1_entry_t sa1_ent;
   5523 
   5524         sal_memset(&sa1_ent, 0, sizeof(sa1_ent));
   5525         if (soc_mem_field_valid(unit, SVP_ATTRS_1m, TPID_ENABLEf)) {
   5526             rv = READ_SVP_ATTRS_1m(unit, MEM_BLOCK_ANY, vp, &sa1_ent);
   5527             if (SOC_FAILURE(rv)) {
   5528                 sal_free(vp_array);
   5529                 return rv;
   5530             }
   5531             old_tpid_enable = soc_mem_field32_get(unit, SVP_ATTRS_1m, &sa1_ent,
   5532                                                   TPID_ENABLEf);
   5533             tpid_enb_len = soc_mem_field_length(unit, SVP_ATTRS_1m, TPID_ENABLEf);
   5534             soc_mem_field32_set(unit, SVP_ATTRS_1m, &sa1_ent, TPID_ENABLEf, 0);
   5535         } else {
   5536             old_tpid_enable = soc_SOURCE_VPm_field32_get(unit, &svp_entry,
   5537                     TPID_ENABLEf);
   5538             tpid_enb_len = soc_mem_field_length(unit, SOURCE_VPm, TPID_ENABLEf);
   5539             soc_SOURCE_VPm_field32_set(unit, &svp_entry, TPID_ENABLEf, 0);
   5540         }
   5541 
   5542         if (old_tpid_enable) {
   5543             for (j = 0; j < tpid_enb_len; j++) {
   5544                 if (old_tpid_enable & (1 << j)) {
   5545                     rv = _bcm_fb2_outer_tpid_entry_delete(unit, j);
   5546                     if (BCM_FAILURE(rv)) {
   5547                         sal_free(vp_array);
   5548                         return rv;
   5549                     }
   5550                 }
   5551             }
   5552         }
   5553 
   5554         if (soc_mem_field_valid(unit, SVP_ATTRS_1m, TPID_ENABLEf)) {
   5555             rv = WRITE_SVP_ATTRS_1m(unit, MEM_BLOCK_ALL, vp, &sa1_ent);
   5556             if (BCM_FAILURE(rv)) {
   5557                 sal_free(vp_array);
   5558                 return rv;
   5559             }
   5560         }
   5561 
   5562         soc_SOURCE_VPm_field32_set(unit, &svp_entry, SD_TAG_MODEf, 0);
   5563         soc_SOURCE_VPm_field32_set(unit, &svp_entry, CLASS_IDf, 0);
   5564         soc_SOURCE_VPm_field32_set(unit, &svp_entry, ENTRY_TYPEf, 0);
   5565     } else if (BCM_GPORT_IS_VXLAN_PORT(gport)) {
   5566         soc_SOURCE_VPm_field32_set(unit, &svp_entry, ENTRY_TYPEf, 0);
   5567     } else if (BCM_GPORT_IS_VLAN_PORT(gport)) {
   5568         soc_SOURCE_VPm_field32_set(unit, &svp_entry, ENTRY_TYPEf, 0);
   5569     } else if (BCM_GPORT_IS_MIM_PORT(gport)) {
   5570         soc_SOURCE_VPm_field32_set(unit, &svp_entry, ENTRY_TYPEf, 0);
   5571     } else if (BCM_GPORT_IS_L2GRE_PORT(gport)) {
   5572         soc_SOURCE_VPm_field32_set(unit, &svp_entry, ENTRY_TYPEf, 0);
   5573     } else if (BCM_GPORT_IS_MPLS_PORT(gport)) {
   5574         soc_SOURCE_VPm_field32_set(unit, &svp_entry, ENTRY_TYPEf, 0);
   5575     } else if (BCM_GPORT_IS_FLOW_PORT(gport)) {
   5576         soc_SOURCE_VPm_field32_set(unit, &svp_entry, ENTRY_TYPEf, 0);
   5577     }
   5578 
   5579 #if defined(CANCUN_SUPPORT)
   5580     if (soc_feature(unit, soc_feature_cancun)) {
   5581         if (BCM_GPORT_IS_VXLAN_PORT(gport) ||
   5582             BCM_GPORT_IS_MIM_PORT(gport) ||
   5583             BCM_GPORT_IS_L2GRE_PORT(gport) ||
   5584             BCM_GPORT_IS_MPLS_PORT(gport) ||
   5585             BCM_GPORT_IS_FLOW_PORT(gport)) {
   5586             soc_SOURCE_VPm_field32_set(unit, &svp_entry, SVP_PROFILE_INDEXf, 0);
   5587         }
   5588     }
   5589 #endif
   5590 
   5591     rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp_entry);
   5592     if (BCM_FAILURE(rv)) {
   5593         sal_free(vp_array);
   5594         return rv;
   5595     }
   5596 
   5597     /* clear L3_ECMP and EGR_VPLAG tables only when there are member VPs actually programmed */
   5598     if (VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member) {
   5599         /* Clear members in ingress pipeline */
   5600         rv = _bcm_td2_vp_lag_member_ingress_clear(unit, vp_lag_id);
   5601         if (BCM_FAILURE(rv)) {
   5602             sal_free(vp_array);
   5603             return rv;
   5604         }
   5605 
   5606         /* Clear members in egress pipeline for VP LAGs < 256 */
   5607         if (vp_lag_id < soc_mem_index_count(unit, EGR_VPLAG_GROUPm)) {
   5608             rv = _bcm_td2_vp_lag_member_egress_clear(unit, vp_lag_id, vp_count,
   5609                     vp_array);
   5610             if (BCM_FAILURE(rv)) {
   5611                 sal_free(vp_array);
   5612                 return rv;
   5613             }
   5614         }
   5615     }
   5616 
   5617     sal_free(vp_array);
   5618     if (rv_2 != BCM_E_NONE) {
   5619         return rv_2;
   5620     }
   5621     return rv;
   5622 }
   5623 
   5624 /*
   5625  * Function:
   5626  *      _bcm_td2_vp_lag_member_is_vfi_type
   5627  * Purpose:
   5628  *      Finds out if member of VP-LAG is VFI type virtual port.
   5629  * Parameters:
   5630  *      unit  - SOC device unit number
   5631  *      tid - trunk id provided
   5632  *      vfi_type - TRUE for VFI type, otherwise FALSE
   5633  * Returns:
   5634  *      BCM_E_XXX
   5635  */
   5636 int
   5637 _bcm_td2_vp_lag_member_is_vfi_type(int unit, bcm_trunk_t tid,
   5638         int *vfi_type)
   5639 {
   5640     int rv = BCM_E_NONE;
   5641     int vp;
   5642     int vp_lag_id;
   5643     int ecmp_idx;
   5644     ecmp_entry_t l3_ecmp_entry;
   5645     ecmp_count_entry_t l3_ecmp_count_entry;
   5646     int base_ptr;
   5647 
   5648     VP_LAG_INIT_CHECK(unit);
   5649 
   5650     BCM_IF_ERROR_RETURN(_bcm_td2_tid_to_vp_lag_id(unit, tid, &vp_lag_id));
   5651     if (!VP_LAG_USED_GET(unit, vp_lag_id)) {
   5652         return BCM_E_NOT_FOUND;
   5653     }
   5654 
   5655     /* Get first member of VP LAG and  check VFI type */
   5656     ecmp_idx = _td2_vp_lag_info[unit]->base_ecmp_idx + vp_lag_id;
   5657     SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_idx,
   5658         &l3_ecmp_count_entry));
   5659     base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, &l3_ecmp_count_entry, BASE_PTRf);
   5660 
   5661     rv = READ_L3_ECMPm(unit, MEM_BLOCK_ANY, base_ptr , &l3_ecmp_entry);
   5662     if (SOC_SUCCESS(rv)) {
   5663         vp = soc_L3_ECMPm_field32_get(unit, &l3_ecmp_entry, DVPf);
   5664         if (_bcm_vp_used_get(unit, vp, _bcmVpTypeVxlan)
   5665             || _bcm_vp_used_get(unit, vp, _bcmVpTypeL2Gre)
   5666             || _bcm_vp_used_get(unit, vp, _bcmVpTypeMpls)
   5667             || _bcm_vp_used_get(unit, vp, _bcmVpTypeMim)) {
   5668             *vfi_type = TRUE;
   5669         }
   5670     }
   5671 
   5672     return rv;
   5673 }
   5674 
   5675 /*
   5676  * Function:
   5677  *	_bcm_td2_vp_lag_match_vp_set
   5678  * Purpose:
   5679  *      Set match vp of a VP LAG.
   5680  * Parameters:
   5681  *      unit - SOC unit number.
   5682  *      vp_lag_id - VP LAG ID.
   5683  *      member_count - Number of members.
   5684  *      member_array - Array of members.
   5685  * Returns:
   5686  *      BCM_E_XXX
   5687  */
   5688 int
   5689 _bcm_td2_vp_lag_match_vp_set(int unit, int vp_lag_id,
   5690         int member_count, bcm_trunk_member_t *member_array)
   5691 {
   5692     int i = 0;
   5693     int rv = BCM_E_NONE;
   5694     int vp_id = VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id;
   5695     bcm_gport_t gport = 0;
   5696 
   5697     for (i = 0; i < member_count; i++) {
   5698         gport = member_array[i].gport;
   5699         if (BCM_GPORT_IS_VLAN_PORT(gport)) {
   5700             rv = _bcm_esw_vlan_port_source_vp_lag_set(unit, gport, vp_id);
   5701             if (BCM_FAILURE(rv)) {
   5702                 return rv;
   5703             }
   5704         } else if (BCM_GPORT_IS_NIV_PORT(gport)) {
   5705             rv = _bcm_esw_niv_port_source_vp_lag_set(unit, gport, vp_id);
   5706             if (BCM_FAILURE(rv)) {
   5707                 return rv;
   5708             }
   5709         } else if (BCM_GPORT_IS_EXTENDER_PORT(gport)) {
   5710             rv = _bcm_esw_extender_port_source_vp_lag_set(unit, gport, vp_id);
   5711             if (BCM_FAILURE(rv)) {
   5712                 return rv;
   5713             }
   5714         } else if (BCM_GPORT_IS_VXLAN_PORT(gport)) {
   5715             rv = _bcm_esw_vxlan_port_source_vp_lag_set(unit, gport, vp_id);
   5716             if (BCM_FAILURE(rv)) {
   5717                 return rv;
   5718             }
   5719         } else if (BCM_GPORT_IS_MIM_PORT(gport)) {
   5720             rv = _bcm_esw_mim_port_source_vp_lag_set(unit, gport, vp_id);
   5721             if (BCM_FAILURE(rv)) {
   5722                 return rv;
   5723             }
   5724         } else if (BCM_GPORT_IS_L2GRE_PORT(gport)) {
   5725             rv = _bcm_esw_l2gre_port_source_vp_lag_set(unit, gport, vp_id);
   5726             if (BCM_FAILURE(rv)) {
   5727                 return rv;
   5728             }
   5729         } else if (BCM_GPORT_IS_MPLS_PORT(gport)) {
   5730             rv = _bcm_esw_mpls_port_source_vp_lag_set(unit, gport, vp_id);
   5731             if (BCM_FAILURE(rv)) {
   5732                 return rv;
   5733             }
   5734         } else if (BCM_GPORT_IS_FLOW_PORT(gport)) {
   5735             rv = _bcm_esw_flow_port_source_vp_lag_set(unit, gport, vp_id);
   5736             if (BCM_FAILURE(rv)) {
   5737                 return rv;
   5738             }
   5739         } else {
   5740             return BCM_E_PARAM;
   5741         }
   5742     }
   5743 
   5744     return rv;
   5745 }
   5746 
   5747 /*
   5748  * Function:
   5749  *	bcm_td2_vp_lag_set
   5750  * Purpose:
   5751  *      Set properties and members of a VP LAG.
   5752  * Parameters:
   5753  *      unit - SOC unit number.
   5754  *      tid - The trunk ID to be affected.
   5755  *      trunk_info - Information on the trunk group.
   5756  *      member_count - Number of members.
   5757  *      member_array - Array of members.
   5758  * Returns:
   5759  *      BCM_E_XXX
   5760  */
   5761 int
   5762 bcm_td2_vp_lag_set(int unit, bcm_trunk_t tid, bcm_trunk_info_t *trunk_info,
   5763         int member_count, bcm_trunk_member_t *member_array)
   5764 {
   5765     bcm_trunk_chip_info_t trunk_chip_info;
   5766     int vp_lag_id;
   5767     int i;
   5768     bcm_gport_t gport;
   5769     bcm_gport_t *egr_dis_vp = NULL;
   5770     int num_egr_dis_vp = 0;
   5771     int rv = BCM_E_NONE;
   5772 
   5773     VP_LAG_INIT_CHECK(unit);
   5774 
   5775     BCM_IF_ERROR_RETURN(_bcm_td2_tid_to_vp_lag_id(unit, tid, &vp_lag_id)); 
   5776     if (!VP_LAG_USED_GET(unit, vp_lag_id)) {
   5777         return BCM_E_NOT_FOUND;
   5778     }
   5779 
   5780     if (NULL == trunk_info) {
   5781         return BCM_E_PARAM;
   5782     }
   5783     if (trunk_info->psc != BCM_TRUNK_PSC_PORTFLOW) {
   5784         /* Only RTAG7 is supported for VP LAG */
   5785         return BCM_E_PARAM;
   5786     }
   5787     if ((trunk_info->dlf_index != trunk_info->mc_index) ||
   5788         (trunk_info->dlf_index != trunk_info->ipmc_index)) {
   5789         return BCM_E_PARAM;
   5790     }
   5791     if ((trunk_info->flags != 0) ||
   5792         (trunk_info->ipmc_psc != 0) ||
   5793         (trunk_info->dynamic_size != 0) ||
   5794         (trunk_info->dynamic_age != 0) ||
   5795         (trunk_info->dynamic_load_exponent != 0) ||
   5796         (trunk_info->dynamic_expected_load_exponent != 0)) { 
   5797         /* These fields should be zeroes */
   5798         return BCM_E_PARAM;
   5799     }
   5800 
   5801     BCM_IF_ERROR_RETURN(bcm_esw_trunk_chip_info_get(unit, &trunk_chip_info));
   5802     if (member_count > trunk_chip_info.vp_ports_max) {
   5803         return BCM_E_PARAM;
   5804     } else if (member_count > 0) {
   5805         if (trunk_info->dlf_index >= member_count) {
   5806             /* dlf_index out of range */
   5807             return BCM_E_PARAM;
   5808         }
   5809         if (NULL == member_array) {
   5810             return BCM_E_PARAM;
   5811         }
   5812     } else {
   5813         if (NULL != member_array) {
   5814             return BCM_E_PARAM;
   5815         }
   5816     }
   5817 
   5818     if (member_count > 0) {
   5819         egr_dis_vp = (bcm_gport_t*)sal_alloc(sizeof(bcm_gport_t) * member_count,
   5820                                                       "VP LAG Member info");
   5821         if (egr_dis_vp == NULL) {
   5822             rv = BCM_E_MEMORY;
   5823             return rv;
   5824         }
   5825         sal_memset(egr_dis_vp, 0, sizeof(bcm_gport_t) * member_count);
   5826     }
   5827 
   5828     for (i = 0; i < member_count; i++) {
   5829         gport = member_array[i].gport;
   5830         if (!BCM_GPORT_IS_VLAN_PORT(gport) &&
   5831             !BCM_GPORT_IS_NIV_PORT(gport) &&
   5832             !BCM_GPORT_IS_EXTENDER_PORT(gport) &&
   5833             !BCM_GPORT_IS_VXLAN_PORT(gport) &&
   5834             !BCM_GPORT_IS_MIM_PORT(gport) &&
   5835             !BCM_GPORT_IS_L2GRE_PORT(gport) &&
   5836             !BCM_GPORT_IS_MPLS_PORT(gport) &&
   5837             !BCM_GPORT_IS_FLOW_PORT(gport)) {
   5838             sal_free(egr_dis_vp);
   5839             return BCM_E_PARAM;
   5840         }
   5841 
   5842         if (member_array[i].flags & BCM_TRUNK_MEMBER_EGRESS_DISABLE) {
   5843             egr_dis_vp[num_egr_dis_vp++] = member_array[i].gport;
   5844         }
   5845     }
   5846 
   5847     /* Clear existing members */
   5848     if (VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member ||
   5849         VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp) {
   5850         rv = _bcm_td2_vp_lag_member_clear(unit, vp_lag_id);
   5851         if (rv != BCM_E_NONE) {
   5852             sal_free(egr_dis_vp);
   5853             return rv;
   5854         }
   5855         VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member = FALSE;
   5856         if (VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp != NULL) {
   5857             sal_free(VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp);
   5858         }
   5859         VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp = 0;
   5860     }
   5861 
   5862     /* Set new members */
   5863     if (member_count > 0) {
   5864         rv = _bcm_td2_vp_lag_member_set(unit, vp_lag_id,
   5865                     trunk_info, member_count, member_array);
   5866         if (rv != BCM_E_NONE) {
   5867             sal_free(egr_dis_vp);
   5868             return rv;
   5869         }
   5870         rv = _bcm_td2_vp_lag_match_vp_set(unit, vp_lag_id,
   5871                     member_count, member_array);
   5872         if (rv != BCM_E_NONE) {
   5873             sal_free(egr_dis_vp);
   5874             return rv;
   5875         }
   5876         VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member =
   5877                                     (member_count - num_egr_dis_vp) ? TRUE:FALSE;
   5878     }
   5879 
   5880     VP_LAG_GROUP_INFO(unit, vp_lag_id).non_uc_index = trunk_info->dlf_index; 
   5881     VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp = num_egr_dis_vp;
   5882     VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp = egr_dis_vp;
   5883 
   5884     return BCM_E_NONE;
   5885 }
   5886 
   5887 /*
   5888  * Function:
   5889  *	bcm_td2_vp_lag_destroy
   5890  * Purpose:
   5891  *      Destroy a VP LAG.
   5892  * Parameters:
   5893  *      unit  - SOC unit number
   5894  *      tid   - Trunk ID
   5895  * Returns:
   5896  *      BCM_E_xxx
   5897  */
   5898 int
   5899 bcm_td2_vp_lag_destroy(int unit, bcm_trunk_t tid)
   5900 {
   5901     int vp_lag_id;
   5902     int vp;
   5903     ecmp_count_entry_t l3_ecmp_count_entry;
   5904     initial_l3_ecmp_group_entry_t initial_l3_ecmp_group_entry;
   5905     ing_dvp_table_entry_t ing_dvp_entry;
   5906     ing_dvp_2_table_entry_t ing_dvp_2_entry;
   5907     egr_vplag_group_entry_t egr_vplag_group_entry;
   5908     source_vp_entry_t svp_entry;
   5909     int ecmp_idx;
   5910     int rv_2 = BCM_E_NONE;
   5911 
   5912     VP_LAG_INIT_CHECK(unit);
   5913 
   5914     BCM_IF_ERROR_RETURN(_bcm_td2_tid_to_vp_lag_id(unit, tid, &vp_lag_id)); 
   5915     if (!VP_LAG_USED_GET(unit, vp_lag_id)) {
   5916         return BCM_E_NOT_FOUND;
   5917     }
   5918 
   5919     if (VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member ||
   5920         VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp) {
   5921         rv_2 = _bcm_td2_vp_lag_member_clear(unit, vp_lag_id);
   5922         VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member = FALSE;
   5923         if (VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp != NULL) {
   5924             sal_free(VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp);
   5925         }
   5926         VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp = 0;;
   5927     }
   5928     VP_LAG_GROUP_INFO(unit, vp_lag_id).non_uc_index = 0; 
   5929 
   5930     /* Get the VP used to represent this VP LAG */
   5931     vp = VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id;
   5932 
   5933     /* Clear VP LAG info in SOURCE_VP */
   5934     SOC_IF_ERROR_RETURN(READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp_entry));
   5935     soc_SOURCE_VPm_field32_set(unit, &svp_entry, CML_FLAGS_NEWf, 0x0);
   5936     soc_SOURCE_VPm_field32_set(unit, &svp_entry, CML_FLAGS_MOVEf, 0x0);
   5937     soc_SOURCE_VPm_field32_set(unit, &svp_entry, VFIf, 0x0);
   5938     soc_SOURCE_VPm_field32_set(unit, &svp_entry, SD_TAG_MODEf, 0);
   5939     if (soc_mem_field_valid(unit, SOURCE_VPm, NETWORK_PORTf)) {
   5940         soc_SOURCE_VPm_field32_set(unit, &svp_entry, NETWORK_PORTf, 0x0);
   5941     }
   5942     if (soc_feature(unit, soc_feature_multiple_split_horizon_group)) {
   5943         soc_SOURCE_VPm_field32_set(unit, &svp_entry, NETWORK_GROUPf, 0x0);
   5944     }
   5945     if (soc_mem_field_valid(unit, SVP_ATTRS_1m, TPID_ENABLEf)) {
   5946         svp_attrs_1_entry_t svp_attrs;
   5947         sal_memset(&svp_attrs, 0, sizeof(svp_attrs));
   5948         SOC_IF_ERROR_RETURN(
   5949             WRITE_SVP_ATTRS_1m(unit, MEM_BLOCK_ANY, vp, &svp_attrs));
   5950     } else if (soc_mem_field_valid(unit, SOURCE_VPm, TPID_ENABLEf)) {
   5951         soc_SOURCE_VPm_field32_set(unit, &svp_entry, TPID_ENABLEf, 0);
   5952     }
   5953 
   5954     SOC_IF_ERROR_RETURN(WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp_entry));
   5955 
   5956     /* Clear VP LAG info in ING_DVP_TABLE */
   5957     SOC_IF_ERROR_RETURN(READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp,
   5958                 &ing_dvp_entry));
   5959     soc_ING_DVP_TABLEm_field32_set(unit, &ing_dvp_entry,
   5960             ENABLE_VPLAG_RESOLUTIONf, 0);
   5961     soc_ING_DVP_TABLEm_field32_set(unit, &ing_dvp_entry,
   5962             DVP_GROUP_PTRf, 0);
   5963     soc_ING_DVP_TABLEm_field32_set(unit, &ing_dvp_entry,
   5964             VP_TYPEf, 0);
   5965     SOC_IF_ERROR_RETURN(WRITE_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp,
   5966                 &ing_dvp_entry));
   5967 
   5968     /* Clear VP LAG info in ING_DVP_2_TABLE */
   5969     SOC_IF_ERROR_RETURN(READ_ING_DVP_2_TABLEm(unit, MEM_BLOCK_ANY, vp,
   5970                 &ing_dvp_2_entry));
   5971     soc_ING_DVP_2_TABLEm_field32_set(unit, &ing_dvp_2_entry,
   5972             ENABLE_VPLAG_RESOLUTIONf, 0);
   5973     soc_ING_DVP_2_TABLEm_field32_set(unit, &ing_dvp_2_entry,
   5974             DVP_GROUP_PTRf, 0);
   5975     soc_ING_DVP_2_TABLEm_field32_set(unit, &ing_dvp_2_entry,
   5976             VP_TYPEf, 0);
   5977     SOC_IF_ERROR_RETURN(WRITE_ING_DVP_2_TABLEm(unit, MEM_BLOCK_ALL, vp,
   5978                 &ing_dvp_2_entry));
   5979 
   5980     /* Clear VP LAG info in INITIAL_L3_ECMP_GROUP entry */
   5981     ecmp_idx = _td2_vp_lag_info[unit]->base_ecmp_idx + vp_lag_id; 
   5982     SOC_IF_ERROR_RETURN(READ_INITIAL_L3_ECMP_GROUPm(unit, MEM_BLOCK_ANY,
   5983                 ecmp_idx, &initial_l3_ecmp_group_entry));
   5984     soc_INITIAL_L3_ECMP_GROUPm_field32_set(unit, &initial_l3_ecmp_group_entry,
   5985             BASE_PTRf, 0);
   5986     soc_INITIAL_L3_ECMP_GROUPm_field32_set(unit, &initial_l3_ecmp_group_entry,
   5987             COUNTf, 0);
   5988     SOC_IF_ERROR_RETURN(WRITE_INITIAL_L3_ECMP_GROUPm(unit, MEM_BLOCK_ALL,
   5989             ecmp_idx, &initial_l3_ecmp_group_entry));
   5990 
   5991     /* Clear VP LAG info in L3_ECMP_COUNT entry */
   5992     SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_idx,
   5993                 &l3_ecmp_count_entry));
   5994     soc_L3_ECMP_COUNTm_field32_set(unit, &l3_ecmp_count_entry, BASE_PTRf, 0);
   5995     soc_L3_ECMP_COUNTm_field32_set(unit, &l3_ecmp_count_entry, COUNTf, 0);
   5996     SOC_IF_ERROR_RETURN(WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL, ecmp_idx,
   5997             &l3_ecmp_count_entry));
   5998 
   5999     /* Clear VP LAG info in EGR_VPLAG_GROUP entry */
   6000     if (vp_lag_id < soc_mem_index_count(unit, EGR_VPLAG_GROUPm)) {
   6001         SOC_IF_ERROR_RETURN(READ_EGR_VPLAG_GROUPm(unit, MEM_BLOCK_ANY,
   6002                     vp_lag_id, &egr_vplag_group_entry));
   6003         soc_EGR_VPLAG_GROUPm_field32_set(unit, &egr_vplag_group_entry,
   6004                 DVP_LAG_IDf, 0);
   6005         soc_EGR_VPLAG_GROUPm_field32_set(unit, &egr_vplag_group_entry,
   6006                 BASE_PTRf, 0);
   6007         soc_EGR_VPLAG_GROUPm_field32_set(unit, &egr_vplag_group_entry,
   6008                 COUNTf, 0);
   6009         SOC_IF_ERROR_RETURN(WRITE_EGR_VPLAG_GROUPm(unit, MEM_BLOCK_ALL,
   6010                     vp_lag_id, &egr_vplag_group_entry));
   6011     }
   6012 
   6013     /* Free the VP used to represent the VP LAG */
   6014     BCM_IF_ERROR_RETURN(_bcm_vp_free(unit, _bcmVpTypeVpLag, 1, vp));
   6015 
   6016     /* Free the VP LAG ID */
   6017     VP_LAG_USED_CLR(unit, vp_lag_id);
   6018 
   6019     if (rv_2 != BCM_E_NONE) {
   6020         return rv_2;
   6021     }
   6022     return BCM_E_NONE;
   6023 }
   6024 
   6025 /*
   6026  * Function:
   6027  *      _bcm_td2_vp_lag_match_multi_get
   6028  * Purpose:
   6029  *      Get all the matches for an existing vp lag.
   6030  * Parameters:
   6031  *      unit -        (IN) Unit number.
   6032  *      tid -         (IN) Trunk Id
   6033  *      size -        (IN) Number of elements in match array
   6034  *      match_array - (OUT) Match array
   6035  *      count -       (OUT) Match count
   6036  * Returns:
   6037  *      BCM_X_XXX
   6038  */
   6039 int
   6040 _bcm_td2_vp_lag_match_multi_get(
   6041     int unit,
   6042     bcm_trunk_t tid,
   6043     int size,
   6044     bcm_port_match_info_t *match_array,
   6045     int *count)
   6046 {
   6047     int                    rv;
   6048     int                    vp, tmp_vp;
   6049     uint8                  *vt_buf = NULL; /* VLAN_XLATE DMA buffer */
   6050     soc_mem_t              mem = VLAN_XLATEm;
   6051     int                    index, index_min, index_max, idx;
   6052     bcm_trunk_member_t     *member_array = NULL;
   6053     int                    member_count;
   6054     void                   *vent;
   6055     uint32                 *vent_member_array = NULL;
   6056     int                    action;
   6057     bcm_gport_t            match_gport = 0, gport;
   6058     int                    key_type_value, key_type;
   6059     int                    cnt = 0;
   6060     int                    alloc_size, ent_size;
   6061     bcm_module_t           mod_out, mod_in;
   6062     bcm_port_t             port_out, port_in;
   6063     uint16                 src_vif = 0;
   6064     bcm_vlan_t             match_vlan = BCM_VLAN_NONE;
   6065     int                    matched = 0;
   6066     int                    vp_lag_id;
   6067 
   6068     if (soc_mem_is_valid(unit, VLAN_XLATE_1_DOUBLEm)) {
   6069         mem = VLAN_XLATE_1_DOUBLEm;
   6070         ent_size = sizeof(vlan_xlate_1_double_entry_t);
   6071     } else {
   6072         ent_size = sizeof(vlan_xlate_entry_t);
   6073     }
   6074 
   6075     /* Parameter checks */
   6076     if ((size < 0) || (count == NULL)) {
   6077         return BCM_E_PARAM;
   6078     }
   6079     if ((size > 0) && (match_array == NULL)) {
   6080         return BCM_E_PARAM;
   6081     }
   6082 
   6083     VP_LAG_INIT_CHECK(unit);
   6084 
   6085     BCM_IF_ERROR_RETURN(_bcm_td2_tid_to_vp_lag_id(unit, tid, &vp_lag_id));
   6086     if (!VP_LAG_USED_GET(unit, vp_lag_id)) {
   6087         return BCM_E_NOT_FOUND;
   6088     }
   6089     BCM_IF_ERROR_RETURN(
   6090         _bcm_esw_trunk_tid_to_vp_lag_vp(unit, tid, &vp));
   6091     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeVpLag)) {
   6092         return BCM_E_NOT_FOUND;
   6093     }
   6094 
   6095     vt_buf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, mem),
   6096                            "VLAN_XLATE buffer");
   6097     if (NULL == vt_buf) {
   6098         return BCM_E_MEMORY;
   6099     }
   6100     index_min = soc_mem_index_min(unit, mem);
   6101     index_max = soc_mem_index_max(unit, mem);
   6102 
   6103     soc_mem_lock(unit, mem);
   6104     if ((rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY,
   6105                                   index_min, index_max, vt_buf)) < 0) {
   6106         goto cleanup;
   6107     }
   6108     rv = bcm_td2_vp_lag_get(unit, tid, NULL, 0, NULL, &member_count);
   6109     if (BCM_FAILURE(rv)) {
   6110         goto cleanup;
   6111     }
   6112     if (member_count > 0) {
   6113         alloc_size = member_count * sizeof(bcm_trunk_member_t);
   6114         member_array = sal_alloc(alloc_size, "vplag member array");
   6115         if (member_array == NULL) {
   6116             rv = BCM_E_MEMORY;
   6117             goto cleanup;
   6118         }
   6119         sal_memset(member_array, 0, alloc_size);
   6120         rv = bcm_td2_vp_lag_get(unit, tid, NULL, member_count,
   6121                                 member_array, &member_count);
   6122         if (BCM_FAILURE(rv)) {
   6123             goto cleanup;
   6124         }
   6125         alloc_size = member_count * ent_size;
   6126         vent_member_array = sal_alloc(alloc_size, "extender port array");
   6127         if (vent_member_array == NULL) {
   6128             rv = BCM_E_MEMORY;
   6129             goto cleanup;
   6130         }
   6131         sal_memset(vent_member_array, 0, alloc_size);
   6132         for (idx = 0; idx < member_count; idx++) {
   6133             gport = member_array[idx].gport;
   6134             if (BCM_GPORT_IS_EXTENDER_PORT(gport)) {
   6135                 rv = bcm_tr3_extender_match_key_get(
   6136                          unit, gport, (void *)&vent_member_array[idx]);
   6137                 if (BCM_FAILURE(rv)) {
   6138                     goto cleanup;
   6139                 }
   6140             } else {
   6141                 rv = BCM_E_PORT;
   6142                 goto cleanup;
   6143             }
   6144         }
   6145     }
   6146 
   6147     cnt = 0;
   6148     for (index = index_min; index <= index_max; index++) {
   6149         int is_valid = 0;
   6150         vent = soc_mem_table_idx_to_pointer(
   6151                    unit, mem, void *, vt_buf, index);
   6152 
   6153         if (soc_feature(unit, soc_feature_base_valid)) {
   6154             is_valid = soc_mem_field32_get(unit, mem, vent, BASE_VALID_0f) == 3
   6155                     && soc_mem_field32_get(unit, mem, vent, BASE_VALID_1f) == 7;
   6156         } else {
   6157             is_valid = soc_mem_field32_get(unit, mem, vent, VALIDf);
   6158         }
   6159         if (!is_valid) {
   6160             continue;
   6161         }
   6162         action = soc_mem_field32_get(unit, mem, vent, VIF__MPLS_ACTIONf);
   6163         if (action != 1) {
   6164             continue; /* Entry is not for an SVP */
   6165         }
   6166         tmp_vp = soc_mem_field32_get(unit, mem, vent, VIF__SOURCE_VPf);
   6167         if (vp != tmp_vp) {
   6168             continue;
   6169         }
   6170 
   6171         matched = 1;
   6172         for (idx = 0; idx < member_count; idx++) {
   6173             rv = _soc_mem_cmp_vlan_xlate_tr(unit, (void *)vent,
   6174                                             (void *)&vent_member_array[idx]);
   6175             /*
   6176              * the key of vent is equl to the key of one entry of vp lag member.
   6177              * So, this vent is not a matched entry.
   6178              */
   6179             if (rv == 0) {
   6180                 matched = 0;
   6181                 break;
   6182             }
   6183         }
   6184         if (!matched) {
   6185             continue;
   6186         }
   6187 
   6188         if ((size > 0) && (size > cnt)) {
   6189             key_type_value = (int)soc_mem_field32_get(unit, mem, vent,
   6190                                                       KEY_TYPEf);
   6191             rv = _bcm_esw_vlan_xlate_key_type_get(unit, key_type_value,
   6192                                                   &key_type);
   6193             if (BCM_FAILURE(rv)) {
   6194                 goto cleanup;
   6195             }
   6196             sal_memset(match_array, 0, sizeof(bcm_port_match_info_t));
   6197             match_array->match = BCM_PORT_MATCH_INVALID;
   6198             switch(key_type) {
   6199                 case VLXLT_HASH_KEY_TYPE_VIF_VLAN:
   6200                     if (match_array->match == BCM_PORT_MATCH_INVALID) {
   6201                         match_array->match =
   6202                             BCM_PORT_MATCH_PORT_EXTENDED_PORT_VID_VLAN;
   6203                         match_vlan = soc_mem_field32_get(unit, mem, vent,
   6204                                                          VIF__VLANf);
   6205                         match_array->match_vlan = match_vlan;
   6206                     }
   6207                 case VLXLT_HASH_KEY_TYPE_VIF:
   6208                     if (match_array->match == BCM_PORT_MATCH_INVALID) {
   6209                         match_array->match =
   6210                             BCM_PORT_MATCH_PORT_EXTENDED_PORT_VID;
   6211                         match_array->match_vlan = BCM_VLAN_NONE;
   6212                     }
   6213 
   6214                     src_vif = soc_mem_field32_get(unit, mem, vent,
   6215                                                   VIF__SRC_VIFf);
   6216                     if (soc_mem_field32_get(unit, mem, vent, VIF__Tf)) {
   6217                         BCM_GPORT_TRUNK_SET(
   6218                             match_gport,
   6219                             soc_mem_field32_get(unit, mem, vent, VIF__TGIDf));
   6220                     } else {
   6221                         mod_in = soc_mem_field32_get(unit, mem, vent,
   6222                                                      VIF__MODULE_IDf);
   6223                         port_in = soc_mem_field32_get(unit, mem, vent,
   6224                                                       VIF__PORT_NUMf);
   6225                         rv = _bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
   6226                                                      mod_in,port_in,
   6227                                                      &mod_out, &port_out);
   6228                         BCM_GPORT_MODPORT_SET(match_gport, mod_out, port_out);
   6229                     }
   6230                     match_array->port = match_gport;
   6231                     match_array->extended_port_vid = src_vif;
   6232                     match_array++;
   6233                     break;
   6234                 default:
   6235                     rv = BCM_E_PARAM;
   6236                     goto cleanup;
   6237             }
   6238         }
   6239         cnt++;
   6240     }
   6241     *count = cnt;
   6242 cleanup:
   6243     if (vt_buf != NULL) {
   6244         soc_cm_sfree(unit, vt_buf);
   6245     }
   6246     if (member_array != NULL) {
   6247         sal_free(member_array);
   6248     }
   6249     if (vent_member_array != NULL) {
   6250         sal_free(vent_member_array);
   6251     }
   6252     soc_mem_unlock(unit, mem);
   6253     return rv;
   6254 }
   6255 
   6256 /*
   6257  * Function:
   6258  *	bcm_td2_vp_lag_get
   6259  * Purpose:
   6260  *      Return information of given VP LAG.
   6261  * Parameters:
   6262  *      unit   - SOC unit number.
   6263  *      tid    - Trunk ID.
   6264  *      trunk_info   - (OUT) Place to store returned VP LAG info.
   6265  *      member_max   - (IN) Size of member_array.
   6266  *      member_array - (OUT) Place to store returned VP LAG members.
   6267  *      member_count - (OUT) Place to store returned number of VP LAG members.
   6268  * Returns:
   6269  *      BCM_E_XXX
   6270  */
   6271 int
   6272 bcm_td2_vp_lag_get(int unit, bcm_trunk_t tid, bcm_trunk_info_t *trunk_info,
   6273         int member_max, bcm_trunk_member_t *member_array, int *member_count)
   6274 {
   6275     int vp_lag_id;
   6276     ecmp_count_entry_t l3_ecmp_count_entry;
   6277     ecmp_entry_t l3_ecmp_entry;
   6278     int base_ptr, vp_count;
   6279     int i;
   6280     int vp;
   6281     bcm_gport_t gport;
   6282     int ecmp_idx;
   6283     int rv = BCM_E_NONE;
   6284 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
   6285 #if defined(BCM_TRIDENT3_SUPPORT)
   6286     uint8 protected_ecmp = 0;
   6287     uint32 alloc_sz = 0;
   6288     soc_esw_ecmp_group_info_t grp_info = {0};
   6289     soc_esw_ecmp_member_info_t *mem_array = NULL;
   6290 #endif /* BCM_TRIDENT3_SUPPORT */
   6291 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
   6292 
   6293     VP_LAG_INIT_CHECK(unit);
   6294 
   6295     BCM_IF_ERROR_RETURN(_bcm_td2_tid_to_vp_lag_id(unit, tid, &vp_lag_id)); 
   6296     if (!VP_LAG_USED_GET(unit, vp_lag_id)) {
   6297         return BCM_E_NOT_FOUND;
   6298     }
   6299 
   6300     if ((member_max > 0) && (NULL == member_array)) {
   6301         return BCM_E_PARAM;
   6302     }
   6303     if ((member_max > 0) && (NULL == member_count)) {
   6304         return BCM_E_PARAM;
   6305     }
   6306 
   6307     if (NULL != trunk_info) {
   6308         bcm_trunk_info_t_init(trunk_info);
   6309         trunk_info->psc = BCM_TRUNK_PSC_PORTFLOW;
   6310         trunk_info->dlf_index = VP_LAG_GROUP_INFO(unit, vp_lag_id).non_uc_index;
   6311         trunk_info->mc_index = VP_LAG_GROUP_INFO(unit, vp_lag_id).non_uc_index;
   6312         trunk_info->ipmc_index = VP_LAG_GROUP_INFO(unit, vp_lag_id).non_uc_index;
   6313     }
   6314 
   6315     /* Get VP LAG members */
   6316     if ((VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member) ||
   6317         (VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp)) {
   6318         ecmp_idx = _td2_vp_lag_info[unit]->base_ecmp_idx + vp_lag_id; 
   6319         if (VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member) {
   6320             SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_idx,
   6321                         &l3_ecmp_count_entry));
   6322             base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, &l3_ecmp_count_entry,
   6323                     BASE_PTRf);
   6324             vp_count = 1 + soc_L3_ECMP_COUNTm_field32_get(unit, &l3_ecmp_count_entry,
   6325                     COUNTf);
   6326             if (vp_count < 1) {
   6327                 return BCM_E_INTERNAL;
   6328             }
   6329         } else {
   6330             vp_count = 0;
   6331             base_ptr = (1 << soc_mem_field_length(unit, L3_ECMP_COUNTm, BASE_PTRf)) - 1;
   6332         }
   6333 
   6334         if (member_max == 0) {
   6335             if (NULL != member_count) {
   6336                 *member_count = vp_count +
   6337                                 VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp;
   6338             }
   6339         } else {
   6340 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
   6341 #if defined(BCM_TRIDENT3_SUPPORT)
   6342             if (soc_esw_ecmp_protected_enabled(unit)) {
   6343                 protected_ecmp = 1;
   6344                 alloc_sz = (vp_count * sizeof(soc_esw_ecmp_member_info_t));
   6345                 mem_array = sal_alloc(alloc_sz, "NH array");
   6346                 if (NULL == mem_array) {
   6347                     goto exit;
   6348                 }
   6349 
   6350                 SOC_ESW_ECMP_LOCK(unit);
   6351                 sal_memset(mem_array, 0, alloc_sz);
   6352                 grp_info.ecmp_grp = ecmp_idx;
   6353                 grp_info.vp_lag = 1;
   6354                 rv = soc_esw_ecmp_protected_grp_get(unit, &grp_info, mem_array);
   6355                 if (BCM_FAILURE(rv)) {
   6356                     SOC_ESW_ECMP_UNLOCK(unit);
   6357                     goto exit;
   6358                 }
   6359                 SOC_ESW_ECMP_UNLOCK(unit);
   6360             }
   6361 #endif /* BCM_TRIDENT3_SUPPORT */
   6362 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
   6363 
   6364             *member_count = 0;
   6365             for (i = 0; i < vp_count && i < member_max; i++) {
   6366 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
   6367 #if defined(BCM_TRIDENT3_SUPPORT)
   6368                 if (protected_ecmp == 1) {
   6369                     vp = mem_array[i].dvp;
   6370                 } else
   6371 #endif /* BCM_TRIDENT3_SUPPORT */
   6372 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
   6373                 {
   6374                     rv = READ_L3_ECMPm(unit, MEM_BLOCK_ANY,
   6375                                        base_ptr + i, &l3_ecmp_entry);
   6376                     if (BCM_FAILURE(rv)) {
   6377                         goto exit;
   6378                     }
   6379                     vp = soc_L3_ECMPm_field32_get(unit, &l3_ecmp_entry, DVPf);
   6380                 }
   6381 
   6382                 /* Derive VP's GPORT ID */
   6383                 if (_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) {
   6384                     BCM_GPORT_VLAN_PORT_ID_SET(gport, vp);
   6385                 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   6386                     BCM_GPORT_NIV_PORT_ID_SET(gport, vp);
   6387                 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeExtender)) {
   6388                     BCM_GPORT_EXTENDER_PORT_ID_SET(gport, vp);
   6389                 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeVxlan)) {
   6390                     BCM_GPORT_VXLAN_PORT_ID_SET(gport, vp);
   6391                 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeMim)) {
   6392                     BCM_GPORT_MIM_PORT_ID_SET(gport, vp);
   6393                 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeL2Gre)) {
   6394                     BCM_GPORT_L2GRE_PORT_ID_SET(gport, vp);
   6395                 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeMpls)) {
   6396                     BCM_GPORT_MPLS_PORT_ID_SET(gport, vp);
   6397                 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeFlow)) {
   6398                     BCM_GPORT_FLOW_PORT_ID_SET(gport, vp);
   6399                 } else {
   6400                     rv = BCM_E_INTERNAL;
   6401                     goto exit;
   6402                 }
   6403 
   6404                 bcm_trunk_member_t_init(&member_array[i]);
   6405                 member_array[i].gport = gport;
   6406                 (*member_count)++;
   6407             }
   6408 
   6409             /* retrieve member VPs which are not programmed to L3_ECMP table */
   6410             for (i = 0; i < VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp; i++) {
   6411                 if (*member_count >= member_max) {
   6412                     break;
   6413                 }
   6414                 bcm_trunk_member_t_init(&member_array[*member_count]);
   6415                 member_array[*member_count].gport
   6416                     = VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp[i];
   6417                 member_array[*member_count].flags = BCM_TRUNK_MEMBER_EGRESS_DISABLE;
   6418                 (*member_count)++;
   6419             }
   6420         }
   6421     } else { /* VP LAG has no members */
   6422         if (NULL != member_count) {
   6423             *member_count = 0;
   6424         }
   6425     }
   6426 
   6427 exit:
   6428 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
   6429 #if defined(BCM_TRIDENT3_SUPPORT)
   6430     if (protected_ecmp == 1) {
   6431         if (mem_array != NULL) {
   6432             sal_free(mem_array);
   6433         }
   6434     }
   6435 #endif /* BCM_TRIDENT3_SUPPORT */
   6436 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
   6437 
   6438     return rv;
   6439 }
   6440 
   6441 /*
   6442  * Function:
   6443  *      bcm_td2_vp_lag_find
   6444  * Description:
   6445  *      Get trunk id that contains the given VP
   6446  * Parameters:
   6447  *      unit - SOC unit number
   6448  *      gport - VP GPORT ID
   6449  *      tid  - (OUT) Trunk id
   6450  * Returns:
   6451  *      BCM_E_xxxx
   6452  */
   6453 int
   6454 bcm_td2_vp_lag_find(int unit, bcm_gport_t gport, bcm_trunk_t *tid)
   6455 {
   6456     int vp_lag_vp;
   6457     ing_dvp_table_entry_t ing_dvp_entry;
   6458     int vp_lag_valid;
   6459     int vp_lag_id;
   6460     int vp_id_min = -1;
   6461 
   6462     VP_LAG_INIT_CHECK(unit);
   6463 
   6464     if (!BCM_GPORT_IS_SET(gport)) {
   6465         return BCM_E_PORT;
   6466     }
   6467 
   6468     /* Get the VP value representing VP LAG from VP's match entry, instead of
   6469      * getting the VP LAG from EGR_DVP_ATTRIBUTE table, since only the
   6470      * multicast capable VP LAGs can be retrieved from EGR_DVP_ATTRIBUTE.
   6471      */
   6472     if (BCM_GPORT_IS_VLAN_PORT(gport)) {
   6473         BCM_IF_ERROR_RETURN
   6474             (_bcm_esw_vlan_port_source_vp_lag_get(unit, gport, &vp_lag_vp));
   6475     } else if (BCM_GPORT_IS_NIV_PORT(gport)) {
   6476         BCM_IF_ERROR_RETURN
   6477             (_bcm_esw_niv_port_source_vp_lag_get(unit, gport, &vp_lag_vp));
   6478     } else if (BCM_GPORT_IS_EXTENDER_PORT(gport)) {
   6479         BCM_IF_ERROR_RETURN
   6480             (_bcm_esw_extender_port_source_vp_lag_get(unit, gport, &vp_lag_vp));
   6481     } else if (BCM_GPORT_IS_VXLAN_PORT(gport)) {
   6482         BCM_IF_ERROR_RETURN
   6483             (_bcm_esw_vxlan_port_source_vp_lag_get(unit, gport, &vp_lag_vp));
   6484     } else if (BCM_GPORT_IS_MIM_PORT(gport)) {
   6485         BCM_IF_ERROR_RETURN
   6486             (_bcm_esw_mim_port_source_vp_lag_get(unit, gport, &vp_lag_vp));
   6487     } else if (BCM_GPORT_IS_L2GRE_PORT(gport)) {
   6488         BCM_IF_ERROR_RETURN(
   6489             _bcm_esw_l2gre_port_source_vp_lag_get(unit, gport, &vp_lag_vp));
   6490     } else if (BCM_GPORT_IS_MPLS_PORT(gport)) {
   6491         BCM_IF_ERROR_RETURN(
   6492             _bcm_esw_mpls_port_source_vp_lag_get(unit, gport, &vp_lag_vp));
   6493     } else if (BCM_GPORT_IS_FLOW_PORT(gport)) {
   6494         BCM_IF_ERROR_RETURN(
   6495             _bcm_esw_flow_port_source_vp_lag_get(unit, gport, &vp_lag_vp));
   6496     } else {
   6497         return BCM_E_PORT;
   6498     }
   6499 
   6500     /* Get VP LAG ID from ING_DVP_TABLE */
   6501     SOC_IF_ERROR_RETURN(READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp_lag_vp,
   6502                 &ing_dvp_entry));
   6503     vp_lag_valid = soc_ING_DVP_TABLEm_field32_get(unit, &ing_dvp_entry,
   6504             ENABLE_VPLAG_RESOLUTIONf);
   6505     if (!vp_lag_valid) {
   6506         return BCM_E_INTERNAL;
   6507     }
   6508     vp_lag_id = soc_ING_DVP_TABLEm_field32_get(unit, &ing_dvp_entry,
   6509             DVP_GROUP_PTRf);
   6510     vp_lag_id -=  _td2_vp_lag_info[unit]->base_ecmp_idx;
   6511 
   6512     /* Convert VP LAG ID to trunk ID */
   6513     BCM_IF_ERROR_RETURN(
   6514         _bcm_esw_trunk_chip_info_vp_resource_get(unit, &vp_id_min,
   6515                                                  NULL, NULL));
   6516     *tid = vp_lag_id + vp_id_min;
   6517 
   6518     return BCM_E_NONE;
   6519 }
   6520 
   6521 /*
   6522  * Function:
   6523  *	bcm_td2_tid_to_vp_lag_vp
   6524  * Purpose:
   6525  *      Convert trunk ID to the VP value representing VP LAG.
   6526  * Parameters:
   6527  *      unit  - SOC unit number
   6528  *      tid   - Trunk ID
   6529  *      vp_lag_vp - (OUT) VP value
   6530  * Returns:
   6531  *      BCM_E_xxx
   6532  */
   6533 int
   6534 bcm_td2_tid_to_vp_lag_vp(int unit, bcm_trunk_t tid, int *vp_lag_vp)
   6535 {
   6536     int vp_lag_id;
   6537 
   6538     VP_LAG_INIT_CHECK(unit);
   6539 
   6540     BCM_IF_ERROR_RETURN(_bcm_td2_tid_to_vp_lag_id(unit, tid, &vp_lag_id)); 
   6541     if (!VP_LAG_USED_GET(unit, vp_lag_id)) {
   6542         return BCM_E_NOT_FOUND;
   6543     }
   6544 
   6545     *vp_lag_vp = VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id;
   6546 
   6547     return BCM_E_NONE;
   6548 }
   6549 
   6550 /*
   6551  * Function:
   6552  *	bcm_td2_vp_lag_vp_to_tid
   6553  * Purpose:
   6554  *      Convert the VP value representing a VP LAG to trunk ID.
   6555  * Parameters:
   6556  *      unit      - SOC unit number
   6557  *      vp_lag_vp - VP value
   6558  *      tid       - (OUT) Trunk ID
   6559  * Returns:
   6560  *      BCM_E_xxx
   6561  */
   6562 int
   6563 bcm_td2_vp_lag_vp_to_tid(int unit, int vp_lag_vp, bcm_trunk_t *tid)
   6564 {
   6565     ing_dvp_table_entry_t ing_dvp_entry;
   6566     int vp_lag_valid;
   6567     int vp_lag_id;
   6568     int vp_id_min = -1;
   6569 
   6570     VP_LAG_INIT_CHECK(unit);
   6571 
   6572     if (!_bcm_vp_used_get(unit, vp_lag_vp, _bcmVpTypeVpLag)) {
   6573         return BCM_E_NOT_FOUND;
   6574     }
   6575 
   6576     /* Get VP LAG ID from ING_DVP_TABLE */
   6577     SOC_IF_ERROR_RETURN(READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp_lag_vp,
   6578                 &ing_dvp_entry));
   6579     vp_lag_valid = soc_ING_DVP_TABLEm_field32_get(unit, &ing_dvp_entry,
   6580             ENABLE_VPLAG_RESOLUTIONf);
   6581     if (!vp_lag_valid) {
   6582         return BCM_E_INTERNAL;
   6583     }
   6584     vp_lag_id = soc_ING_DVP_TABLEm_field32_get(unit, &ing_dvp_entry,
   6585             DVP_GROUP_PTRf);
   6586     vp_lag_id -=  _td2_vp_lag_info[unit]->base_ecmp_idx;
   6587 
   6588     /* Convert VP LAG ID to trunk ID */
   6589     BCM_IF_ERROR_RETURN(
   6590         _bcm_esw_trunk_chip_info_vp_resource_get(unit, &vp_id_min,
   6591                                                  NULL, NULL));
   6592     *tid = vp_lag_id + vp_id_min;
   6593 
   6594     return BCM_E_NONE;
   6595 }
   6596 
   6597 /*
   6598  * Function:
   6599  *     bcm_td2_vp_lag_status_get
   6600  * Purpose:
   6601  *     Get VP LAG status.
   6602  * Parameters:
   6603  *     unit - SOC unit number
   6604  *     vp_lag_id - VP LAG ID
   6605  *     is_vp_lag - (OUT) Indicates if the given vp_lag_id is a valid VP LAG ID.
   6606  *     is_used - (OUT) Indicates if the given vp_lag_id is being used.
   6607  *     has_member - (OUT) Indicates if the given vp_lag_id has members.
   6608  * Returns:
   6609  *      BCM_E_xxx
   6610  */
   6611 int
   6612 bcm_td2_vp_lag_status_get(int unit, int vp_lag_id, int *is_vp_lag,
   6613         int *is_used, int *has_member)
   6614 {
   6615     if (NULL == is_vp_lag || NULL == is_used || NULL == has_member) {
   6616         return BCM_E_PARAM;
   6617     }
   6618 
   6619     *is_vp_lag = FALSE;
   6620     *is_used = FALSE;
   6621     *has_member = FALSE;
   6622 
   6623     if (vp_lag_id >= 0 && vp_lag_id < MAX_VP_LAGS(unit)) {
   6624         *is_vp_lag = TRUE;
   6625         if (VP_LAG_USED_GET(unit, vp_lag_id)) {
   6626             *is_used = TRUE;
   6627             if (VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member) {
   6628                 *has_member = TRUE;
   6629             }
   6630         }
   6631     }
   6632 
   6633     return BCM_E_NONE;
   6634 }
   6635 
   6636 /*
   6637  * Function:
   6638  *     _bcm_esw_num_vp_trunk_groups
   6639  * Purpose:
   6640  *     Get Number of VP LAG groups supported.
   6641  * Parameters:
   6642  *     unit - SOC unit number
   6643  * Returns:
   6644  *      Number of VP LAG groups supported.
   6645  */
   6646 int _bcm_esw_num_vp_trunk_groups(int unit)
   6647 {
   6648     return MAX_VP_LAGS(unit);
   6649 }
   6650 
   6651 /*
   6652  * Function:
   6653  *      bcm_td2_vp_lag_port_learn_set
   6654  * Purpose:
   6655  *      Set the CML bits for a vp_lag port.
   6656  * Parameters:
   6657  *      unit  - SOC unit number
   6658  *      tid   - Trunk ID
   6659  *      flags - learning control flags
   6660  * Returns:
   6661  *      BCM_E_XXX
   6662  */
   6663 int
   6664 bcm_td2_vp_lag_port_learn_set(int unit, bcm_trunk_t tid, uint32 flags)
   6665 {
   6666     int vp, cml = 0, rv = BCM_E_NONE;
   6667     source_vp_entry_t svp;
   6668 
   6669     cml = 0;
   6670     if (!(flags & BCM_PORT_LEARN_FWD)) {
   6671        cml |= (1 << 0);
   6672     }
   6673     if (flags & BCM_PORT_LEARN_CPU) {
   6674        cml |= (1 << 1);
   6675     }
   6676     if (flags & BCM_PORT_LEARN_PENDING) {
   6677        cml |= (1 << 2);
   6678     }
   6679     if (flags & BCM_PORT_LEARN_ARL) {
   6680        cml |= (1 << 3);
   6681     }
   6682 
   6683     /* Get the VP index from the gport */
   6684     BCM_IF_ERROR_RETURN(
   6685         bcm_td2_tid_to_vp_lag_vp(unit, tid, &vp));
   6686 
   6687     MEM_LOCK(unit, SOURCE_VPm);
   6688     /* Be sure the entry is used and is set for Vp Lag */
   6689     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeVpLag)) {
   6690         MEM_UNLOCK(unit, SOURCE_VPm);
   6691         return BCM_E_NOT_FOUND;
   6692     }
   6693     rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp);
   6694     if (rv < 0) {
   6695         MEM_UNLOCK(unit, SOURCE_VPm);
   6696         return rv;
   6697     }
   6698 
   6699     soc_SOURCE_VPm_field32_set(unit, &svp, CML_FLAGS_MOVEf, cml);
   6700     soc_SOURCE_VPm_field32_set(unit, &svp, CML_FLAGS_NEWf, cml);
   6701     rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp);
   6702     MEM_UNLOCK(unit, SOURCE_VPm);
   6703     return rv;
   6704 }
   6705 
   6706 /*
   6707  * Function:
   6708  *      bcm_td2_vp_lag_port_learn_get
   6709  * Purpose:
   6710  *      Get the CML bits for a VxLAN port
   6711  * Parameters:
   6712  *      unit  - SOC unit number
   6713  *      tid   - Trunk ID
   6714  *      flags - learning control flags (OUT)
   6715  * Returns:
   6716  *      BCM_E_XXX
   6717  */
   6718 int
   6719 bcm_td2_vp_lag_port_learn_get(int unit, bcm_trunk_t tid, uint32 *flags)
   6720 {
   6721     int rv, vp, cml = 0;
   6722     source_vp_entry_t svp;
   6723 
   6724     /* Get the VP index from the gport */
   6725     BCM_IF_ERROR_RETURN(
   6726         bcm_td2_tid_to_vp_lag_vp(unit, tid, &vp));
   6727 
   6728     /* Be sure the entry is used and is set for VP Lag */
   6729     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeVpLag)) {
   6730         return BCM_E_NOT_FOUND;
   6731     }
   6732     rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp);
   6733     if (rv < 0) {
   6734         return rv;
   6735     }
   6736 
   6737     cml = soc_SOURCE_VPm_field32_get(unit, &svp, CML_FLAGS_NEWf);
   6738 
   6739     *flags = 0;
   6740     if (!(cml & (1 << 0))) {
   6741        *flags |= BCM_PORT_LEARN_FWD;
   6742     }
   6743     if (cml & (1 << 1)) {
   6744        *flags |= BCM_PORT_LEARN_CPU;
   6745     }
   6746     if (cml & (1 << 2)) {
   6747        *flags |= BCM_PORT_LEARN_PENDING;
   6748     }
   6749     if (cml & (1 << 3)) {
   6750        *flags |= BCM_PORT_LEARN_ARL;
   6751     }
   6752     return BCM_E_NONE;
   6753 }
   6754 
   6755 #ifdef BCM_WARM_BOOT_SUPPORT
   6756 
   6757 /*
   6758  * Function:
   6759  *      _bcm_td2_vp_lag_egr_dis_vp_scache_size_get
   6760  * Purpose:
   6761  *      Get VP LAGs' egress disabled member VPs' software state size.
   6762  * Parameters:
   6763  *      unit - (IN) SOC unit number.
   6764  *      size - (out) Number of bytes
   6765  * Returns:
   6766  *      BCM_E_xxx
   6767  */
   6768 int
   6769 _bcm_td2_vp_lag_egr_dis_vp_scache_size_get(int unit, int *size)
   6770 {
   6771     int num_egr_dis_vp = 0;
   6772     int i;
   6773 
   6774     if (size == NULL) {
   6775         return BCM_E_PARAM;
   6776     }
   6777 
   6778     /* num of egr_dis_vp for each VP LAG */
   6779     *size += MAX_VP_LAGS(unit) * sizeof(int);
   6780 
   6781     for (i = 0; i < MAX_VP_LAGS(unit); i++) {
   6782         /* space for egr_dis_vp list */
   6783         if (VP_LAG_USED_GET(unit, i)) {
   6784             num_egr_dis_vp += VP_LAG_MEMBER_INFO(unit, i).num_egr_dis_vp;
   6785         }
   6786     }
   6787 
   6788     *size += num_egr_dis_vp * sizeof(bcm_gport_t);
   6789 
   6790     return BCM_E_NONE;
   6791 }
   6792 
   6793 /*
   6794  * Function:
   6795  *      _bcm_td2_vp_lag_egr_dis_vp_scache_recover
   6796  * Purpose:
   6797  *      Recover VP LAGs' egress disabled member VPs' state from scache.
   6798  * Parameters:
   6799  *      unit - (IN) SOC unit number.
   6800  * Returns:
   6801  *      BCM_E_xxx
   6802  */
   6803 int
   6804 _bcm_td2_vp_lag_egr_dis_vp_scache_recover(int unit, uint8 **scache_ptr)
   6805 {
   6806     int vp_lag_id;
   6807     int num_egr_dis_vp;
   6808     bcm_gport_t *egr_dis_vp;
   6809     int i;
   6810 
   6811     if (scache_ptr == NULL || *scache_ptr == NULL) {
   6812         return BCM_E_PARAM;
   6813     }
   6814 
   6815     for (vp_lag_id = 0; vp_lag_id < MAX_VP_LAGS(unit); vp_lag_id++) {
   6816         if (VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp != NULL) {
   6817             sal_free(VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp);
   6818         }
   6819 
   6820         num_egr_dis_vp = *(int*)*scache_ptr;
   6821         *scache_ptr += sizeof(int);
   6822         VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp = num_egr_dis_vp;
   6823         if (num_egr_dis_vp == 0) {
   6824             VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp = NULL;
   6825             continue;
   6826         }
   6827 
   6828         egr_dis_vp = sal_alloc(num_egr_dis_vp * sizeof(bcm_gport_t),
   6829                                 "VP LAG egress disabled member VP");
   6830         if (egr_dis_vp == NULL) {
   6831             return BCM_E_MEMORY;
   6832         }
   6833         VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp = egr_dis_vp;
   6834 
   6835         /* recover egr_dis_vp list */
   6836         for (i = 0; i < num_egr_dis_vp; i++) {
   6837             egr_dis_vp[i] = *(bcm_gport_t*)*scache_ptr;
   6838             *scache_ptr += sizeof(bcm_gport_t);
   6839         }
   6840     }
   6841 
   6842     return BCM_E_NONE;
   6843 }
   6844 
   6845 
   6846 /*
   6847  * Function:
   6848  *      _bcm_td2_vp_lag_egr_dis_vp_sync
   6849  * Purpose:
   6850  *      Record VP LAGs' egress disabled member VPs' state to scache.
   6851  * Parameters:
   6852  *      unit - (IN) SOC unit number.
   6853  * Returns:
   6854  *      BCM_E_xxx
   6855  */
   6856 int
   6857 _bcm_td2_vp_lag_egr_dis_vp_sync(int unit, uint8 **scache_ptr)
   6858 {
   6859     int vp_lag_id;
   6860     int i;
   6861 
   6862     if (scache_ptr == NULL || *scache_ptr == NULL) {
   6863         return BCM_E_PARAM;
   6864     }
   6865 
   6866     for (vp_lag_id = 0; vp_lag_id < MAX_VP_LAGS(unit); vp_lag_id++) {
   6867         *(int*)*scache_ptr = VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp;
   6868         *scache_ptr += sizeof(int);
   6869 
   6870         for (i = 0; i < VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp; i++) {
   6871             *(bcm_gport_t*)*scache_ptr = VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp[i];
   6872             *scache_ptr += sizeof(bcm_gport_t);
   6873         }
   6874     }
   6875 
   6876     return BCM_E_NONE;
   6877 }
   6878 
   6879 /*
   6880  * Function:
   6881  *      bcm_td2_vp_lag_reinit
   6882  * Purpose:
   6883  *      Recover VP LAG software state.
   6884  * Parameters:
   6885  *      unit - (IN) SOC unit number.
   6886  * Returns:
   6887  *      BCM_E_xxx
   6888  */
   6889 int
   6890 bcm_td2_vp_lag_reinit(int unit)
   6891 {
   6892     int rv = BCM_E_NONE;
   6893     soc_mem_t mem;
   6894     int entry_size;
   6895     int chunk_size, num_chunks, chunk_index;
   6896     int alloc_size;
   6897     uint8 *buf = NULL;
   6898     int i, j, entry_index_min, entry_index_max;
   6899     uint32 *buf_entry;
   6900     int vp_lag_id;
   6901     int vp;
   6902     int dvp;
   6903     ecmp_count_entry_t l3_ecmp_count_entry;
   6904     ecmp_entry_t l3_ecmp_entry;
   6905     int base_ptr;
   6906     int count_field;
   6907     int vp_count;
   6908     egr_vplag_member_entry_t egr_member_entry;
   6909     egr_vplag_group_entry_t egr_vplag_group_entry;
   6910     int egr_base_ptr;
   6911     int egr_vp_count;
   6912     int non_uc_member;
   6913     int stable_size;
   6914     _bcm_vp_info_t vp_info;
   6915 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
   6916 #if defined(BCM_TRIDENT3_SUPPORT)
   6917     uint8 protected_ecmp = 0;
   6918     uint32 alloc_sz = 0;
   6919     soc_esw_ecmp_group_info_t grp_info = {0};
   6920     soc_esw_ecmp_member_info_t *mem_array = NULL;
   6921 #endif /* BCM_TRIDENT3_SUPPORT */
   6922 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
   6923 
   6924     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
   6925 
   6926     /* Traverse ING_DVP_TABLE to find valid VP LAGs */
   6927     mem = ING_DVP_TABLEm;
   6928     entry_size = sizeof(ing_dvp_table_entry_t);
   6929 
   6930     chunk_size = 1024;
   6931     num_chunks = soc_mem_index_count(unit, mem) / chunk_size;
   6932     if (soc_mem_index_count(unit, mem) % chunk_size) {
   6933         num_chunks++;
   6934     }
   6935 
   6936     alloc_size = entry_size * chunk_size;
   6937     buf = soc_cm_salloc(unit, alloc_size, "ING_DVP_TABLE buffer");
   6938     if (NULL == buf) {
   6939         rv = BCM_E_MEMORY;
   6940         goto cleanup;
   6941     }
   6942 
   6943     for (chunk_index = 0; chunk_index < num_chunks; chunk_index++) {
   6944 
   6945         /* Get a chunk of entries */
   6946         entry_index_min = chunk_index * chunk_size;
   6947         entry_index_max = entry_index_min + chunk_size - 1;
   6948         if (entry_index_max > soc_mem_index_max(unit, mem)) {
   6949             entry_index_max = soc_mem_index_max(unit, mem);
   6950         }
   6951         rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY,
   6952                 entry_index_min, entry_index_max, buf);
   6953         if (SOC_FAILURE(rv)) {
   6954             goto cleanup;
   6955         }
   6956 
   6957         /* Read each entry of the chunk to extract VP LAG info */
   6958         for (i = 0; i < (entry_index_max - entry_index_min + 1); i++) {
   6959             buf_entry = soc_mem_table_idx_to_pointer(unit,
   6960                     mem, uint32 *, buf, i);
   6961             if (soc_mem_field32_get(unit, mem, buf_entry,
   6962                         ENABLE_VPLAG_RESOLUTIONf) == 0) {
   6963                 continue;
   6964             }
   6965             vp_lag_id = soc_mem_field32_get(unit, mem, buf_entry,
   6966                     DVP_GROUP_PTRf);
   6967             vp_lag_id -=  _td2_vp_lag_info[unit]->base_ecmp_idx;
   6968             if (vp_lag_id >= MAX_VP_LAGS(unit)) {
   6969                 /* The configuration property MAX_VP_LAGS was not
   6970                  *  set correctly.
   6971                  */
   6972                 rv = BCM_E_CONFIG;
   6973                 goto cleanup;
   6974             }
   6975 
   6976             /* Recover bitmap of VP LAG IDs */
   6977             VP_LAG_USED_SET(unit, vp_lag_id);
   6978 
   6979             /* Recover VP LAG's VP value */
   6980             vp = entry_index_min + i;
   6981             VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id = vp;
   6982             if ((stable_size == 0) || SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) {
   6983                 _bcm_vp_info_init(&vp_info);
   6984                 vp_info.vp_type = _bcmVpTypeVpLag;
   6985                 rv = _bcm_vp_used_set(unit, vp, vp_info);
   6986                 if (BCM_FAILURE(rv)) {
   6987                     goto cleanup;
   6988                 }
   6989             } else {
   6990                 /* In level 2 warm boot, the VP LAG VP bitmap should have been
   6991                  * recovered by virtual_init.
   6992                  */
   6993                  if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeVpLag)) {
   6994                      rv = BCM_E_INTERNAL;
   6995                      goto cleanup;
   6996                  }
   6997             }
   6998 
   6999             /* Recover if VP LAG has any members */
   7000             rv = READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, vp_lag_id,
   7001                     &l3_ecmp_count_entry);
   7002             if (SOC_FAILURE(rv)) {
   7003                 goto cleanup;
   7004             }
   7005             base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit,
   7006                     &l3_ecmp_count_entry, BASE_PTRf);
   7007             count_field = soc_L3_ECMP_COUNTm_field32_get(unit,
   7008                     &l3_ecmp_count_entry, COUNTf);
   7009             vp_count = count_field + 1;
   7010             if (base_ptr == ((1 << soc_mem_field_length(unit,
   7011                                 L3_ECMP_COUNTm, BASE_PTRf)) - 1) &&
   7012                 count_field == ((1 << soc_mem_field_length(unit,
   7013                                 L3_ECMP_COUNTm, COUNTf)) - 1)) {
   7014                 /* BASE_PTR and COUNT fields being all ones indicates
   7015                  * this VP LAG has no members.
   7016                  */
   7017                 VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member = FALSE;
   7018             } else {
   7019                 VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member = TRUE;
   7020                 BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ecmp),
   7021                         base_ptr, vp_count);
   7022             }
   7023 
   7024             if (!VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member) {
   7025                 /* obviously no vp specified since H/W is empty */
   7026                 VP_LAG_GROUP_INFO(unit, vp_lag_id).non_uc_index =
   7027                     BCM_TRUNK_UNSPEC_INDEX;
   7028                 continue;
   7029             }
   7030 
   7031             /* Recover non-unicast member index and bitmap of
   7032              * used entries of EGR_VPLAG_MEMBER table
   7033              */
   7034             if (vp_lag_id >= soc_mem_index_count(unit, EGR_VPLAG_GROUPm)) {
   7035                 /* VP LAG is unicast only */
   7036                 VP_LAG_GROUP_INFO(unit, vp_lag_id).non_uc_index =
   7037                     BCM_TRUNK_UNSPEC_INDEX;
   7038             } else {
   7039                 rv = READ_EGR_VPLAG_GROUPm(unit, MEM_BLOCK_ANY, vp_lag_id,
   7040                         &egr_vplag_group_entry);
   7041                 if (SOC_FAILURE(rv)) {
   7042                     goto cleanup;
   7043                 }
   7044                 egr_base_ptr = soc_EGR_VPLAG_GROUPm_field32_get(unit,
   7045                         &egr_vplag_group_entry, BASE_PTRf);
   7046                 egr_vp_count = 1 + soc_EGR_VPLAG_GROUPm_field32_get(unit,
   7047                         &egr_vplag_group_entry, COUNTf);
   7048                 VP_LAG_EGR_MEMBER_USED_SET_RANGE(unit, egr_base_ptr,
   7049                         egr_vp_count);
   7050                 if (egr_vp_count == 1 && vp_count > egr_vp_count) {
   7051                     rv = READ_EGR_VPLAG_MEMBERm(unit, MEM_BLOCK_ANY,
   7052                             egr_base_ptr, &egr_member_entry);
   7053                     if (SOC_FAILURE(rv)) {
   7054                         goto cleanup;
   7055                     }
   7056 
   7057 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
   7058 #if defined(BCM_TRIDENT3_SUPPORT)
   7059                     if (soc_esw_ecmp_protected_enabled(unit)) {
   7060                         protected_ecmp = 1;
   7061                         alloc_sz = (vp_count * sizeof(soc_esw_ecmp_member_info_t));
   7062                         mem_array = sal_alloc(alloc_sz, "NH array");
   7063                         if (NULL == mem_array) {
   7064                             goto cleanup;
   7065                         }
   7066 
   7067                         SOC_ESW_ECMP_LOCK(unit);
   7068                         sal_memset(mem_array, 0, alloc_sz);
   7069                         grp_info.ecmp_grp = vp_lag_id;
   7070                         grp_info.vp_lag = 1;
   7071                         rv = soc_esw_ecmp_protected_grp_get(unit, &grp_info, mem_array);
   7072                         if (BCM_FAILURE(rv)) {
   7073                             SOC_ESW_ECMP_UNLOCK(unit);
   7074                             goto cleanup;
   7075                         }
   7076                         SOC_ESW_ECMP_UNLOCK(unit);
   7077                     }
   7078 #endif /* BCM_TRIDENT3_SUPPORT */
   7079 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
   7080 
   7081                     non_uc_member = soc_EGR_VPLAG_MEMBERm_field32_get(unit,
   7082                             &egr_member_entry, DVPf);
   7083                     for (j = 0; j < vp_count; j++) {
   7084 
   7085 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
   7086 #if defined(BCM_TRIDENT3_SUPPORT)
   7087                         if (protected_ecmp == 1) {
   7088                             dvp = mem_array[i].dvp;
   7089                         } else
   7090 #endif /* BCM_TRIDENT3_SUPPORT */
   7091 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
   7092                         {
   7093                             rv = READ_L3_ECMPm(unit, MEM_BLOCK_ANY, base_ptr + j,
   7094                                                &l3_ecmp_entry);
   7095                             if (SOC_FAILURE(rv)) {
   7096                                 goto cleanup;
   7097                             }
   7098 
   7099                             dvp = soc_L3_ECMPm_field32_get(unit,
   7100                                                            &l3_ecmp_entry, DVPf);
   7101                         }
   7102                         if (non_uc_member == dvp) {
   7103                             VP_LAG_GROUP_INFO(unit, vp_lag_id).non_uc_index = j;
   7104                             break;
   7105                         }
   7106                     }
   7107                     if (j == vp_count) {
   7108                         /* non_uc_member not found */
   7109                         rv = BCM_E_INTERNAL;
   7110                         goto cleanup;
   7111                     }
   7112                 } else {
   7113                     VP_LAG_GROUP_INFO(unit, vp_lag_id).non_uc_index =
   7114                         BCM_TRUNK_UNSPEC_INDEX;
   7115                 }
   7116             }
   7117         }
   7118     }
   7119 
   7120 cleanup:
   7121     if (buf) {
   7122         soc_cm_sfree(unit, buf);
   7123     }
   7124 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
   7125 #if defined(BCM_TRIDENT3_SUPPORT)
   7126     if (protected_ecmp == 1) {
   7127         if (mem_array != NULL) {
   7128             sal_free(mem_array);
   7129         }
   7130     }
   7131 #endif /* BCM_TRIDENT3_SUPPORT */
   7132 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
   7133 
   7134     return rv;
   7135 }
   7136 
   7137 #endif /* BCM_WARM_BOOT_SUPPORT */
   7138 
   7139 #ifndef BCM_SW_STATE_DUMP_DISABLE
   7140 /*
   7141  * Function:
   7142  *     bcm_td2_vp_lag_sw_dump
   7143  * Purpose:
   7144  *     Displays VP LAG information maintained by software.
   7145  * Parameters:
   7146  *     unit - SOC unit number
   7147  * Returns:
   7148  *     None
   7149  */
   7150 void
   7151 bcm_td2_vp_lag_sw_dump(int unit)
   7152 {
   7153     bcm_trunk_chip_info_t trunk_chip_info;
   7154     int i;
   7155     int j;
   7156 
   7157     LOG_CLI((BSL_META_U(unit,
   7158                         "VP LAG Information:\n")));
   7159     LOG_CLI((BSL_META_U(unit,
   7160                         "  Max number of VP LAGs: %d\n"), MAX_VP_LAGS(unit)));
   7161 
   7162     (void)bcm_esw_trunk_chip_info_get(unit, &trunk_chip_info);
   7163     LOG_CLI((BSL_META_U(unit,
   7164                         "  VP LAG trunk ID min:   %d\n"), trunk_chip_info.vp_id_min));
   7165     LOG_CLI((BSL_META_U(unit,
   7166                         "  VP LAG trunk ID max:   %d\n"), trunk_chip_info.vp_id_max));
   7167     LOG_CLI((BSL_META_U(unit,
   7168                         "  VP LAG max members:    %d\n"), trunk_chip_info.vp_ports_max));
   7169 
   7170     for (i = 0; i < MAX_VP_LAGS(unit); i++) {
   7171         if (VP_LAG_USED_GET(unit, i)) {
   7172             LOG_CLI((BSL_META_U(unit,
   7173                                 "  VP LAG %d: vp_id = %d, "), i,
   7174                      VP_LAG_GROUP_INFO(unit, i).vp_id));
   7175             LOG_CLI((BSL_META_U(unit,
   7176                                 "has_member = %d, "),
   7177                      VP_LAG_GROUP_INFO(unit, i).has_member));
   7178             LOG_CLI((BSL_META_U(unit,
   7179                                 "num_egr_dis_vp = %d, "),
   7180                      VP_LAG_MEMBER_INFO(unit, i).num_egr_dis_vp));
   7181             LOG_CLI((BSL_META_U(unit,
   7182                                 "non_uc_index = %d"),
   7183                      VP_LAG_GROUP_INFO(unit, i).non_uc_index));
   7184             for (j = 0; j < VP_LAG_MEMBER_INFO(unit, i).num_egr_dis_vp; j++) {
   7185                 LOG_CLI((BSL_META_U(unit,
   7186                                     ", egr_dis_vp[%d] = %x"), j,
   7187                          VP_LAG_MEMBER_INFO(unit, i).egr_dis_vp[j]));
   7188             }
   7189             LOG_CLI((BSL_META_U(unit, "\n")));
   7190 
   7191         }
   7192     }
   7193 
   7194     return;
   7195 }
   7196 
   7197 #endif /* BCM_SW_STATE_DUMP_DISABLE */
   7198 
   7199 /*
   7200  * Function:
   7201  *      _bcm_esw_vplag_lock
   7202  * Purpose:
   7203  *     Lock VPLAG - if module was not initialized NOOP
   7204  *
   7205  * Parameters:
   7206  *      unit - (IN) Unit number.
   7207  * Returns:
   7208  *      BCM_E_XXX
   7209  * Notes:
   7210  */
   7211 int
   7212 _bcm_esw_vplag_lock(int unit)
   7213 {
   7214     if ((NULL != _td2_vp_lag_info[unit]) &&
   7215         (NULL != _td2_vp_lag_info[unit]->lock)) {
   7216         return sal_mutex_take(_td2_vp_lag_info[unit]->lock,
   7217                               sal_mutex_FOREVER);
   7218     }
   7219     return (BCM_E_NONE);
   7220 }
   7221 
   7222 /*
   7223  * Function:
   7224  *      _bcm_esw_vplag_unlock
   7225  * Purpose:
   7226  *     Unlock VPLAG - if module was not initialized NOOP
   7227  *
   7228  * Parameters:
   7229  *      unit - (IN) Unit number.
   7230  * Returns:
   7231  *      BCM_E_XXX
   7232  * Notes:
   7233  */
   7234 int
   7235 _bcm_esw_vplag_unlock(int unit)
   7236 {
   7237     if ((NULL != _td2_vp_lag_info[unit]) &&
   7238         (NULL != _td2_vp_lag_info[unit]->lock)) {
   7239         return sal_mutex_give(_td2_vp_lag_info[unit]->lock);
   7240     }
   7241     return (BCM_E_NONE);
   7242 }
   7243 #endif /* INCLUDE_L3 */
   7244 
   7245 #endif /* BCM_TRIDENT2_SUPPORT */