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

l3.c (277895B)


      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:    l3.c
      8  * Purpose: Tomahawk2 L3 function implementations
      9  */
     10 
     11 #include <soc/defs.h>
     12 #include <shared/bsl.h>
     13 #if defined(INCLUDE_L3) && (defined(BCM_TOMAHAWK2_SUPPORT) || \
     14     defined(BCM_TOMAHAWK3_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT))
     15 #include <soc/drv.h>
     16 #include <soc/tomahawk2.h>
     17 #include <soc/profile_mem.h>
     18 
     19 #include <bcm/vlan.h>
     20 #include <bcm/error.h>
     21 #include <bcm/l3.h>
     22 #include <bcm/debug.h>
     23 #include <bcm/error.h>
     24 #include <bcm/stack.h>
     25 
     26 #include <bcm_int/esw/firebolt.h>
     27 #include <bcm_int/esw/stack.h>
     28 #include <bcm_int/esw_dispatch.h>
     29 #include <bcm_int/esw/tomahawk2.h>
     30 #include <bcm_int/esw/tomahawk3.h>
     31 
     32 _th2_ecmp_dlb_bookkeeping_t *_th2_ecmp_dlb_bk[BCM_MAX_NUM_UNITS];
     33 
     34 /* per ecmp group enhanced hashing enabled info  */
     35 #ifdef BCM_TRIDENT3_SUPPORT
     36 extern uint8  ecmp_grp_enhanced_hashing[BCM_MAX_NUM_UNITS][4096];
     37 #endif
     38 #define ECMP_DLB_INFO(_unit_) (_th2_ecmp_dlb_bk[_unit_])
     39 #define ECMP_DLB_PORT_INFO(_unit_, _idx_) \
     40            (_th2_ecmp_dlb_bk[_unit_]->ecmp_dlb_port_info[_idx_])
     41 #define ECMP_DLB_PORT_LIST(_unit_, _idx_) \
     42             ECMP_DLB_PORT_INFO(unit, _idx_).port_membership_list
     43 
     44 #define _BCM_ECMP_DLB_ID_USED_GET(_u_, _idx_) \
     45     SHR_BITGET(ECMP_DLB_INFO(_u_)->ecmp_dlb_id_used_bitmap, _idx_)
     46 #define _BCM_ECMP_DLB_ID_USED_SET(_u_, _idx_) \
     47     SHR_BITSET(ECMP_DLB_INFO(_u_)->ecmp_dlb_id_used_bitmap, _idx_)
     48 #define _BCM_ECMP_DLB_ID_USED_CLR(_u_, _idx_) \
     49     SHR_BITCLR(ECMP_DLB_INFO(_u_)->ecmp_dlb_id_used_bitmap, _idx_)
     50 
     51 #define _BCM_ECMP_DLB_ID_DGM_GET(_u_, _idx_) \
     52     SHR_BITGET(ECMP_DLB_INFO(_u_)->ecmp_dlb_id_dgm_bitmap, _idx_)
     53 #define _BCM_ECMP_DLB_ID_DGM_SET(_u_, _idx_) \
     54     SHR_BITSET(ECMP_DLB_INFO(_u_)->ecmp_dlb_id_dgm_bitmap, _idx_)
     55 #define _BCM_ECMP_DLB_ID_DGM_CLR(_u_, _idx_) \
     56     SHR_BITCLR(ECMP_DLB_INFO(_u_)->ecmp_dlb_id_dgm_bitmap, _idx_)
     57 
     58 
     59 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_GET(_u_, _idx_) \
     60     SHR_BITGET(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_)
     61 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_SET(_u_, _idx_) \
     62     SHR_BITSET(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_)
     63 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_CLR(_u_, _idx_) \
     64     SHR_BITCLR(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_)
     65 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_SET_RANGE(_u_, _idx_, _count_) \
     66     SHR_BITSET_RANGE(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_, _count_)
     67 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_CLR_RANGE(_u_, _idx_, _count_) \
     68     SHR_BITCLR_RANGE(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_, _count_)
     69 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_TEST_RANGE(_u_, _idx_, _count_, _result_) \
     70     SHR_BITTEST_RANGE(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_, _count_, _result_)
     71 
     72 #define _BCM_ECMP_DLB_CELL_BYTES 208
     73 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT      8
     74 #define _BCM_ECMP_DLB_DEFAULT_SCALING_FACTOR        10
     75 #define _BCM_ECMP_DLB_DEFAULT_PORT_LOAD_WEIGHT      100
     76 #define _BCM_ECMP_DLB_DEFAULT_QUEUE_SIZE_WEIGHT     0
     77 
     78 
     79 
     80 /*----- ECMP DLB FUNCS ----- */
     81 
     82 
     83 /*
     84  * Function:
     85  *      _bcm_th2_ecmp_dlb_quality_assign
     86  * Purpose:
     87  *      Assign quality based on loading, total queue size and physical queue size.
     88  * Parameters:
     89  *      unit            - (IN) SOC unit number.
     90  *      tx_load_percent - (IN) Percent weight of loading in determing quality.
     91  *      qsize_percent   - (IN) Percent weight of total queue size in determing
     92  *                             quality.
     93  *                             The remaining percentage is the weight of physical
     94  *                             queue size.
     95  *      entry_arr       - (IN) Array of 512 quality map table entries.
     96  * Returns:
     97  *      BCM_X_XXX
     98  */
     99 STATIC int
    100 _bcm_th2_ecmp_dlb_quality_assign(int unit, int tx_load_percent,
    101                                  int qsize_percent, uint32 *entry_arr)
    102 {
    103     int quantized_tx_load;
    104     int quantized_qsize;
    105     int quantized_physical_qsize;
    106     int quality;
    107     int entry_index;
    108     int physical_qsize_percent = 100 - tx_load_percent - qsize_percent;
    109 
    110     if (entry_arr == NULL) {
    111         return BCM_E_PARAM;
    112     }
    113 
    114 #ifdef BCM_TRIDENT3_SUPPORT
    115     if (SOC_IS_TRIDENT3X(unit)) {
    116         for (quantized_tx_load = 0; quantized_tx_load < 8; quantized_tx_load++) {
    117             for (quantized_qsize = 0; quantized_qsize < 8; quantized_qsize++) {
    118                 quality = (quantized_tx_load * tx_load_percent +
    119                             quantized_qsize * qsize_percent) / 100;
    120                 entry_index = (quantized_tx_load << 6) +
    121                                 (quantized_qsize << 3);
    122                 soc_DLB_ECMP_PORT_QUALITY_MAPPINGm_field32_set(unit,
    123                         &entry_arr[entry_index], ASSIGNED_QUALITYf, quality);
    124             }
    125         }
    126     } else
    127 #endif
    128     {
    129         for (quantized_tx_load = 0; quantized_tx_load < 8; quantized_tx_load++) {
    130             for (quantized_physical_qsize = 0; quantized_physical_qsize < 8;
    131                  quantized_physical_qsize++) {
    132                 for (quantized_qsize = 0; quantized_qsize < 8; quantized_qsize++) {
    133                     quality = (quantized_tx_load * tx_load_percent +
    134                                quantized_qsize * qsize_percent +
    135                                quantized_physical_qsize * physical_qsize_percent) /
    136                                100;
    137                     entry_index = (quantized_tx_load << 6) +
    138                                   (quantized_physical_qsize << 3) +
    139                                   quantized_qsize;
    140                     soc_DLB_ECMP_PORT_QUALITY_MAPPINGm_field32_set(unit,
    141                             &entry_arr[entry_index], ASSIGNED_QUALITYf, quality);
    142                 }
    143             }
    144         }
    145     }
    146 
    147     return BCM_E_NONE;
    148 }
    149 
    150 /*
    151  * Function:
    152  *      _bcm_th2_ecmp_dlb_port_quality_map_set
    153  * Purpose:
    154  *      Set per-member ECMP DLB quality mapping table.
    155  * Parameters:
    156  *      unit            - (IN) SOC unit number.
    157  *      port            - (IN) Port, not Gport.
    158  *      tx_load_percent - (IN) Percent weight of loading in determing quality.
    159  *      qsize_percent   - (IN) Percent weight of total queue size in determing
    160  *                             quality.
    161  *                             The remaining percentage is the weight of physical
    162  *                             queue size.
    163  * Returns:
    164  *      BCM_E_xxx
    165  */
    166 STATIC int
    167 _bcm_th2_ecmp_dlb_port_quality_map_set(int unit, int port,
    168                                        int tx_load_percent, int qsize_percent)
    169 {
    170     soc_profile_mem_t *profile;
    171     soc_mem_t mem;
    172     int entry_bytes;
    173     int entries_per_profile;
    174     int alloc_size;
    175     uint32 *entry_arr;
    176     int rv = BCM_E_NONE;
    177     void *entries;
    178     uint32 base_index;
    179     uint32 old_base_index;
    180     dlb_ecmp_quantize_control_entry_t quantize_control_entry;
    181     int num_quality_map_profiles;
    182 
    183     profile = ECMP_DLB_INFO(unit)->ecmp_dlb_quality_map_profile;
    184     num_quality_map_profiles = 1 << soc_mem_field_length(unit,
    185             DLB_ECMP_QUANTIZE_CONTROLm, PORT_QUALITY_MAPPING_PROFILE_PTRf);
    186     entries_per_profile =
    187         soc_mem_index_count(unit, DLB_ECMP_PORT_QUALITY_MAPPINGm) /
    188         num_quality_map_profiles;
    189 
    190     entry_bytes = sizeof(dlb_ecmp_quality_mapping_entry_t);
    191     alloc_size = entries_per_profile * entry_bytes;
    192     entry_arr = sal_alloc(alloc_size, "ECMP DLB Quality Map entries");
    193     if (entry_arr == NULL) {
    194         return BCM_E_MEMORY;
    195     }
    196     sal_memset(entry_arr, 0, alloc_size);
    197 
    198     /* Assign quality in the entry array */
    199     rv = _bcm_th2_ecmp_dlb_quality_assign(unit, tx_load_percent,
    200                                           qsize_percent, entry_arr);
    201     if (BCM_FAILURE(rv)) {
    202         sal_free(entry_arr);
    203         return rv;
    204     }
    205 
    206     mem = DLB_ECMP_PORT_QUALITY_MAPPINGm;
    207     soc_mem_lock(unit, mem);
    208 
    209     /* Add profile */
    210     entries = entry_arr;
    211     rv = soc_profile_mem_add(unit, profile, &entries, entries_per_profile,
    212                              &base_index);
    213     sal_free(entry_arr);
    214     if (BCM_FAILURE(rv)) {
    215         soc_mem_unlock(unit, mem);
    216         return rv;
    217     }
    218 
    219     /* Update member profile pointer */
    220     rv = READ_DLB_ECMP_QUANTIZE_CONTROLm(unit, MEM_BLOCK_ANY, port,
    221             &quantize_control_entry);
    222     if (BCM_FAILURE(rv)) {
    223         soc_mem_unlock(unit, mem);
    224         return rv;
    225     }
    226     old_base_index = entries_per_profile * soc_mem_field32_get(unit,
    227             DLB_ECMP_QUANTIZE_CONTROLm, &quantize_control_entry,
    228             PORT_QUALITY_MAPPING_PROFILE_PTRf);
    229     soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_set(unit, &quantize_control_entry,
    230             PORT_QUALITY_MAPPING_PROFILE_PTRf, base_index / entries_per_profile);
    231     rv = WRITE_DLB_ECMP_QUANTIZE_CONTROLm(unit, MEM_BLOCK_ALL, port,
    232             &quantize_control_entry);
    233     if (BCM_FAILURE(rv)) {
    234         soc_mem_unlock(unit, mem);
    235         return rv;
    236     }
    237 
    238     /* Delete old profile */
    239     rv = soc_profile_mem_delete(unit, profile, old_base_index);
    240     soc_mem_unlock(unit, mem);
    241 
    242     ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[base_index/entries_per_profile] =
    243         tx_load_percent;
    244     ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_weight[base_index/entries_per_profile] =
    245         qsize_percent;
    246 
    247     return rv;
    248 }
    249 
    250 /*
    251  * Function:
    252  *      _bcm_th2_ecmp_dlb_scaling_factor_encode
    253  * Purpose:
    254  *      Check valid scaling factors, and encode them.
    255  * Parameters:
    256  *      unit            - (IN) SOC unit number.
    257  *      scaling_factor  - (IN) Threshold scaling factor.
    258  * Returns:
    259  *      1: check success
    260  *      0: check fail
    261  */
    262 STATIC int
    263 _bcm_th2_ecmp_dlb_scaling_factor_encode(int unit, int scaling_factor,
    264                                         int *scaling_factor_hw)
    265 {
    266     int bcm_factors[] = {10, 25, 40, 50, 75, 100};
    267     int hw_factors[]  = { 0,  1,  2,  3,  4,   5};
    268     int i;
    269 
    270 #if defined(BCM_TOMAHAWK3_SUPPORT)
    271     if (soc_feature(unit, soc_feature_th3_style_dlb)) {
    272         return _bcm_th3_l3_ecmp_dlb_scaling_factor_encode(unit, scaling_factor,
    273                                                        scaling_factor_hw);
    274     }
    275 #endif
    276 
    277     for (i = 0; i < COUNTOF(bcm_factors); i++ ) {
    278         if (scaling_factor == bcm_factors[i]) {
    279             break;
    280         }
    281     }
    282 
    283     if (i < COUNTOF(hw_factors)) {
    284         if (scaling_factor_hw) {
    285             *scaling_factor_hw = hw_factors[i];
    286         }
    287         return 1;
    288     }
    289     return 0;
    290 }
    291 
    292 
    293 /*
    294  * Function:
    295  *      _bcm_th2_ecmp_dlb_scaling_factor_decode
    296  * Purpose:
    297  *      Decode scaling factors.
    298  * Parameters:
    299  *      unit            - (IN) SOC unit number.
    300  *      scaling_factor  - (IN) Threshold scaling factor.
    301  * Returns:
    302  *      BCM_E_xxx
    303  */
    304 STATIC int
    305 _bcm_th2_ecmp_dlb_scaling_factor_decode(int unit, int scaling_factor_hw,
    306                                         int *scaling_factor)
    307 {
    308     int bcm_factors[] = {10, 25, 40, 50, 75, 100};
    309     int hw_factors[]  = { 0,  1,  2,  3,  4,   5};
    310     int i;
    311 
    312 #if defined(BCM_TOMAHAWK3_SUPPORT)
    313     if (soc_feature(unit, soc_feature_th3_style_dlb)) {
    314         return _bcm_th3_l3_ecmp_dlb_scaling_factor_decode(unit, scaling_factor_hw,
    315                                                        scaling_factor);
    316     }
    317 #endif
    318     for (i = 0; i < COUNTOF(hw_factors); i++ ) {
    319         if (scaling_factor_hw == hw_factors[i]) {
    320             break;
    321         }
    322     }
    323 
    324     if (i == COUNTOF(hw_factors)) {
    325         return BCM_E_INTERNAL;
    326     }
    327 
    328     *scaling_factor = bcm_factors[i];
    329     return BCM_E_NONE;
    330 }
    331 
    332 
    333 /*
    334  * Function:
    335  *      _bcm_th2_ecmp_dlb_port_attr_set
    336  * Purpose:
    337  *      Set ECMP dynamic load balancing attributes for a member.
    338  * Parameters:
    339  *      unit            - (IN) SOC unit number.
    340  *      port            - (IN) Port, not Gport.
    341  *      nh_index        - (IN) Next hop index.
    342  *      scaling_factor  - (IN) Threshold scaling factor.
    343  *      load_weight     - (IN) Weighting of load in determining member quality.
    344  *      qsize_weight    - (IN) Weighting of total qsize in determining member quality.
    345  * Returns:
    346  *      BCM_E_XXX
    347  */
    348 STATIC int
    349 _bcm_th2_ecmp_dlb_port_attr_set(int unit, bcm_port_t port,
    350         int scaling_factor, int load_weight, int qsize_weight)
    351 {
    352     dlb_ecmp_quantize_control_entry_t quantize_control_entry;
    353     int scaling_factor_hw;
    354     soc_field_t qsf_field = XPE_PORT_QSIZE_THRESHOLD_SCALING_FACTORf;
    355 
    356 #if defined(BCM_TOMAHAWK3_SUPPORT)
    357     if (soc_feature(unit, soc_feature_th3_style_dlb)) {
    358         qsf_field = ITM_PORT_QSIZE_THRESHOLD_SCALING_FACTORf;
    359     }
    360 #endif
    361 
    362     /* Set load weight, qsize weight */
    363     BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_port_quality_map_set(unit,
    364                                                                port,
    365                                                                load_weight,
    366                                                                qsize_weight));
    367 
    368     if (!_bcm_th2_ecmp_dlb_scaling_factor_encode(unit,
    369             scaling_factor, &scaling_factor_hw)) {
    370         return BCM_E_PARAM;
    371     }
    372     /* Set scaling factor */
    373     BCM_IF_ERROR_RETURN(READ_DLB_ECMP_QUANTIZE_CONTROLm(unit, MEM_BLOCK_ANY,
    374                 port, &quantize_control_entry));
    375 
    376     soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_set(unit,
    377             &quantize_control_entry,
    378             PORT_LOADING_THRESHOLD_SCALING_FACTORf,
    379             scaling_factor_hw);
    380     if (!soc_feature(unit, soc_feature_td3_dlb)) {
    381         soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_set(unit,
    382                 &quantize_control_entry,
    383                 TOTAL_PORT_QSIZE_THRESHOLD_SCALING_FACTORf,
    384                 scaling_factor_hw);
    385     }
    386     soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_set(unit,
    387             &quantize_control_entry,
    388             qsf_field,
    389             scaling_factor_hw);
    390     BCM_IF_ERROR_RETURN(WRITE_DLB_ECMP_QUANTIZE_CONTROLm(unit, MEM_BLOCK_ALL,
    391                 port, &quantize_control_entry));
    392 
    393     return BCM_E_NONE;
    394 }
    395 
    396 /*
    397  * Function:
    398  *      _bcm_th2_ecmp_dlb_port_attr_get
    399  * Purpose:
    400  *      Get ECMP dynamic load balancing attributes for a member.
    401  * Parameters:
    402  *      unit            - (IN) SOC unit number.
    403  *      port            - (IN) Port, not Gport.
    404  *      scaling_factor  - (OUT) Threshold scaling factor.
    405  *      load_weight     - (OUT) Weighting of load in determining member quality.
    406  *      qsize_weight    - (OUT) Weighting of total qsize in determining member quality.
    407  * Returns:
    408  *      BCM_E_XXX
    409  */
    410 STATIC int
    411 _bcm_th2_ecmp_dlb_port_attr_get(int unit, bcm_port_t port, int *scaling_factor,
    412         int *load_weight, int *qsize_weight)
    413 {
    414     dlb_ecmp_quantize_control_entry_t quantize_control_entry;
    415     int profile_ptr;
    416     int scaling_factor_hw;
    417 
    418     BCM_IF_ERROR_RETURN(READ_DLB_ECMP_QUANTIZE_CONTROLm(unit, MEM_BLOCK_ANY,
    419                 port, &quantize_control_entry));
    420 
    421     /* Get load weight, qsize weight*/
    422     profile_ptr = soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_get(unit,
    423             &quantize_control_entry, PORT_QUALITY_MAPPING_PROFILE_PTRf);
    424     *load_weight = ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[profile_ptr];
    425     *qsize_weight = ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_weight[profile_ptr];
    426 
    427     /* Get scaling factor */
    428     scaling_factor_hw = soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_get(unit,
    429             &quantize_control_entry, PORT_LOADING_THRESHOLD_SCALING_FACTORf);
    430 
    431     BCM_IF_ERROR_RETURN
    432         (_bcm_th2_ecmp_dlb_scaling_factor_decode(unit, scaling_factor_hw,
    433                                                  scaling_factor));
    434 
    435     return BCM_E_NONE;
    436 }
    437 
    438 /*
    439  * Function:
    440  *      bcm_th2_l3_egress_dlb_attr_set
    441  * Purpose:
    442  *      Set ECMP dynamic load balancing attributes for a next hop index.
    443  * Parameters:
    444  *      unit     - (IN) SOC unit number.
    445  *      nh_index - (IN) Next hop index.
    446  *      egr      - (IN) L3 egress info.
    447  *      old_egr  - (IN) Old L3 egress info.
    448  * Returns:
    449  *      BCM_E_XXX
    450  */
    451 int
    452 bcm_th2_l3_egress_dlb_attr_set(int unit, int nh_index,
    453                                bcm_l3_egress_t *egr, bcm_l3_egress_t *old_egr)
    454 {
    455     int scaling_factor_valid = 1;
    456     int load_weight_valid = 1;
    457     int qsize_weight_valid = 1;
    458     int sum_valid;
    459     _th2_ecmp_dlb_port_membership_t *membership = NULL;
    460     int new_mod, new_port; /* not GPORT */
    461     int mod, port;         /* not GPORT */
    462     int is_local;
    463     int move_dlb_count;
    464     int search_old_qualified;
    465     _th2_ecmp_dlb_port_membership_t *current_ptr, *prev_ptr;
    466     _th2_ecmp_dlb_port_membership_t *current_next;
    467     _th2_ecmp_dlb_port_membership_t *first_ptr, *prev_first_ptr;
    468     _th2_ecmp_dlb_port_membership_t *last_ptr;
    469     _th2_ecmp_dlb_port_membership_t *record_ptr;
    470     if (egr->dynamic_scaling_factor ==
    471              BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID) {
    472        scaling_factor_valid = 0;
    473     }
    474     if (egr->dynamic_load_weight ==
    475              BCM_L3_ECMP_DYNAMIC_LOAD_WEIGHT_INVALID) {
    476         load_weight_valid = 0;
    477     }
    478     if (egr->dynamic_queue_size_weight ==
    479              BCM_L3_ECMP_DYNAMIC_QUEUE_SIZE_WEIGHT_INVALID) {
    480         qsize_weight_valid = 0;
    481     }
    482     sum_valid = scaling_factor_valid +
    483         load_weight_valid + qsize_weight_valid;
    484 
    485     if ((sum_valid != 0) && (sum_valid != 3)) {
    486         /* The scaling factor, load weight and qsize weight must
    487          * be all invalid or all valid.
    488          */
    489         return BCM_E_PARAM;
    490     }
    491 
    492     /* Verify DLB parameters */
    493     if (sum_valid == 3) {
    494         if (!_bcm_th2_ecmp_dlb_scaling_factor_encode(unit,
    495                 egr->dynamic_scaling_factor, NULL)) {
    496             return BCM_E_PARAM;
    497         }
    498         if (egr->dynamic_load_weight < 0 ||
    499             egr->dynamic_load_weight > 100) {
    500             return BCM_E_PARAM;
    501         }
    502         if (egr->dynamic_queue_size_weight < 0 ||
    503             egr->dynamic_queue_size_weight > 100) {
    504             return BCM_E_PARAM;
    505         }
    506         if ((egr->dynamic_load_weight + egr->dynamic_queue_size_weight) < 0 ||
    507             (egr->dynamic_load_weight + egr->dynamic_queue_size_weight) > 100) {
    508             return BCM_E_PARAM;
    509         }
    510         /* ECMP DLB members shouldn't be LAG */
    511         if (egr->flags & BCM_L3_TGID) {
    512             return BCM_E_PARAM;
    513         } else {
    514             /* ECMP DLB members should be local */
    515             BCM_IF_ERROR_RETURN
    516                 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET,
    517                                          egr->module, egr->port,
    518                                          &new_mod, &new_port));
    519             if (new_port < 0 ||
    520                 new_port >= ECMP_DLB_INFO(unit)->ecmp_dlb_port_info_size) {
    521                 return BCM_E_PARAM;
    522             }
    523 
    524             (void) _bcm_esw_modid_is_local(unit, new_mod, &is_local);
    525             if (!is_local) {
    526                 return BCM_E_PARAM;
    527             }
    528         }
    529     }
    530 
    531 
    532     search_old_qualified = 0;
    533     if (old_egr &&
    534         !(old_egr->flags & BCM_L3_TGID)) {
    535         BCM_IF_ERROR_RETURN
    536         (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET,
    537                                  old_egr->module, old_egr->port,
    538                                  &mod, &port));
    539         (void) _bcm_esw_modid_is_local(unit, mod, &is_local);
    540         if (port < 0 ||
    541             port >= ECMP_DLB_INFO(unit)->ecmp_dlb_port_info_size) {
    542             return BCM_E_PARAM;
    543         }
    544 
    545         search_old_qualified = is_local;
    546     }
    547 
    548     current_ptr = NULL;
    549     prev_ptr    = NULL;
    550     if (search_old_qualified) {
    551         current_ptr = ECMP_DLB_PORT_LIST(unit, port);
    552         while (current_ptr) {
    553             if (nh_index == current_ptr->nh_index) {
    554                 break;
    555             } else {
    556                 prev_ptr = current_ptr;
    557             }
    558             current_ptr = current_ptr->next;
    559         }
    560     }
    561 
    562     if (current_ptr) {
    563         /* This Nexthop existed with DLB attributes, which means it
    564          * must have DLB attributes before.
    565          */
    566 
    567         record_ptr = current_ptr;
    568         if (egr->dynamic_scaling_factor ==
    569                 BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID) {
    570             /* Now remove its DLB attributes. This node should be removed
    571              * from port list.
    572              */
    573 
    574             /* Check that the given next hop index is currently not a member of
    575              * any ECMP DLB group.
    576              */
    577             while (current_ptr) {
    578                 if (nh_index == current_ptr->nh_index &&
    579                     -1 != current_ptr->dlb_id) {
    580                     return BCM_E_BUSY;
    581                 }
    582                 current_ptr = current_ptr->next;
    583             }
    584 
    585             current_ptr = record_ptr;
    586             while (current_ptr) {
    587                 current_next = current_ptr->next;
    588                 if (nh_index == current_ptr->nh_index) {
    589                     if (prev_ptr == NULL) {
    590                         ECMP_DLB_PORT_LIST(unit, port) = current_next;
    591                     } else {
    592                         prev_ptr->next = current_next;
    593                     }
    594                     sal_free(current_ptr);
    595                 } else {
    596                     break;
    597                 }
    598                 current_ptr = current_next;
    599             }
    600             /* must do and only do once */
    601             ECMP_DLB_PORT_INFO(unit, port).nh_count--;
    602 
    603             /* Reset the DLB attributes */
    604             if (ECMP_DLB_PORT_INFO(unit, port).nh_count == 0) {
    605                 /* Verify nh_count consistent with port_list and dlb_count */
    606                 if (ECMP_DLB_PORT_LIST(unit, port) != NULL ||
    607                     ECMP_DLB_PORT_INFO(unit, port).dlb_count != 0) {
    608                     return BCM_E_INTERNAL;
    609                 }
    610 
    611                 BCM_IF_ERROR_RETURN
    612                 (_bcm_th2_ecmp_dlb_port_attr_set(unit, port,
    613                     _BCM_ECMP_DLB_DEFAULT_SCALING_FACTOR,
    614                     _BCM_ECMP_DLB_DEFAULT_PORT_LOAD_WEIGHT,
    615                     _BCM_ECMP_DLB_DEFAULT_QUEUE_SIZE_WEIGHT));
    616             }
    617         } else {
    618             /* Set nexthop with new DLB attributes.
    619              * There're 2 cases:
    620              * 1, the new port equal to old port
    621              * 2, the new port not equal to old port
    622  */
    623             if (port == new_port) {
    624                 /* 1, the new port is equal to old port. */
    625                 if (ECMP_DLB_PORT_INFO(unit, port).nh_count == 0) {
    626                     return BCM_E_INTERNAL;
    627                 }
    628 
    629                 if (ECMP_DLB_PORT_INFO(unit, port).nh_count == 1 ||
    630                     ECMP_DLB_INFO(unit)->ecmp_dlb_property_force_set) {
    631                     /* This nexthop is the only nexthop pointing to old port
    632                      * Set with new DLB attributes.
    633                      */
    634                     BCM_IF_ERROR_RETURN
    635                     (_bcm_th2_ecmp_dlb_port_attr_set(unit,
    636                                                      new_port,
    637                                                      egr->dynamic_scaling_factor,
    638                                                      egr->dynamic_load_weight,
    639                                                      egr->dynamic_queue_size_weight));
    640                 } else {
    641                     /* This nexthop is not the only nexthop pointing to old port
    642                      * Reject/alert if new DLB attributes are not equal
    643                      * to old DLB attributes
    644                      */
    645                     if (egr->dynamic_load_weight       != old_egr->dynamic_load_weight ||
    646                         egr->dynamic_queue_size_weight != old_egr->dynamic_queue_size_weight ||
    647                         egr->dynamic_scaling_factor    != old_egr->dynamic_scaling_factor) {
    648                         return BCM_E_BUSY;
    649                     }
    650                 }
    651 
    652             } else {
    653                /* 2, the new port is not equal to old port.
    654                 *  move this nexthop's node or nodes to new port list
    655                 */
    656 
    657                 /* Check that the move is feasible */
    658                 if (!ECMP_DLB_INFO(unit)->ecmp_dlb_property_force_set &&
    659                     ECMP_DLB_PORT_INFO(unit, new_port).nh_count >= 1) {
    660                     int dynamic_scaling_factor;
    661                     int dynamic_load_weight;
    662                     int dynamic_qsize_weight;
    663                     BCM_IF_ERROR_RETURN
    664                     (_bcm_th2_ecmp_dlb_port_attr_get(unit,
    665                                                      new_port,
    666                                                      &dynamic_scaling_factor,
    667                                                      &dynamic_load_weight,
    668                                                      &dynamic_qsize_weight));
    669                     if (egr->dynamic_load_weight       != dynamic_load_weight ||
    670                         egr->dynamic_queue_size_weight != dynamic_qsize_weight||
    671                         egr->dynamic_scaling_factor    != dynamic_scaling_factor){
    672                         return BCM_E_BUSY;
    673                     }
    674                 }
    675 
    676                 /* a, first remove this nexthop from old port list */
    677                 first_ptr = NULL;
    678                 last_ptr = NULL;
    679                 move_dlb_count = 0;
    680                 prev_ptr = ECMP_DLB_PORT_LIST(unit, port);
    681                 prev_first_ptr = NULL;
    682                 while (current_ptr) {
    683                     if (nh_index == current_ptr->nh_index) {
    684                         if (first_ptr == NULL) {
    685                             first_ptr = current_ptr;
    686                             prev_first_ptr = prev_ptr;
    687                         }
    688                         if (current_ptr->dlb_id != -1) {
    689                             move_dlb_count++;
    690                         }
    691                         last_ptr = current_ptr;
    692                     } else {
    693                         /* Given the fact nodes with same nh_index are always
    694                          * bundled together.
    695                          */
    696                         if (first_ptr) {
    697                             break;
    698                         }
    699                     }
    700                     prev_ptr = current_ptr;
    701                     current_ptr = current_ptr->next;
    702                 }
    703                 /* must do and only do once */
    704                 ECMP_DLB_PORT_INFO(unit, port).nh_count--;
    705 
    706                 if (last_ptr == NULL ||
    707                     first_ptr == NULL ||
    708                     prev_first_ptr == NULL) {
    709                     return BCM_E_INTERNAL;
    710                 }
    711                 if (prev_first_ptr == ECMP_DLB_PORT_LIST(unit, port)) {
    712                     ECMP_DLB_PORT_LIST(unit, port) = last_ptr->next;
    713                 } else {
    714                     prev_first_ptr->next = last_ptr->next;
    715                 }
    716 
    717                 ECMP_DLB_PORT_INFO(unit, port).dlb_count -= move_dlb_count;
    718 
    719                 /* Reset the DLB attributes */
    720                 if (ECMP_DLB_PORT_INFO(unit, port).nh_count == 0) {
    721                     if (ECMP_DLB_PORT_LIST(unit, port) != NULL ||
    722                         ECMP_DLB_PORT_INFO(unit, port).dlb_count != 0) {
    723                         return BCM_E_INTERNAL;
    724                     }
    725                     BCM_IF_ERROR_RETURN
    726                         (_bcm_th2_ecmp_dlb_port_attr_set(unit, port,
    727                             _BCM_ECMP_DLB_DEFAULT_SCALING_FACTOR,
    728                             _BCM_ECMP_DLB_DEFAULT_PORT_LOAD_WEIGHT,
    729                             _BCM_ECMP_DLB_DEFAULT_QUEUE_SIZE_WEIGHT));
    730                 }
    731 
    732                 /* Set the DLB attributes */
    733                 BCM_IF_ERROR_RETURN(
    734                 _bcm_th2_ecmp_dlb_port_attr_set(unit,
    735                                                 new_port,
    736                                                 egr->dynamic_scaling_factor,
    737                                                 egr->dynamic_load_weight,
    738                                                 egr->dynamic_queue_size_weight));
    739                 /*  Add into list */
    740                 last_ptr->next = ECMP_DLB_PORT_LIST(unit, new_port);
    741                 ECMP_DLB_PORT_LIST(unit, new_port) = first_ptr;
    742                 ECMP_DLB_PORT_INFO(unit, new_port).nh_count++;
    743                 ECMP_DLB_PORT_INFO(unit, new_port).dlb_count += move_dlb_count;
    744 
    745             }
    746         }
    747     } else {
    748         /* Either the Nexthop did not exist or it existed without DLB attributes. */
    749         if (egr->dynamic_scaling_factor ==
    750             BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID) {
    751             /* still without DLB porperties */
    752             return BCM_E_NONE;
    753         } else {
    754             /* With DLB porperties */
    755 
    756             /* Check that DLB attributes setting is feasible */
    757             if (!ECMP_DLB_INFO(unit)->ecmp_dlb_property_force_set &&
    758                 ECMP_DLB_PORT_INFO(unit, new_port).nh_count >= 1) {
    759                 int dynamic_scaling_factor;
    760                 int dynamic_load_weight;
    761                 int dynamic_qsize_weight;
    762                 BCM_IF_ERROR_RETURN
    763                 (_bcm_th2_ecmp_dlb_port_attr_get(unit,
    764                                                  new_port,
    765                                                  &dynamic_scaling_factor,
    766                                                  &dynamic_load_weight,
    767                                                  &dynamic_qsize_weight));
    768                 if (egr->dynamic_load_weight != dynamic_load_weight ||
    769                     egr->dynamic_queue_size_weight != dynamic_qsize_weight ||
    770                     egr->dynamic_scaling_factor != dynamic_scaling_factor){
    771                     return BCM_E_BUSY;
    772                 }
    773             }
    774 
    775             BCM_IF_ERROR_RETURN
    776             (_bcm_th2_ecmp_dlb_port_attr_set(unit,
    777                                              new_port,
    778                                              egr->dynamic_scaling_factor,
    779                                              egr->dynamic_load_weight,
    780                                              egr->dynamic_queue_size_weight));
    781 
    782             membership = sal_alloc(sizeof(_th2_ecmp_dlb_port_membership_t),
    783                     "ecmp dlb nh membership");
    784             if (NULL == membership) {
    785                 return BCM_E_MEMORY;
    786             }
    787             sal_memset(membership, 0, sizeof(_th2_ecmp_dlb_port_membership_t));
    788             membership->nh_index = nh_index;
    789             membership->ref_count = 0;
    790             membership->dlb_id    = -1;
    791             membership->next = ECMP_DLB_PORT_LIST(unit, new_port);
    792             ECMP_DLB_PORT_LIST(unit, new_port) = membership;
    793             ECMP_DLB_PORT_INFO(unit, new_port).nh_count++;
    794         }
    795     }
    796 
    797     return BCM_E_NONE;
    798 }
    799 
    800 /*
    801  * Function:
    802  *      bcm_th2_l3_egress_dlb_attr_destroy
    803  * Purpose:
    804  *      Destroy ECMP dynamic load balancing attributes for a next hop index.
    805  * Parameters:
    806  *      unit     - (IN) SOC unit number.
    807  *      nh_index - (IN) Next hop index.
    808  * Returns:
    809  *      BCM_E_XXX
    810  */
    811 int
    812 bcm_th2_l3_egress_dlb_attr_destroy(int unit, int nh_index, bcm_l3_egress_t *egr)
    813 {
    814     int mod, port;
    815     int is_local;
    816     _th2_ecmp_dlb_port_membership_t *record_ptr = NULL;
    817     _th2_ecmp_dlb_port_membership_t *current_next, *prev_ptr = NULL;
    818     _th2_ecmp_dlb_port_membership_t *current_ptr = NULL;
    819 
    820     /* ECMP DLB members shouldn't be LAG */
    821     if (egr->flags & BCM_L3_TGID) {
    822         return BCM_E_NONE;
    823     } else {
    824         BCM_IF_ERROR_RETURN
    825             (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET,
    826                                      egr->module, egr->port,
    827                                      &mod, &port));
    828         if (port < 0 ||
    829             port >= ECMP_DLB_INFO(unit)->ecmp_dlb_port_info_size) {
    830             if (egr->flags & BCM_L3_DST_DISCARD) {
    831                 return BCM_E_NONE;
    832             }
    833             return BCM_E_PARAM;
    834         }
    835 
    836         (void) _bcm_esw_modid_is_local(unit, mod, &is_local);
    837         if (!is_local) {
    838             return BCM_E_NONE;
    839         }
    840     }
    841 
    842     /* Check that the given next hop index is currently not a member of
    843      * any ECMP DLB group.
    844      */
    845     current_ptr = ECMP_DLB_PORT_LIST(unit, port);
    846     while (current_ptr) {
    847         if (nh_index == current_ptr->nh_index) {
    848             if (record_ptr == NULL) {
    849                 record_ptr = current_ptr;
    850             }
    851             if (current_ptr->dlb_id != -1) {
    852                 return BCM_E_BUSY;
    853             }
    854         } else {
    855             if (record_ptr) {
    856                 break;
    857             } else {
    858                 prev_ptr = current_ptr;
    859             }
    860         }
    861         current_ptr = current_ptr->next;
    862     }
    863 
    864     if (record_ptr == NULL) {
    865         return BCM_E_NONE;
    866     }
    867 
    868     current_ptr = record_ptr;
    869 
    870     while (current_ptr) {
    871         current_next = current_ptr->next;
    872         if (nh_index == current_ptr->nh_index) {
    873             if (prev_ptr == NULL) {
    874                 ECMP_DLB_PORT_LIST(unit, port) = current_next;
    875             } else {
    876                 prev_ptr->next = current_next;
    877             }
    878             sal_free(current_ptr);
    879         } else {
    880             break;
    881         }
    882         current_ptr = current_next;
    883     }
    884     /* must do and only do once */
    885     ECMP_DLB_PORT_INFO(unit, port).nh_count--;
    886 
    887     /* Reset the DLB attributes */
    888     if (ECMP_DLB_PORT_INFO(unit, port).nh_count == 0) {
    889         /* Verify nh_count consistent with port_list and dlb_count */
    890         if (ECMP_DLB_PORT_LIST(unit, port) != NULL ||
    891             ECMP_DLB_PORT_INFO(unit, port).dlb_count != 0) {
    892             return BCM_E_INTERNAL;
    893         }
    894         BCM_IF_ERROR_RETURN
    895         (_bcm_th2_ecmp_dlb_port_attr_set(unit, port,
    896             _BCM_ECMP_DLB_DEFAULT_SCALING_FACTOR,
    897             _BCM_ECMP_DLB_DEFAULT_PORT_LOAD_WEIGHT,
    898             _BCM_ECMP_DLB_DEFAULT_QUEUE_SIZE_WEIGHT));
    899     }
    900 
    901     return BCM_E_NONE;
    902 }
    903 
    904 /*
    905  * Function:
    906  *      bcm_th2_l3_egress_dlb_attr_get
    907  * Purpose:
    908  *      Get ECMP dynamic load balancing attributes for a next hop index.
    909  * Parameters:
    910  *      unit     - (IN) SOC unit number.
    911  *      nh_index - (IN) Next hop index.
    912  *      egr      - (OUT) L3 egress info.
    913  * Returns:
    914  *      BCM_E_XXX
    915  */
    916 int
    917 bcm_th2_l3_egress_dlb_attr_get(int unit, int nh_index, bcm_l3_egress_t *egr)
    918 {
    919     _th2_ecmp_dlb_port_membership_t *current_ptr;
    920     int port;
    921 
    922     /* ECMP DLB members shouldn't be LAG */
    923     if (egr->flags & BCM_L3_TGID) {
    924         return BCM_E_NONE;
    925     } else {
    926         BCM_IF_ERROR_RETURN
    927             (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET,
    928                                      egr->module, egr->port,
    929                                      NULL, &port));
    930         if (port < 0 ||
    931             port >= ECMP_DLB_INFO(unit)->ecmp_dlb_port_info_size) {
    932             if (egr->flags & BCM_L3_DST_DISCARD) {
    933                 egr->dynamic_scaling_factor = \
    934                           BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID;
    935                 egr->dynamic_load_weight = \
    936                           BCM_L3_ECMP_DYNAMIC_LOAD_WEIGHT_INVALID;
    937                 egr->dynamic_queue_size_weight = \
    938                           BCM_L3_ECMP_DYNAMIC_QUEUE_SIZE_WEIGHT_INVALID;
    939                 return BCM_E_NONE;
    940             }
    941             return BCM_E_PARAM;
    942         }
    943     }
    944 
    945     current_ptr = ECMP_DLB_PORT_LIST(unit, port);
    946     while (current_ptr) {
    947         if (nh_index == current_ptr->nh_index) {
    948             break;
    949         }
    950         current_ptr = current_ptr->next;
    951     }
    952 
    953     if (current_ptr) {
    954         /* Get the DLB attributes */
    955         BCM_IF_ERROR_RETURN
    956         (_bcm_th2_ecmp_dlb_port_attr_get(unit,
    957                                          port,
    958                                          &egr->dynamic_scaling_factor,
    959                                          &egr->dynamic_load_weight,
    960                                          &egr->dynamic_queue_size_weight));
    961     } else {
    962         egr->dynamic_scaling_factor = BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID;
    963         egr->dynamic_load_weight = BCM_L3_ECMP_DYNAMIC_LOAD_WEIGHT_INVALID;
    964         egr->dynamic_queue_size_weight = BCM_L3_ECMP_DYNAMIC_QUEUE_SIZE_WEIGHT_INVALID;
    965     }
    966 
    967     return BCM_E_NONE;
    968 }
    969 
    970 /*
    971  * Function:
    972  *      _bcm_th2_ecmp_dlb_id_alloc
    973  * Purpose:
    974  *      Get a free ECMP DLB ID and mark it used.
    975  * Parameters:
    976  *      unit    - (IN) SOC unit number.
    977  *      dynamic_mode - (IN) Dynamic mode
    978  *      dlb_id  - (OUT) Allocated DLB ID.
    979  * Returns:
    980  *      BCM_E_xxx
    981  */
    982 STATIC int
    983 _bcm_th2_ecmp_dlb_id_alloc(int unit, bcm_l3_egress_ecmp_t *ecmp, int *dlb_id)
    984 {
    985     int i;
    986     uint32 dynamic_mode = ecmp->dynamic_mode;
    987 
    988 #if defined(BCM_TOMAHAWK3_SUPPORT)
    989     if (soc_feature(unit, soc_feature_th3_style_dlb)) {
    990         *dlb_id = _bcm_th3_l3_ecmp_dlb_get_id(unit, ecmp->ecmp_intf
    991                                - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit));
    992         _BCM_ECMP_DLB_ID_USED_SET(unit, *dlb_id);
    993         if (dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) {
    994             _BCM_ECMP_DLB_ID_DGM_SET(unit, *dlb_id);
    995         } else {
    996             _BCM_ECMP_DLB_ID_DGM_CLR(unit, *dlb_id);
    997         }
    998         return BCM_E_NONE;
    999     }
   1000 #endif
   1001     for (i = 0; i < soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm); i++) {
   1002         if (!_BCM_ECMP_DLB_ID_USED_GET(unit, i)) {
   1003             _BCM_ECMP_DLB_ID_USED_SET(unit, i);
   1004             if (dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) {
   1005                 _BCM_ECMP_DLB_ID_DGM_SET(unit, i);
   1006             } else {
   1007                 _BCM_ECMP_DLB_ID_DGM_CLR(unit, i);
   1008             }
   1009             *dlb_id = i;
   1010             return BCM_E_NONE;
   1011         }
   1012     }
   1013 
   1014     return BCM_E_RESOURCE;
   1015 }
   1016 
   1017 /*
   1018  * Function:
   1019  *      _bcm_th2_ecmp_dlb_id_free
   1020  * Purpose:
   1021  *      Free an ECMP DLB ID.
   1022  * Parameters:
   1023  *      unit    - (IN) SOC unit number.
   1024  *      dlb_id  - (IN) DLB ID to be freed.
   1025  * Returns:
   1026  *      BCM_E_xxx
   1027  */
   1028 STATIC int
   1029 _bcm_th2_ecmp_dlb_id_free(int unit, int dlb_id)
   1030 {
   1031     if (dlb_id < 0 ||
   1032         dlb_id > soc_mem_index_max(unit, DLB_ECMP_GROUP_CONTROLm)) {
   1033         return BCM_E_PARAM;
   1034     }
   1035 
   1036     _BCM_ECMP_DLB_ID_USED_CLR(unit, dlb_id);
   1037     _BCM_ECMP_DLB_ID_DGM_CLR(unit, dlb_id);
   1038 
   1039     return BCM_E_NONE;
   1040 }
   1041 
   1042 /*
   1043  * Function:
   1044  *      _bcm_th2_ecmp_dlb_dynamic_size_encode
   1045  * Purpose:
   1046  *      Encode ECMP dynamic load balancing flow set size.
   1047  * Parameters:
   1048  *      dynamic_size    - (IN) Number of flow sets.
   1049  *      encoded_value   - (OUT) Encoded value.
   1050  * Returns:
   1051  *      BCM_E_xxx
   1052  */
   1053 STATIC int
   1054 _bcm_th2_ecmp_dlb_dynamic_size_encode(int dynamic_size,
   1055         int *encoded_value)
   1056 {
   1057     switch (dynamic_size) {
   1058         case 256:
   1059             *encoded_value = 1;
   1060             break;
   1061         case 512:
   1062             *encoded_value = 2;
   1063             break;
   1064         case 1024:
   1065             *encoded_value = 3;
   1066             break;
   1067         case 2048:
   1068             *encoded_value = 4;
   1069             break;
   1070         case 4096:
   1071             *encoded_value = 5;
   1072             break;
   1073         case 8192:
   1074             *encoded_value = 6;
   1075             break;
   1076         case 16384:
   1077             *encoded_value = 7;
   1078             break;
   1079         case 32768:
   1080             *encoded_value = 8;
   1081             break;
   1082         default:
   1083             return BCM_E_PARAM;
   1084     }
   1085 
   1086     return BCM_E_NONE;
   1087 }
   1088 
   1089 /*
   1090  * Function:
   1091  *      _bcm_th2_ecmp_dlb_dynamic_size_decode
   1092  * Purpose:
   1093  *      Decode ECMP dynamic load balancing flow set size.
   1094  * Parameters:
   1095  *      encoded_value   - (IN) Encoded value.
   1096  *      dynamic_size    - (OUT) Number of flow sets.
   1097  * Returns:
   1098  *      BCM_E_xxx
   1099  */
   1100 STATIC int
   1101 _bcm_th2_ecmp_dlb_dynamic_size_decode(int encoded_value,
   1102         int *dynamic_size)
   1103 {
   1104     switch (encoded_value) {
   1105         case 1:
   1106             *dynamic_size = 256;
   1107             break;
   1108         case 2:
   1109             *dynamic_size = 512;
   1110             break;
   1111         case 3:
   1112             *dynamic_size = 1024;
   1113             break;
   1114         case 4:
   1115             *dynamic_size = 2048;
   1116             break;
   1117         case 5:
   1118             *dynamic_size = 4096;
   1119             break;
   1120         case 6:
   1121             *dynamic_size = 8192;
   1122             break;
   1123         case 7:
   1124             *dynamic_size = 16384;
   1125             break;
   1126         case 8:
   1127             *dynamic_size = 32768;
   1128             break;
   1129         default:
   1130             return BCM_E_INTERNAL;
   1131     }
   1132 
   1133     return BCM_E_NONE;
   1134 }
   1135 
   1136 /*
   1137  * Function:
   1138  *      _bcm_th2_ecmp_dlb_free_resource
   1139  * Purpose:
   1140  *      Free resources for an ECMP dynamic load balancing group.
   1141  * Parameters:
   1142  *      unit            - (IN) SOC unit number.
   1143  *      ecmp_group_idx  - (IN) ECMP group index.
   1144  *      dlb_id          - (IN) DLB id.
   1145  *                         -1: free all DLB resources,
   1146  *                         others: will not disable DLB and free flowset.
   1147  * Returns:
   1148  *      BCM_E_xxx
   1149  */
   1150 STATIC int
   1151 _bcm_th2_ecmp_dlb_free_resource(int unit, int ecmp_group_idx, int dlb_id,
   1152                                 int cleanup_flowset)
   1153 {
   1154     int rv = BCM_E_NONE;
   1155     ecmp_dlb_control_entry_t ecmp_dlb_control_entry;
   1156     int dlb_enable;
   1157     dlb_ecmp_group_control_entry_t dlb_ecmp_group_control_entry;
   1158     int entry_base_ptr;
   1159     int flow_set_size;
   1160     int num_entries;
   1161     int block_base_ptr;
   1162     int membership_pointer;
   1163     int port2member_base = 0;
   1164     int num_blocks;
   1165     dlb_ecmp_group_membership_entry_t dlb_ecmp_group_membership_entry;
   1166     int port_map_width;
   1167     int alloc_size;
   1168     SHR_BITDCL *port_map = NULL, *port_map2 = NULL;
   1169     SHR_BITDCL *port_map_remove = NULL;
   1170     int port_map_remove_set = 0;
   1171     SHR_BITDCL *status_bitmap = NULL;
   1172     SHR_BITDCL *override_bitmap = NULL;
   1173     int port;
   1174     dlb_ecmp_link_control_entry_t link_control_entry;
   1175     _th2_ecmp_dlb_port_membership_t *current_ptr, *prev_ptr, *current_next;
   1176     int duplicate = 0;
   1177     dlb_ecmp_group_port_to_member_entry_t *entry_arr = NULL;
   1178     int entry_size;
   1179     int entries_per_profile;
   1180     int index_max;
   1181 #ifdef BCM_TRIDENT3_SUPPORT
   1182     ecmp_count_entry_t ecmp_count_entry;
   1183 #endif
   1184 #if defined(BCM_TOMAHAWK3_SUPPORT)
   1185     uint64 dlb_en_bitmap;
   1186 #endif
   1187     int delete_all_flag = TRUE;
   1188 
   1189     delete_all_flag = (dlb_id == -1) ? TRUE: FALSE;
   1190 
   1191 #if defined(BCM_TOMAHAWK3_SUPPORT)
   1192     if (soc_feature(unit, soc_feature_th3_style_dlb)) {
   1193         /* Make sure the ECMP group is in DLB range */
   1194         if ( ecmp_group_idx < BCM_TH3_L3_ECMP_DLB_START(unit)) {
   1195             return BCM_E_NONE;
   1196         }
   1197 
   1198         dlb_id = _bcm_th3_l3_ecmp_dlb_get_id(unit, ecmp_group_idx);
   1199         /* Enable bits for the first 64 groups are in
   1200            DLB_ID_0_TO_63_ENABLE register and the next 64 are in
   1201            DLB_ID_64_TO_127_ENABLE. */
   1202         if (dlb_id < soc_reg_field_length(unit,
   1203                      DLB_ID_0_TO_63_ENABLEr, BITMAPf)) {
   1204             SOC_IF_ERROR_RETURN(READ_DLB_ID_0_TO_63_ENABLEr(unit, &dlb_en_bitmap));
   1205             if (!(COMPILER_64_BITTEST(dlb_en_bitmap, dlb_id))) {
   1206                 return BCM_E_NONE;
   1207             }
   1208         } else {
   1209             SOC_IF_ERROR_RETURN( \
   1210                 READ_DLB_ID_64_TO_127_ENABLEr(unit, &dlb_en_bitmap));
   1211             if (!(COMPILER_64_BITTEST(dlb_en_bitmap, dlb_id -
   1212                 soc_reg_field_length(unit, DLB_ID_0_TO_63_ENABLEr, BITMAPf)))) {
   1213                 return BCM_E_NONE;
   1214             }
   1215         }
   1216         delete_all_flag = cleanup_flowset;
   1217     }
   1218 #endif
   1219 
   1220     if (delete_all_flag) {
   1221         if (!(soc_feature(unit, soc_feature_th3_style_dlb))) {
   1222             BCM_IF_ERROR_RETURN(
   1223                 READ_ECMP_DLB_CONTROLm(unit, MEM_BLOCK_ANY,
   1224                                        ecmp_group_idx, &ecmp_dlb_control_entry));
   1225             dlb_enable =
   1226                 soc_ECMP_DLB_CONTROLm_field32_get(unit, &ecmp_dlb_control_entry,
   1227                                                   GROUP_ENABLEf);
   1228             dlb_id =
   1229                 soc_ECMP_DLB_CONTROLm_field32_get(unit,
   1230                                               &ecmp_dlb_control_entry, DLB_IDf);
   1231             if (!dlb_enable) {
   1232                 return BCM_E_NONE;
   1233             }
   1234             /* Clear DLB fields in ECMP group table */
   1235             soc_ECMP_DLB_CONTROLm_field32_set(unit, &ecmp_dlb_control_entry,
   1236                                               GROUP_ENABLEf, 0);
   1237             soc_ECMP_DLB_CONTROLm_field32_set(unit, &ecmp_dlb_control_entry,
   1238                                               DLB_IDf, 0);
   1239             BCM_IF_ERROR_RETURN(
   1240                 WRITE_ECMP_DLB_CONTROLm(unit, MEM_BLOCK_ALL,
   1241                                     ecmp_group_idx, &ecmp_dlb_control_entry));
   1242         }
   1243 
   1244 #ifdef BCM_TRIDENT3_SUPPORT
   1245         if (soc_feature(unit, soc_feature_td3_dlb)) {
   1246             BCM_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group_idx, &ecmp_count_entry));
   1247             soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_count_entry, LB_MODEf, 0x0);
   1248             BCM_IF_ERROR_RETURN(WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group_idx, &ecmp_count_entry));
   1249             ecmp_grp_enhanced_hashing[unit][ecmp_group_idx] = 0;
   1250         }
   1251 #endif
   1252     }
   1253 
   1254     /* Free flow set table resources */
   1255     BCM_IF_ERROR_RETURN
   1256         (READ_DLB_ECMP_GROUP_CONTROLm(unit, MEM_BLOCK_ANY, dlb_id,
   1257                                       &dlb_ecmp_group_control_entry));
   1258     entry_base_ptr = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   1259             &dlb_ecmp_group_control_entry, FLOW_SET_BASEf);
   1260     flow_set_size = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   1261             &dlb_ecmp_group_control_entry, FLOW_SET_SIZEf);
   1262     membership_pointer = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   1263             &dlb_ecmp_group_control_entry, GROUP_MEMBERSHIP_POINTERf);
   1264     if (!soc_feature(unit, soc_feature_th3_style_dlb)) {
   1265         port2member_base = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   1266                 &dlb_ecmp_group_control_entry, GROUP_PORT_TO_MEMBER_BASE_ADDRf);
   1267     }
   1268 
   1269     if (delete_all_flag) {
   1270         BCM_IF_ERROR_RETURN(
   1271             _bcm_th2_ecmp_dlb_dynamic_size_decode(flow_set_size, &num_entries));
   1272         block_base_ptr =
   1273             entry_base_ptr >> _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT;
   1274         num_blocks =
   1275             num_entries >> _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT;
   1276 
   1277         _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_CLR_RANGE(unit, block_base_ptr,
   1278                                                    num_blocks);
   1279     }
   1280 
   1281     /* Clear ECMP DLB group control */
   1282     if (cleanup_flowset) {
   1283 #if defined(BCM_TOMAHAWK3_SUPPORT)
   1284         SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_GROUP_CONTROLm(unit, \
   1285                     MEM_BLOCK_ALL, dlb_id, \
   1286                     soc_mem_entry_null(unit, DLB_ECMP_GROUP_CONTROLm)));
   1287         if ((soc_feature(unit, soc_feature_th3_style_dlb))) {
   1288             if (dlb_id < soc_reg_field_length(unit,
   1289                          DLB_ID_0_TO_63_ENABLEr, BITMAPf)) {
   1290                 SOC_IF_ERROR_RETURN( \
   1291                   READ_DLB_ID_0_TO_63_ENABLEr(unit, &dlb_en_bitmap));
   1292                 COMPILER_64_BITCLR(dlb_en_bitmap, dlb_id);
   1293                 SOC_IF_ERROR_RETURN( \
   1294                   WRITE_DLB_ID_0_TO_63_ENABLEr(unit, dlb_en_bitmap));
   1295             } else {
   1296                 SOC_IF_ERROR_RETURN( \
   1297                   READ_DLB_ID_64_TO_127_ENABLEr(unit, &dlb_en_bitmap));
   1298                 COMPILER_64_BITCLR(dlb_en_bitmap, (dlb_id -
   1299                                  (soc_reg_field_length(unit,
   1300                                  DLB_ID_0_TO_63_ENABLEr, BITMAPf))));
   1301                 SOC_IF_ERROR_RETURN( \
   1302                   WRITE_DLB_ID_64_TO_127_ENABLEr(unit, dlb_en_bitmap));
   1303             }
   1304         }
   1305 #endif
   1306     }
   1307 
   1308     /* Allocate port map */
   1309     port_map_width = soc_mem_field_length(unit,
   1310             DLB_ECMP_GROUP_MEMBERSHIPm, PORT_MAPf);
   1311     alloc_size = SHR_BITALLOCSIZE(port_map_width);
   1312     port_map = sal_alloc(alloc_size, "DLB ECMP port map");
   1313     if (NULL == port_map) {
   1314         rv = BCM_E_MEMORY;
   1315         goto error;
   1316     }
   1317     sal_memset(port_map, 0, alloc_size);
   1318 
   1319     port_map2 = sal_alloc(alloc_size, "DLB ECMP port map2");
   1320     if (NULL == port_map2) {
   1321         rv = BCM_E_MEMORY;
   1322         goto error;
   1323     }
   1324     sal_memset(port_map2, 0, alloc_size);
   1325 
   1326     rv = READ_DLB_ECMP_GROUP_MEMBERSHIPm(unit, MEM_BLOCK_ANY, membership_pointer,
   1327             &dlb_ecmp_group_membership_entry);
   1328     if (BCM_FAILURE(rv)) {
   1329         goto error;
   1330     }
   1331     soc_DLB_ECMP_GROUP_MEMBERSHIPm_field_get(unit,
   1332             &dlb_ecmp_group_membership_entry, PORT_MAPf, port_map);
   1333     soc_DLB_ECMP_GROUP_MEMBERSHIPm_field_get(unit,
   1334             &dlb_ecmp_group_membership_entry, PORT_MAP_ALTERNATEf, port_map2);
   1335 
   1336     /* Allocate port map remove */
   1337     port_map_remove = sal_alloc(alloc_size, "DLB ECMP port map remove");
   1338     if (NULL == port_map_remove) {
   1339         rv = BCM_E_MEMORY;
   1340         goto error;
   1341     }
   1342     sal_memset(port_map_remove, 0, alloc_size);
   1343 
   1344     SHR_BITOR_RANGE(port_map, port_map2, 0, port_map_width, port_map);
   1345     for (port = 0; port < port_map_width; port++) {
   1346         if (!SHR_BITGET(port_map, port)) {
   1347             continue;
   1348         }
   1349         current_ptr = ECMP_DLB_PORT_LIST(unit, port);
   1350 
   1351         /*
   1352          * Traverse the port list and then delete all duplicate nodes, if any,
   1353          * in given DLB group.
   1354          */
   1355 
   1356         prev_ptr = NULL;
   1357         while (current_ptr) {
   1358             current_next = current_ptr->next;
   1359             if (current_ptr->dlb_id == dlb_id) {
   1360                 /* Duplicate nodes are always bundled together.
   1361                  * Keep the first one if duplicate notes exist.
   1362                  */
   1363                 duplicate = 0;
   1364                 if (prev_ptr &&
   1365                     prev_ptr->nh_index == current_ptr->nh_index) {
   1366                     duplicate = 1;
   1367                 }
   1368 
   1369                 if (duplicate) {
   1370                     prev_ptr->next = current_next;
   1371                     sal_free(current_ptr);
   1372                     current_ptr = NULL;
   1373                 } else {
   1374                     current_ptr->ref_count = 0;
   1375                     current_ptr->dlb_id = -1;
   1376                 }
   1377                 if (ECMP_DLB_PORT_INFO(unit, port).dlb_count <= 0) {
   1378                     rv = BCM_E_INTERNAL;
   1379                     goto error;
   1380                 }
   1381                 ECMP_DLB_PORT_INFO(unit, port).dlb_count--;
   1382             }
   1383             if (current_ptr != NULL) {
   1384                 prev_ptr = current_ptr;
   1385             }
   1386             current_ptr = current_next;
   1387         }
   1388 
   1389         if (ECMP_DLB_PORT_INFO(unit, port).dlb_count == 0) {
   1390             /* This port is now removed from all DLB Groups.
   1391              * So it's safe to remove it from link_control.
   1392              */
   1393             SHR_BITSET(port_map_remove, port);
   1394             port_map_remove_set = 1;
   1395         }
   1396     }
   1397 
   1398     if (port_map_remove_set) {
   1399         rv = READ_DLB_ECMP_LINK_CONTROLm(unit, MEM_BLOCK_ANY, 0,
   1400                     &link_control_entry);
   1401         if (BCM_FAILURE(rv)) {
   1402             goto error;
   1403         }
   1404         /* Clear software status bitmap */
   1405         status_bitmap = sal_alloc(alloc_size, "DLB ECMP member status bitmap");
   1406         if (NULL == status_bitmap) {
   1407             rv = BCM_E_MEMORY;
   1408             goto error;
   1409         }
   1410         sal_memset(status_bitmap, 0, alloc_size);
   1411         soc_DLB_ECMP_LINK_CONTROLm_field_get(unit,
   1412                 &link_control_entry, SW_PORT_STATEf, status_bitmap);
   1413         SHR_BITREMOVE_RANGE(status_bitmap, port_map_remove, 0, port_map_width,
   1414                 status_bitmap);
   1415         soc_DLB_ECMP_LINK_CONTROLm_field_set(unit,
   1416                 &link_control_entry, SW_PORT_STATEf, status_bitmap);
   1417 
   1418         /* Clear software override bitmap */
   1419         override_bitmap = sal_alloc(alloc_size, "DLB ECMP member override bitmap");
   1420         if (NULL == override_bitmap) {
   1421             rv = BCM_E_MEMORY;
   1422             goto error;
   1423         }
   1424         sal_memset(override_bitmap, 0, alloc_size);
   1425         soc_DLB_ECMP_LINK_CONTROLm_field_get(unit,
   1426                 &link_control_entry, SW_OVERRIDE_PORT_MAPf,
   1427                 override_bitmap);
   1428         SHR_BITREMOVE_RANGE(override_bitmap, port_map_remove, 0, port_map_width,
   1429                 override_bitmap);
   1430         soc_DLB_ECMP_LINK_CONTROLm_field_set(unit,
   1431                 &link_control_entry, SW_OVERRIDE_PORT_MAPf,
   1432                 override_bitmap);
   1433         rv = WRITE_DLB_ECMP_LINK_CONTROLm(unit, MEM_BLOCK_ALL, 0,
   1434                     &link_control_entry);
   1435         if (BCM_FAILURE(rv)) {
   1436             goto error;
   1437         }
   1438     }
   1439 
   1440 
   1441     /* Clear group membership */
   1442     rv = WRITE_DLB_ECMP_GROUP_MEMBERSHIPm(unit, MEM_BLOCK_ANY, membership_pointer,
   1443             soc_mem_entry_null(unit, DLB_ECMP_GROUP_MEMBERSHIPm));
   1444     if (BCM_FAILURE(rv)) {
   1445         goto error;
   1446     }
   1447 
   1448     /* Clear group port2member */
   1449     entry_size = sizeof(dlb_ecmp_group_port_to_member_entry_t);
   1450     entries_per_profile = ECMP_DLB_INFO(unit)->ecmp_dlb_port_info_size;
   1451     alloc_size = entries_per_profile * entry_size;
   1452     entry_arr = soc_cm_salloc(unit, alloc_size,
   1453                               "ECMP DLB Group Port To Member entries");
   1454     if (entry_arr == NULL) {
   1455         rv = BCM_E_MEMORY;
   1456         goto error;
   1457     }
   1458     sal_memset(entry_arr, 0, alloc_size);
   1459 
   1460     if (!(soc_feature(unit, soc_feature_th3_style_dlb))) {
   1461         index_max = port2member_base + entries_per_profile - 1;
   1462         rv = soc_mem_write_range(unit, DLB_ECMP_GROUP_PORT_TO_MEMBERm, MEM_BLOCK_ALL,
   1463                                  port2member_base, index_max, entry_arr);
   1464     }
   1465 
   1466     if (BCM_FAILURE(rv)) {
   1467         goto error;
   1468     }
   1469 
   1470     if (NULL != status_bitmap) {
   1471         sal_free(status_bitmap);
   1472     }
   1473     if (NULL != override_bitmap) {
   1474         sal_free(override_bitmap);
   1475     }
   1476     sal_free(port_map);
   1477     sal_free(port_map2);
   1478     sal_free(port_map_remove);
   1479     soc_cm_sfree(unit, entry_arr);
   1480 
   1481     /* Free DLB ID */
   1482     if ((soc_feature(unit, soc_feature_th3_style_dlb))) {
   1483         if (delete_all_flag) {
   1484             BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_id_free(unit, dlb_id));
   1485         }
   1486     } else {
   1487         BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_id_free(unit, dlb_id));
   1488     }
   1489 
   1490     return BCM_E_NONE;
   1491 
   1492 error:
   1493     if (NULL != port_map) {
   1494         sal_free(port_map);
   1495     }
   1496     if (NULL != port_map2) {
   1497         sal_free(port_map2);
   1498     }
   1499     if (NULL != port_map_remove) {
   1500         sal_free(port_map_remove);
   1501     }
   1502     if (NULL != status_bitmap) {
   1503         sal_free(status_bitmap);
   1504     }
   1505     if (NULL != override_bitmap) {
   1506         sal_free(override_bitmap);
   1507     }
   1508     if (NULL != entry_arr) {
   1509         soc_cm_sfree(unit, entry_arr);
   1510     }
   1511     return rv;
   1512 }
   1513 
   1514 /*
   1515  * Function:
   1516  *      _bcm_th2_ecmp_dlb_port_array_get
   1517  * Purpose:
   1518  *      Get ports for each ECMP member.
   1519  * Parameters:
   1520  *      unit                - (IN) SOC unit number.
   1521  *      ecmp                - (IN) ECMP group info.
   1522  *      dlb_id              - (IN) DLB group ID.
   1523  *      primary_count       - (IN) ECMP primary count..
   1524  *      intf_count          - (IN) Number of elements in intf_array.
   1525  *      intf_array          - (IN) Array of Egress forwarding objects.
   1526  *      port_array          - (OUT) Array of ports.
   1527  *      portmap_first_use   - (OUT) Port Bitmap indicates correspoinding port
   1528  *                                  in port_array being attached to ECMP Group
   1529  *                                  the first time.
   1530  *      ecmp_member_bitmap  - (IN) ECMP DLB members.
   1531  * Returns:
   1532  *      BCM_E_xxx
   1533  */
   1534 STATIC int
   1535 _bcm_th2_ecmp_dlb_port_array_get(int unit, bcm_l3_egress_ecmp_t *ecmp,
   1536                                  int dlb_id, int primary_count, int intf_count,
   1537                                  bcm_if_t *intf_array, int *port_array,
   1538                                  SHR_BITDCL *portmap_first_use,
   1539                                  SHR_BITDCL *ecmp_member_bitmap)
   1540 {
   1541     int rv = BCM_E_NONE;
   1542     int i;
   1543     _th2_ecmp_dlb_port_membership_t *current_ptr, *first_ptr;
   1544     _th2_ecmp_dlb_port_membership_t *membership = NULL;
   1545     ing_l3_next_hop_entry_t ing_nh_entry;
   1546     int mod = 0, port;
   1547     int is_local;
   1548     int nh_index;
   1549     int location_offset = 0;
   1550 #ifdef BCM_TRIDENT3_SUPPORT
   1551     uint32 dt, dv;
   1552 #endif
   1553 
   1554     /* Only alternate members exist , start from 0 instead of max_paths / 2 */
   1555     if ((ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) &&
   1556         (primary_count == 0))  {
   1557         location_offset = ecmp->max_paths / 2;
   1558     }
   1559 
   1560     for (i = 0; i < intf_count; i++) {
   1561         /* Ignore filler members */
   1562         if (!SHR_BITGET(ecmp_member_bitmap, i + location_offset)) {
   1563             continue;
   1564         }
   1565 
   1566         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf_array[i])) {
   1567             nh_index =  intf_array[i] - BCM_XGS3_EGRESS_IDX_MIN(unit);
   1568         } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf_array[i])) {
   1569             nh_index = intf_array[i] - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   1570         } else {
   1571             return BCM_E_PARAM;
   1572         }
   1573 
   1574         /* Derive port from nh_index */
   1575         rv = (READ_ING_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY,
   1576                     nh_index, &ing_nh_entry));
   1577         if (BCM_FAILURE(rv)) {
   1578             return rv;
   1579         }
   1580 #ifdef BCM_TRIDENT3_SUPPORT
   1581         if (soc_feature(unit, soc_feature_generic_dest)) {
   1582             dv = soc_mem_field32_dest_get(unit, ING_L3_NEXT_HOPm, &ing_nh_entry,
   1583                     DESTINATIONf, &dt);
   1584             if (dt == SOC_MEM_FIF_DEST_LAG) {
   1585                 /* Next hop correspond to Trunk group */
   1586                 return BCM_E_CONFIG;
   1587             } else if (dt == SOC_MEM_FIF_DEST_DGPP) {
   1588                 mod = (dv & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >>
   1589                     SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS;
   1590                 port = dv & SOC_MEM_FIF_DGPP_PORT_MASK;
   1591             } else {
   1592                 return BCM_E_PARAM;
   1593             }
   1594         } else
   1595 #endif
   1596         {
   1597             if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, Tf)) {
   1598                 /* Next hop should correspond to a single physical port. */
   1599                 return BCM_E_CONFIG;
   1600             }
   1601             if (!(soc_feature(unit, soc_feature_th3_style_dlb))) {
   1602                 mod = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry,
   1603                         MODULE_IDf);
   1604             }
   1605             port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry,
   1606                     PORT_NUMf);
   1607         }
   1608         (void) _bcm_esw_modid_is_local(unit, mod, &is_local);
   1609         if (!is_local) {
   1610             return BCM_E_PARAM;
   1611         }
   1612         port_array[i] = port;
   1613 
   1614         /* Check if DLB attributes have been set for next hop index */
   1615         current_ptr = ECMP_DLB_PORT_LIST(unit, port);
   1616         while (current_ptr) {
   1617             if (current_ptr->nh_index == nh_index) {
   1618                 break;
   1619             }
   1620             current_ptr = current_ptr->next;
   1621         }
   1622 
   1623         if (current_ptr == NULL) {
   1624             /* User did not configure DLB attributes for this next hop index */
   1625             return BCM_E_CONFIG;
   1626         }
   1627 
   1628         /* When the port is first referenced by a DLB Group, its link control
   1629          * state will be cleard. This is consitent to free_resource where
   1630          * the port is removed from all DLB Groups.
   1631          */
   1632         if (ECMP_DLB_PORT_INFO(unit, port).dlb_count == 0) {
   1633             SHR_BITSET(portmap_first_use, port);
   1634         }
   1635 
   1636         /* Continue traverse */
   1637         first_ptr = NULL;
   1638         while (current_ptr) {
   1639             if (current_ptr->nh_index != nh_index) {
   1640                 current_ptr = current_ptr->next;
   1641                 continue;
   1642             }
   1643             /* There're 3 cases when nh_index equals:
   1644              * 1) this nexthop never be used. dlb_id = -1.
   1645              * 2) this nexthop is used, and now will be used again in same dlb_id.
   1646              * 3) this nexthop is used, but now will be used in different dlb_id.
   1647  */
   1648 
   1649             if (-1 == current_ptr->dlb_id) {
   1650                 /* first case, set ref_count, dlb_id, and dlb_count.
   1651                  * And break.
   1652                  */
   1653                 current_ptr->ref_count = 1;
   1654                 current_ptr->dlb_id = dlb_id;
   1655                 ECMP_DLB_PORT_INFO(unit, port).dlb_count++;
   1656                 break;
   1657             } else if (dlb_id == current_ptr->dlb_id) {
   1658                 /* second case, just increase ref_count. And break. */
   1659                 current_ptr->ref_count++;
   1660                 break;
   1661             }
   1662             if (first_ptr == NULL) {
   1663                 /* third case, record first same nexthop node, but don't break
   1664                  * since there's still chance this dlb_id used later.
   1665                  */
   1666                 first_ptr = current_ptr;
   1667             }
   1668             current_ptr = current_ptr->next;
   1669         }
   1670 
   1671         /* deal with third case: same nexthop find but dlb_id is different.
   1672          * It's certain that first_ptr is find. We have got this covered above.
   1673          */
   1674         if (current_ptr == NULL) {
   1675             /* did not find an available node or find an existing node
   1676              * however, we record the first node with same nexthop.
   1677              * rember the rule is to bundle nodes with same nexthop.
   1678              */
   1679 
   1680             if (first_ptr == NULL) {
   1681                 /* there must exist a node with same nexthop*/
   1682                 return BCM_E_INTERNAL;
   1683             }
   1684 
   1685             membership = sal_alloc(sizeof(_th2_ecmp_dlb_port_membership_t),
   1686                     "ecmp dlb nh membership");
   1687             if (NULL == membership) {
   1688                 return BCM_E_MEMORY;
   1689             }
   1690             sal_memset(membership, 0, sizeof(_th2_ecmp_dlb_port_membership_t));
   1691 
   1692             /* this duplicate node will be placed after first one */
   1693             membership->nh_index = nh_index;
   1694             membership->ref_count = 1;
   1695             membership->dlb_id = dlb_id;
   1696             membership->next = first_ptr->next;
   1697             first_ptr->next = membership;
   1698             ECMP_DLB_PORT_INFO(unit, port).dlb_count++;
   1699         }
   1700 
   1701         if (ECMP_DLB_PORT_INFO(unit, port).dlb_count < 1) {
   1702             return BCM_E_INTERNAL;
   1703         }
   1704     }
   1705     return BCM_E_NONE;
   1706 }
   1707 
   1708 #if defined(BCM_TOMAHAWK3_SUPPORT)
   1709 /*
   1710  * Function:
   1711  *      _bcm_th3_cmp_int
   1712  * Purpose:
   1713  *      Compare two integers.
   1714  * Parameters:
   1715  *      b - first compared integer
   1716  *      a - second compared integer
   1717  * Returns:
   1718  *      a<=>b
   1719  */
   1720 static INLINE int
   1721 _bcm_th3_cmp_int(void *a, void *b)
   1722 {
   1723     int first;                  /* First compared integer. */
   1724     int second;                 /* Second compared integer. */
   1725 
   1726     first = *(int *)a;
   1727     second = *(int *)b;
   1728 
   1729     if (first < second) {
   1730         return (BCM_L3_CMP_LESS);
   1731     } else if (first > second) {
   1732         return (BCM_L3_CMP_GREATER);
   1733     }
   1734     return (BCM_L3_CMP_EQUAL);
   1735 }
   1736 #endif
   1737 
   1738 /*
   1739  * Function:
   1740  *      _bcm_th2_ecmp_dlb_set
   1741  * Purpose:
   1742  *      Configure an ECMP dynamic load balancing group.
   1743  * Parameters:
   1744  *      unit       - (IN) bcm device.
   1745  *      ecmp       - (IN) ECMP group info.
   1746  *      intf_count - (IN) Number of elements in intf_array.
   1747  *      intf_array - (IN) Array of Egress forwarding objects.
   1748  *      primary    - (IN) ECMP primary count.
   1749  *      dlb_id     - (IN) DLB id. -1:  new create, others: replace.
   1750  *      ecmp_member_bitmap   - (IN) ECMP DLB members.
   1751  * Returns:
   1752  *      BCM_E_xxx
   1753  */
   1754 STATIC int
   1755 _bcm_th2_ecmp_dlb_set(int unit, bcm_l3_egress_ecmp_t *ecmp, int intf_count,
   1756                       bcm_if_t *intf_array, int primary_count, int dlb_id,
   1757                       int *old_id, SHR_BITDCL *ecmp_member_bitmap)
   1758 {
   1759     int rv = BCM_E_NONE;
   1760     int *port_array = NULL;
   1761 #if defined(BCM_TOMAHAWK3_SUPPORT)
   1762     int *ports = NULL;
   1763 #endif
   1764     soc_mem_t mem;
   1765     int flowset_entry_size;
   1766     int mflowset_entry_size;
   1767     dlb_ecmp_flowset_entry_t *flowset_entry;
   1768     dlb_ecmp_flowset_member_entry_t *mflowset_entry;
   1769     int num_blocks;
   1770     int total_blocks;
   1771     int max_block_base_ptr;
   1772     int block_base_ptr;
   1773     int occupied;
   1774     int entry_base_ptr;
   1775     int num_entries_per_block;
   1776     int port_map_width;
   1777     int member_bitmap_width;
   1778     int member_bitmap_bitdclsize = 0;
   1779     int alloc_size;
   1780     uint32 *block_ptr = NULL;
   1781     uint32 *mblock_ptr = NULL;
   1782     int i = 0, k = 0, j = 0;
   1783     int index_min, index_max;
   1784     int flow_set_size;
   1785     int dlb_mode, primary_size = 0, primary_thd = 0;
   1786     int cost = 0, bias = 0;
   1787     SHR_BITDCL *port_map = NULL;
   1788     SHR_BITDCL *port_map2 = NULL;
   1789     SHR_BITDCL *member_bitmap = NULL;
   1790     SHR_BITDCL *port_map_first_use = NULL;
   1791     SHR_BITDCL *status_bitmap = NULL;
   1792     SHR_BITDCL *override_bitmap = NULL;
   1793     int ecmp_group_idx;
   1794     int entry_size;
   1795     int entries_per_profile;
   1796     int port;
   1797 #if defined(BCM_TOMAHAWK3_SUPPORT)
   1798     int unique_intf_count = 0;
   1799 #endif
   1800     uint32 membership_pointer;
   1801     uint32 base_addr = 0;
   1802     ecmp_dlb_control_entry_t ecmp_dlb_control_entry;
   1803     dlb_ecmp_group_control_entry_t dlb_ecmp_group_control_entry;
   1804     dlb_ecmp_group_membership_entry_t dlb_ecmp_group_membership_entry;
   1805     dlb_ecmp_link_control_entry_t link_control_entry;
   1806 #ifdef BCM_TRIDENT3_SUPPORT
   1807     ecmp_count_entry_t ecmp_count_entry;
   1808 #endif
   1809     dlb_ecmp_group_port_to_member_entry_t *entry_arr = NULL;
   1810     int *member_offset = NULL;
   1811     int dlb_member_count = 0;  /* Exclude filler member */
   1812     int location_offset = 0;
   1813 #ifdef BCM_TOMAHAWK3_SUPPORT
   1814     uint64 dlb_en_bitmap;
   1815     int unique_primary_intf_count = 0;
   1816 #endif
   1817 
   1818     if (ecmp_member_bitmap == NULL) {
   1819         return BCM_E_PARAM;
   1820     }
   1821 
   1822     if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) {
   1823         primary_size = primary_count;
   1824     } else {
   1825         primary_size = 0;
   1826     }
   1827 
   1828     if (dlb_id == -1) {
   1829         /* Allocate a DLB ID */
   1830         BCM_IF_ERROR_RETURN(
   1831             _bcm_th2_ecmp_dlb_id_alloc(unit, ecmp, &dlb_id));
   1832     }
   1833 
   1834     /* Allocate port array */
   1835     port_array = sal_alloc(sizeof(int) * intf_count,
   1836                            "ECMP DLB Ports");
   1837     if (NULL == port_array) {
   1838         rv = BCM_E_MEMORY;
   1839         goto error;
   1840     }
   1841     sal_memset(port_array, 0, sizeof(int) * intf_count);
   1842 
   1843     /* Allocate portmap first use */
   1844     port_map_width = soc_mem_field_length(unit,
   1845             DLB_ECMP_GROUP_MEMBERSHIPm, PORT_MAPf);
   1846     alloc_size = SHR_BITALLOCSIZE(port_map_width);
   1847     port_map_first_use = sal_alloc(alloc_size, "DLB ECMP port map first use");
   1848     if (NULL == port_map_first_use) {
   1849         rv = BCM_E_MEMORY;
   1850         goto error;
   1851     }
   1852     sal_memset(port_map_first_use, 0, alloc_size);
   1853 
   1854     ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   1855 
   1856     rv = _bcm_th2_ecmp_dlb_port_array_get(unit, ecmp, dlb_id,
   1857                                           primary_count, intf_count,
   1858                                           intf_array, port_array,
   1859                                           port_map_first_use, ecmp_member_bitmap);
   1860     if (BCM_FAILURE(rv)) {
   1861         goto error;
   1862     }
   1863 
   1864     if (!SHR_BITNULL_RANGE(port_map_first_use, 0, port_map_width)) {
   1865         rv = READ_DLB_ECMP_LINK_CONTROLm(unit, MEM_BLOCK_ANY, 0,
   1866                     &link_control_entry);
   1867         if (BCM_FAILURE(rv)) {
   1868             goto error;
   1869         }
   1870         /* Clear software status bitmap */
   1871         status_bitmap = sal_alloc(alloc_size, "DLB ECMP member status bitmap");
   1872         if (NULL == status_bitmap) {
   1873             rv = BCM_E_MEMORY;
   1874             goto error;
   1875         }
   1876         sal_memset(status_bitmap, 0, alloc_size);
   1877         soc_DLB_ECMP_LINK_CONTROLm_field_get(unit,
   1878                 &link_control_entry, SW_PORT_STATEf, status_bitmap);
   1879         SHR_BITREMOVE_RANGE(status_bitmap, port_map_first_use, 0, port_map_width,
   1880                 status_bitmap);
   1881         soc_DLB_ECMP_LINK_CONTROLm_field_set(unit,
   1882                 &link_control_entry, SW_PORT_STATEf, status_bitmap);
   1883 
   1884         /* Clear software override bitmap */
   1885         override_bitmap = sal_alloc(alloc_size, "DLB ECMP member override bitmap");
   1886         if (NULL == override_bitmap) {
   1887             rv = BCM_E_MEMORY;
   1888             goto error;
   1889         }
   1890         sal_memset(override_bitmap, 0, alloc_size);
   1891         soc_DLB_ECMP_LINK_CONTROLm_field_get(unit,
   1892                 &link_control_entry, SW_OVERRIDE_PORT_MAPf,
   1893                 override_bitmap);
   1894         SHR_BITREMOVE_RANGE(override_bitmap, port_map_first_use, 0, port_map_width,
   1895                 override_bitmap);
   1896         soc_DLB_ECMP_LINK_CONTROLm_field_set(unit,
   1897                 &link_control_entry, SW_OVERRIDE_PORT_MAPf,
   1898                 override_bitmap);
   1899         rv = WRITE_DLB_ECMP_LINK_CONTROLm(unit, MEM_BLOCK_ALL, 0,
   1900                     &link_control_entry);
   1901         if (BCM_FAILURE(rv)) {
   1902             goto error;
   1903         }
   1904     }
   1905 
   1906 #if defined(BCM_TOMAHAWK3_SUPPORT)
   1907     /* Allocate ports */
   1908     ports = sal_alloc(sizeof(int) * intf_count,
   1909                            "ECMP DLB Ports");
   1910     if (NULL == ports) {
   1911         rv = BCM_E_MEMORY;
   1912         goto error;
   1913     }
   1914 
   1915     sal_memset(ports, 0, sizeof(int) * intf_count);
   1916 #endif
   1917 
   1918     /* Allocate port map */
   1919     port_map_width = soc_mem_field_length(unit,
   1920             DLB_ECMP_GROUP_MEMBERSHIPm, PORT_MAPf);
   1921     alloc_size = SHR_BITALLOCSIZE(port_map_width);
   1922     port_map = sal_alloc(alloc_size, "DLB ECMP port map");
   1923     if (NULL == port_map) {
   1924         rv = BCM_E_MEMORY;
   1925         goto error;
   1926     }
   1927     sal_memset(port_map, 0, alloc_size);
   1928 
   1929     port_map2 = sal_alloc(alloc_size, "DLB ECMP port map 2");
   1930     if (NULL == port_map2) {
   1931         rv = BCM_E_MEMORY;
   1932         goto error;
   1933     }
   1934     sal_memset(port_map2, 0, alloc_size);
   1935 
   1936     member_offset = sal_alloc(intf_count * sizeof(int),
   1937                               "dlb member offset array");
   1938     if (NULL == member_offset) {
   1939         rv = BCM_E_MEMORY;
   1940         goto error;
   1941     }
   1942 
   1943     sal_memset(member_offset, 0, intf_count * sizeof(int));
   1944 
   1945     /* Only alternate members exist , start from 0 instead of max_paths / 2 */
   1946     if ((ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) &&
   1947         (primary_count == 0))  {
   1948         location_offset = ecmp->max_paths / 2;
   1949     }
   1950 
   1951     /* Allocate member bitmap */
   1952 #if defined(BCM_TOMAHAWK3_SUPPORT)
   1953     if (soc_feature(unit, soc_feature_th3_style_dlb)) {
   1954         int index = 0;
   1955         bcm_if_t *intf_array_copy;
   1956 
   1957         intf_array_copy = sal_alloc(intf_count * sizeof(int),
   1958                                   "dlb member offset array");
   1959 
   1960         if (NULL == intf_array_copy) {
   1961             rv = BCM_E_MEMORY;
   1962             goto error;
   1963         }
   1964 
   1965         if (dlb_id < soc_reg_field_length(unit,
   1966                      DLB_ID_0_TO_63_ENABLEr, BITMAPf)) {
   1967             rv = READ_DLB_ID_0_TO_63_ENABLEr(unit, &dlb_en_bitmap);
   1968             if (rv < 0) {
   1969                 goto error;
   1970             }
   1971             COMPILER_64_BITSET(dlb_en_bitmap, dlb_id);
   1972             rv = WRITE_DLB_ID_0_TO_63_ENABLEr(unit, dlb_en_bitmap);
   1973             if (rv < 0) {
   1974                 goto error;
   1975             }
   1976         } else {
   1977             rv = READ_DLB_ID_64_TO_127_ENABLEr(unit, &dlb_en_bitmap);
   1978             if (rv < 0) {
   1979                 goto error;
   1980             }
   1981             COMPILER_64_BITSET(dlb_en_bitmap, (dlb_id -
   1982                                 (soc_reg_field_length(unit,
   1983                                 DLB_ID_0_TO_63_ENABLEr, BITMAPf))));
   1984             rv = WRITE_DLB_ID_64_TO_127_ENABLEr(unit, dlb_en_bitmap);
   1985             if (rv < 0) {
   1986                 goto error;
   1987             }
   1988         }
   1989         for (i = 0; i < intf_count; i++) {
   1990             intf_array_copy[i] = intf_array[i];
   1991             if (!SHR_BITGET(ecmp_member_bitmap, i + location_offset)) {
   1992                 continue;
   1993             }
   1994             /* Construct port_map */
   1995             port = port_array[i];
   1996             if ((ecmp->dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_DGM) ||
   1997                 (i < primary_size)) {
   1998                 SHR_BITSET(port_map, port);
   1999                 /* Construct member bitmap */
   2000             } else {
   2001                 SHR_BITSET(port_map2, port);
   2002                 /* Construct member bitmap */
   2003             }
   2004             member_offset[j++] = i;
   2005         }
   2006 
   2007         _shr_sort(intf_array_copy, intf_count, sizeof(int),
   2008                   _bcm_th3_cmp_int);
   2009 
   2010         index = 0;
   2011         for (i = 1; i < intf_count; i++) {
   2012             if (intf_array_copy[i] != intf_array_copy[index]) {
   2013                 index++;
   2014                 intf_array_copy[index]  = intf_array_copy[i];
   2015             }
   2016         }
   2017 
   2018         rv = _bcm_th3_l3_ecmp_dlb_port_get(unit, ecmp, dlb_id,
   2019                                           primary_count, intf_count,
   2020                                           intf_array_copy, ports);
   2021 
   2022         if (rv != BCM_E_NONE) {
   2023             goto error;
   2024         }
   2025         for (i = 0; i < intf_count; i++) {
   2026             if (!SHR_BITGET(ecmp_member_bitmap, i + location_offset)) {
   2027                 continue;
   2028             }
   2029             if ((ecmp->dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_DGM) ||
   2030                 (i < primary_size)) {
   2031                 unique_primary_intf_count++;
   2032             }
   2033             unique_intf_count++;
   2034         }
   2035         if ((ecmp->dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_DGM) &&
   2036             (unique_intf_count > primary_count)) {
   2037             unique_intf_count = primary_count;
   2038         }
   2039         _bcm_th3_l3_ecmp_dlb_port_member_set(unit, ports, unique_primary_intf_count, unique_intf_count, dlb_id);
   2040         _bcm_th3_l3_ecmp_dlb_nhi_member_set(unit, intf_array_copy, unique_primary_intf_count, unique_intf_count, dlb_id);
   2041     } else
   2042 #endif
   2043     {
   2044         member_bitmap_width = soc_mem_field_length(unit,
   2045                 DLB_ECMP_GROUP_PORT_TO_MEMBERm, ECMP_MEMBER_BITMAPf);
   2046         member_bitmap_bitdclsize = _SHR_BITDCLSIZE(member_bitmap_width);
   2047 
   2048         entries_per_profile = ECMP_DLB_INFO(unit)->ecmp_dlb_port_info_size;
   2049         alloc_size = SHR_BITALLOCSIZE(member_bitmap_width)  * entries_per_profile;
   2050         member_bitmap = sal_alloc(alloc_size, "DLB ECMP member bitmap");
   2051         if (NULL == member_bitmap) {
   2052             rv = BCM_E_MEMORY;
   2053             goto error;
   2054         }
   2055 
   2056         sal_memset(member_bitmap, 0, alloc_size);
   2057 
   2058         /* Fulfill member bitmaps */
   2059         for (i = 0; i < intf_count; i++) {
   2060             if (!SHR_BITGET(ecmp_member_bitmap, i + location_offset)) {
   2061                 continue;
   2062             }
   2063             member_offset[j++] = i;
   2064             /* Construct port_map */
   2065             port = port_array[i];
   2066             if (ecmp->dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_DGM || i < primary_size) {
   2067                 SHR_BITSET(port_map, port);
   2068                 /* Construct member bitmap */
   2069                 SHR_BITSET(&member_bitmap[member_bitmap_bitdclsize * port], i);
   2070             } else {
   2071                 SHR_BITSET(port_map2, port);
   2072                 /* Construct member bitmap */
   2073                 SHR_BITSET(&member_bitmap[member_bitmap_bitdclsize * port],
   2074                            (i - primary_size));
   2075             }
   2076         }
   2077     }
   2078 
   2079     SHR_BITAND_RANGE(port_map, port_map2, 0, port_map_width,
   2080                      port_map_first_use);
   2081     if (!SHR_BITNULL_RANGE(port_map_first_use, 0, port_map_width)) {
   2082         /* the priamray and alternate port map should not overlap */
   2083         rv = BCM_E_PARAM;
   2084         goto error;
   2085     }
   2086 
   2087     if (!(soc_feature(unit, soc_feature_th3_style_dlb))) {
   2088         /* Allocate entry array */
   2089         mem = DLB_ECMP_GROUP_PORT_TO_MEMBERm;
   2090         entry_size = sizeof(dlb_ecmp_group_port_to_member_entry_t);
   2091         entries_per_profile = ECMP_DLB_INFO(unit)->ecmp_dlb_port_info_size;
   2092         alloc_size = entries_per_profile * entry_size;
   2093         entry_arr = soc_cm_salloc(unit, alloc_size,
   2094                                   "ECMP DLB Group Port To Member entries");
   2095         if (entry_arr == NULL) {
   2096             rv = BCM_E_MEMORY;
   2097             goto error;
   2098         }
   2099         sal_memset(entry_arr, 0, alloc_size);
   2100 
   2101         /* Construct Port To Member entries */
   2102         SHR_BITOR_RANGE(port_map, port_map2, 0, port_map_width,
   2103                         port_map_first_use);
   2104 
   2105         for (port = 0; port < entries_per_profile; port++) {
   2106             if (SHR_BITGET(port_map_first_use, port)) {
   2107                 soc_DLB_ECMP_GROUP_PORT_TO_MEMBERm_field_set(unit,
   2108                         &entry_arr[port],
   2109                         ECMP_MEMBER_BITMAPf,
   2110                         &member_bitmap[member_bitmap_bitdclsize * port]);
   2111 
   2112                 /* dlb_count only count different DLBs, a ECMP group could have
   2113                  * 2 identical nexthops (same port, 1 node),
   2114                  * 1 different nexthop (same port, 1 node)
   2115                  * however, the 3 nexthops only contributes 2 count.
   2116                  */
   2117             } else {
   2118                 sal_memcpy(&entry_arr[port],
   2119                    soc_mem_entry_null(unit, mem), entry_size);
   2120             }
   2121         }
   2122 
   2123         base_addr = dlb_id * entries_per_profile;
   2124         index_max = base_addr + entries_per_profile - 1;
   2125         rv = soc_mem_write_range(unit, DLB_ECMP_GROUP_PORT_TO_MEMBERm, MEM_BLOCK_ALL,
   2126                                  base_addr, index_max, entry_arr);
   2127         if (BCM_FAILURE(rv)) {
   2128             goto error;
   2129         }
   2130     }
   2131 
   2132     /* Construct membership entry */
   2133     membership_pointer = dlb_id;
   2134     soc_DLB_ECMP_GROUP_MEMBERSHIPm_field_set(unit,
   2135                                              &dlb_ecmp_group_membership_entry,
   2136                                              PORT_MAPf,
   2137                                              port_map);
   2138     soc_DLB_ECMP_GROUP_MEMBERSHIPm_field_set(unit,
   2139                                              &dlb_ecmp_group_membership_entry,
   2140                                              PORT_MAP_ALTERNATEf,
   2141                                              port_map2);
   2142     rv = WRITE_DLB_ECMP_GROUP_MEMBERSHIPm(unit,
   2143                                           MEM_BLOCK_ALL,
   2144                                           membership_pointer,
   2145                                           &dlb_ecmp_group_membership_entry);
   2146 
   2147     if (BCM_FAILURE(rv)) {
   2148         goto error;
   2149     }
   2150 
   2151     if (!(soc_feature(unit, soc_feature_th3_style_dlb))) {
   2152         rv = READ_ECMP_DLB_CONTROLm(unit, MEM_BLOCK_ANY, ecmp_group_idx,
   2153                 &ecmp_dlb_control_entry);
   2154         if (BCM_FAILURE(rv)) {
   2155             goto error;
   2156         }
   2157     }
   2158 
   2159     /* Set ECMP DLB group control table */
   2160     if (old_id == NULL) { /* not replace */
   2161         sal_memset(&dlb_ecmp_group_control_entry, 0,
   2162                 sizeof(dlb_ecmp_group_control_entry_t));
   2163     } else {
   2164 #if defined(BCM_TOMAHAWK3_SUPPORT)
   2165         if ((soc_feature(unit, soc_feature_th3_style_dlb))) {
   2166             *old_id = _bcm_th3_l3_ecmp_dlb_get_id(unit, ecmp_group_idx);
   2167         } else
   2168 #endif
   2169         {
   2170             *old_id = soc_ECMP_DLB_CONTROLm_field32_get
   2171                                     (unit, &ecmp_dlb_control_entry, DLB_IDf);
   2172         }
   2173         rv = READ_DLB_ECMP_GROUP_CONTROLm(unit, MEM_BLOCK_ANY, *old_id,
   2174                                       &dlb_ecmp_group_control_entry);
   2175         if (BCM_FAILURE(rv)) {
   2176             goto error;
   2177         }
   2178     }
   2179     if (!(soc_feature(unit, soc_feature_th3_style_dlb))) {
   2180         soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry,
   2181             GROUP_PORT_TO_MEMBER_BASE_ADDRf, base_addr);
   2182     }
   2183 
   2184     soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry,
   2185         GROUP_MEMBERSHIP_POINTERf, membership_pointer);
   2186 
   2187     if (old_id == NULL) { /* not replace */
   2188         /* Find a contiguous region in flow set table.
   2189          * A better practice would be: make this 2 sub-routies: alloc and free.
   2190          * And do the alloc ahead of time, to make sure the resource is available.
   2191          */
   2192 
   2193 #ifdef BCM_TRIDENT3_SUPPORT
   2194         if (soc_feature(unit, soc_feature_td3_dlb)){
   2195             if (soc_mem_index_count(unit, DLB_ECMP_FLOWSETm)) {
   2196                 rv = soc_reg_field32_modify(
   2197                         unit, ENHANCED_HASHING_CONTROLr, REG_PORT_ANY,
   2198                         RH_DLB_SELECTIONf, 0);
   2199                 if (BCM_FAILURE(rv)) {
   2200                     goto error;
   2201                 }
   2202             }
   2203         }
   2204 #endif
   2205         flowset_entry_size = sizeof(dlb_ecmp_flowset_entry_t);
   2206         mflowset_entry_size = sizeof(dlb_ecmp_flowset_member_entry_t);
   2207         num_blocks = ecmp->dynamic_size >> _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT;
   2208         total_blocks = soc_mem_index_count(unit, DLB_ECMP_FLOWSETm) >>
   2209                        _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT;
   2210         max_block_base_ptr = total_blocks - num_blocks;
   2211         for (block_base_ptr = 0;
   2212                 block_base_ptr <= max_block_base_ptr;
   2213                 block_base_ptr++) {
   2214             /* Check if the contiguous region of flow set table from
   2215              * block_base_ptr to (block_base_ptr + num_blocks - 1) is free.
   2216              */
   2217             _BCM_ECMP_DLB_FLOWSET_BLOCK_TEST_RANGE(unit, block_base_ptr, num_blocks,
   2218                     occupied);
   2219             if (!occupied) {
   2220                 break;
   2221             }
   2222         }
   2223         if (block_base_ptr > max_block_base_ptr) {
   2224             /* A contiguous region of the desired size could not be found in
   2225              * flow set table.
   2226              */
   2227             rv = BCM_E_RESOURCE;
   2228             goto error;
   2229         }
   2230 
   2231         /* Set DLB flow set table */
   2232         entry_base_ptr = block_base_ptr << _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT;
   2233         num_entries_per_block = 1 << _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT;
   2234         alloc_size = num_entries_per_block * flowset_entry_size;
   2235         block_ptr = soc_cm_salloc(unit, alloc_size,
   2236                 "Block of DLB_ECMP_FLOWSET entries");
   2237         if (NULL == block_ptr) {
   2238             rv = BCM_E_MEMORY;
   2239             goto error;
   2240         }
   2241         sal_memset(block_ptr, 0, alloc_size);
   2242 
   2243         alloc_size = num_entries_per_block * mflowset_entry_size;
   2244         mblock_ptr = soc_cm_salloc(unit, alloc_size,
   2245                 "Block of DLB_ECMP_FLOWSET_MEMBER entries");
   2246         if (NULL == mblock_ptr) {
   2247             rv = BCM_E_MEMORY;
   2248             goto error;
   2249         }
   2250         sal_memset(mblock_ptr, 0, alloc_size);
   2251 
   2252         /* Reset ECMP count excluding filler members */
   2253         SHR_BITCOUNT_RANGE(ecmp_member_bitmap, dlb_member_count,
   2254                            0, ecmp->max_paths);
   2255 
   2256         for (i = 0; i < num_blocks; i++) {
   2257             for (k = 0; k < num_entries_per_block; k++) {
   2258                 flowset_entry = soc_mem_table_idx_to_pointer(unit,
   2259                         DLB_ECMP_FLOWSETm, dlb_ecmp_flowset_entry_t *,
   2260                         block_ptr, k);
   2261                 mflowset_entry = soc_mem_table_idx_to_pointer(unit,
   2262                         DLB_ECMP_FLOWSET_MEMBERm, dlb_ecmp_flowset_member_entry_t *,
   2263                         mblock_ptr, k);
   2264                 if (dlb_member_count > 0) {
   2265                     soc_DLB_ECMP_FLOWSETm_field32_set(unit, flowset_entry,
   2266                             VALIDf, 1);
   2267                     j = (i * num_entries_per_block + k) % dlb_member_count;
   2268                     soc_DLB_ECMP_FLOWSETm_field32_set(unit, flowset_entry,
   2269                             PORT_MEMBER_ASSIGNMENTf,
   2270                             port_array[member_offset[j]]);
   2271                     if (member_offset[j] < primary_count) {
   2272                         soc_DLB_ECMP_FLOWSET_MEMBERm_field32_set(
   2273                             unit, mflowset_entry,
   2274                             ECMP_MEMBER_ASSIGNMENTf, member_offset[j]);
   2275                         soc_DLB_ECMP_FLOWSET_MEMBERm_field32_set(
   2276                             unit, mflowset_entry,
   2277                             ECMP_MEMBER_IS_ALTERNATEf, 0);
   2278                     } else {
   2279                         soc_DLB_ECMP_FLOWSET_MEMBERm_field32_set(
   2280                             unit, mflowset_entry, ECMP_MEMBER_ASSIGNMENTf,
   2281                             member_offset[j] - primary_count);
   2282                         soc_DLB_ECMP_FLOWSET_MEMBERm_field32_set(
   2283                             unit, mflowset_entry,
   2284                             ECMP_MEMBER_IS_ALTERNATEf, 1);
   2285                     }
   2286                 } else {
   2287                     soc_DLB_ECMP_FLOWSETm_field32_set(unit, flowset_entry,
   2288                             VALIDf, 0);
   2289                 }
   2290             }
   2291             index_min = entry_base_ptr + i * num_entries_per_block;
   2292             index_max = index_min + num_entries_per_block - 1;
   2293             rv = soc_mem_write_range(unit, DLB_ECMP_FLOWSETm, MEM_BLOCK_ALL,
   2294                     index_min, index_max, block_ptr);
   2295             if (BCM_FAILURE(rv)) {
   2296                 goto error;
   2297             }
   2298             rv = soc_mem_write_range(unit, DLB_ECMP_FLOWSET_MEMBERm, MEM_BLOCK_ALL,
   2299                     index_min, index_max, mblock_ptr);
   2300             if (BCM_FAILURE(rv)) {
   2301                 goto error;
   2302             }
   2303         }
   2304         _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr, num_blocks);
   2305 
   2306         soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry,
   2307                 ENABLE_OPTIMAL_CANDIDATE_UPDATEf, 1);
   2308         soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry,
   2309                 FLOW_SET_BASEf, entry_base_ptr);
   2310         rv = _bcm_th2_ecmp_dlb_dynamic_size_encode(ecmp->dynamic_size,
   2311                 &flow_set_size);
   2312         if (BCM_FAILURE(rv)) {
   2313             goto error;
   2314         }
   2315         soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry,
   2316                 FLOW_SET_SIZEf, flow_set_size);
   2317 #ifdef BCM_TRIDENT3_SUPPORT
   2318         if (soc_feature(unit, soc_feature_td3_dlb)) {
   2319             ecmp_grp_enhanced_hashing[unit][ecmp_group_idx] = 1;
   2320         }
   2321 #endif
   2322     }
   2323     switch (ecmp->dynamic_mode) {
   2324         case BCM_L3_ECMP_DYNAMIC_MODE_DGM:
   2325             primary_thd = ecmp->dgm.threshold;
   2326             cost = ecmp->dgm.cost;
   2327             bias = ecmp->dgm.bias;
   2328             dlb_mode = 0;
   2329             break;
   2330         case BCM_L3_ECMP_DYNAMIC_MODE_NORMAL:
   2331             dlb_mode = 0;
   2332             break;
   2333         case BCM_L3_ECMP_DYNAMIC_MODE_ASSIGNED:
   2334             dlb_mode = 1;
   2335             break;
   2336         case BCM_L3_ECMP_DYNAMIC_MODE_OPTIMAL:
   2337             dlb_mode = 2;
   2338             break;
   2339         default:
   2340             rv = BCM_E_PARAM;
   2341             goto error;
   2342     }
   2343     soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry,
   2344             PORT_ASSIGNMENT_MODEf, dlb_mode);
   2345     soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry,
   2346             PRIMARY_GROUP_SIZEf, primary_size);
   2347     soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry,
   2348             PRIMARY_PATH_THRESHOLDf, primary_thd);
   2349     soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry,
   2350             ALTERNATE_PATH_COSTf, cost);
   2351     soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry,
   2352             ALTERNATE_PATH_BIASf, bias);
   2353     soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry,
   2354             INACTIVITY_DURATIONf, ecmp->dynamic_age);
   2355     rv = WRITE_DLB_ECMP_GROUP_CONTROLm(unit, MEM_BLOCK_ALL, dlb_id,
   2356             &dlb_ecmp_group_control_entry);
   2357     if (BCM_FAILURE(rv)) {
   2358         goto error;
   2359     }
   2360 
   2361     /* Update ECMP DLB control table */
   2362     if (!(soc_feature(unit, soc_feature_th3_style_dlb))) {
   2363         soc_ECMP_DLB_CONTROLm_field32_set(unit, &ecmp_dlb_control_entry, GROUP_ENABLEf, 1);
   2364         soc_ECMP_DLB_CONTROLm_field32_set(unit, &ecmp_dlb_control_entry, DLB_IDf, dlb_id);
   2365         rv = WRITE_ECMP_DLB_CONTROLm(unit, MEM_BLOCK_ALL, ecmp_group_idx,
   2366                 &ecmp_dlb_control_entry);
   2367         if (BCM_FAILURE(rv)) {
   2368             goto error;
   2369         }
   2370     }
   2371 #ifdef BCM_TRIDENT3_SUPPORT
   2372     if (soc_feature(unit, soc_feature_td3_dlb)) {
   2373         rv = READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group_idx, &ecmp_count_entry);
   2374         if (BCM_FAILURE(rv)) {
   2375             goto error;
   2376         }
   2377         soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_count_entry, LB_MODEf, 0x4);
   2378         rv = WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group_idx, &ecmp_count_entry);
   2379         if (BCM_FAILURE(rv)) {
   2380             goto error;
   2381         }
   2382     }
   2383 #endif
   2384     if (NULL != status_bitmap) {
   2385         sal_free(status_bitmap);
   2386     }
   2387     if (NULL != override_bitmap) {
   2388         sal_free(override_bitmap);
   2389     }
   2390     sal_free(port_array);
   2391     sal_free(port_map);
   2392     sal_free(port_map2);
   2393     sal_free(member_offset);
   2394     if (member_bitmap) {
   2395         sal_free(member_bitmap);
   2396     }
   2397     if (entry_arr) {
   2398         soc_cm_sfree(unit, entry_arr);
   2399     }
   2400     sal_free(port_map_first_use);
   2401     if (block_ptr) {
   2402         soc_cm_sfree(unit, block_ptr);
   2403     }
   2404     if (mblock_ptr) {
   2405         soc_cm_sfree(unit, mblock_ptr);
   2406     }
   2407 
   2408 #if defined(BCM_TOMAHAWK3_SUPPORT)
   2409     if (ports) {
   2410         sal_free(ports);
   2411     }
   2412 #endif
   2413     return BCM_E_NONE;
   2414 
   2415 error:
   2416     if (dlb_id != -1) {
   2417         _bcm_th2_ecmp_dlb_id_free(unit, dlb_id);
   2418     }
   2419     if (NULL != port_array) {
   2420         sal_free(port_array);
   2421     }
   2422     if (NULL != port_map_first_use) {
   2423         sal_free(port_map_first_use);
   2424     }
   2425     if (NULL != block_ptr) {
   2426         soc_cm_sfree(unit, block_ptr);
   2427     }
   2428     if (NULL != mblock_ptr) {
   2429         soc_cm_sfree(unit, mblock_ptr);
   2430     }
   2431     if (NULL != port_map) {
   2432         sal_free(port_map);
   2433     }
   2434     if (NULL != port_map2) {
   2435         sal_free(port_map2);
   2436     }
   2437     if (NULL != member_bitmap) {
   2438         sal_free(member_bitmap);
   2439     }
   2440     if (NULL != member_offset) {
   2441         sal_free(member_offset);
   2442     }
   2443     if (NULL != entry_arr) {
   2444         soc_cm_sfree(unit, entry_arr);
   2445     }
   2446     if (NULL != status_bitmap) {
   2447         sal_free(status_bitmap);
   2448     }
   2449     if (NULL != override_bitmap) {
   2450         sal_free(override_bitmap);
   2451     }
   2452 #if defined(BCM_TOMAHAWK3_SUPPORT)
   2453     if (NULL != ports) {
   2454         sal_free(ports);
   2455     }
   2456 #endif
   2457     return rv;
   2458 }
   2459 /*
   2460  * Function:
   2461  *      bcm_th2_l3_egress_ecmp_dlb_create
   2462  * Purpose:
   2463  *      Create ECMP DLB group.
   2464  * Parameters:
   2465  *      unit       - (IN) bcm device.
   2466  *      ecmp       - (IN) ECMP group info.
   2467  *      intf_count - (IN) Number of elements in intf_array.
   2468  *      intf_array - (IN) Array of Egress forwarding objects.
   2469  *      ecmp_member_bitmap   - (IN) ECMP DLB members.
   2470  * Returns:
   2471  *      BCM_E_XXX
   2472  */
   2473 int
   2474 bcm_th2_l3_egress_ecmp_dlb_create(int unit, bcm_l3_egress_ecmp_t *ecmp,
   2475                                   int intf_count, bcm_if_t *intf_array,
   2476                                   int primary_count,
   2477                                   SHR_BITDCL *dlb_member_bitmap)
   2478 {
   2479     int dlb_enable;
   2480     int dynamic_size_encode;
   2481     int ecmp_group_idx;
   2482     uint32 hw_limit;
   2483     SHR_BITDCL *group_bitmap_ptr = NULL;
   2484 
   2485     bcm_l3_egress_ecmp_t dlb_ecmp;
   2486     int dlb_ecmp_count = 0;
   2487 
   2488     if (BCM_TH2_ECMP_IS_DLB_OR_DGM(unit, ecmp->dynamic_mode)) {
   2489         dlb_enable = 1;
   2490     } else {
   2491         dlb_enable = 0;
   2492     }
   2493 
   2494     if (dlb_enable) {
   2495         /* Verify dynamic_size */
   2496         BCM_IF_ERROR_RETURN
   2497             (_bcm_th2_ecmp_dlb_dynamic_size_encode(ecmp->dynamic_size,
   2498                                                    &dynamic_size_encode));
   2499 
   2500         /* Verify dynamic_age */
   2501         hw_limit = (1 << soc_mem_field_length(unit, DLB_ECMP_GROUP_CONTROLm,
   2502                                               INACTIVITY_DURATIONf)) - 1;
   2503         if (ecmp->dynamic_age < 16 ||
   2504             ecmp->dynamic_age > hw_limit) {
   2505             /* Hardware limits */
   2506             return BCM_E_PARAM;
   2507         }
   2508 
   2509         if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) {
   2510             if (primary_count > intf_count) {
   2511                 return BCM_E_PARAM;
   2512             }
   2513             hw_limit = (1 << soc_mem_field_length(unit, DLB_ECMP_GROUP_CONTROLm,
   2514                                                   PRIMARY_PATH_THRESHOLDf)) - 1;
   2515 
   2516             if (ecmp->dgm.threshold > hw_limit) {
   2517                 return BCM_E_PARAM;
   2518             }
   2519             hw_limit = (1 << soc_mem_field_length(unit, DLB_ECMP_GROUP_CONTROLm,
   2520                                                   ALTERNATE_PATH_COSTf)) - 1;
   2521 
   2522             if (ecmp->dgm.cost > hw_limit ||
   2523                 ecmp->dgm.bias > hw_limit) {
   2524                 return BCM_E_PARAM;
   2525             }
   2526         }
   2527     }
   2528 
   2529     /* Free resources associated with old DLB group, if exists */
   2530     ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   2531 
   2532     if (ecmp->flags & BCM_L3_REPLACE) {
   2533 
   2534 #if defined(BCM_TOMAHAWK3_SUPPORT)
   2535         if ((!dlb_enable) && (soc_feature(unit, soc_feature_th3_style_dlb))) {
   2536             return BCM_E_NONE;
   2537         }
   2538 #endif
   2539 
   2540         bcm_l3_egress_ecmp_t_init(&dlb_ecmp);
   2541         dlb_ecmp.ecmp_intf = ecmp->ecmp_intf;
   2542         BCM_IF_ERROR_RETURN(
   2543             _bcm_esw_l3_egress_ecmp_get(unit, &dlb_ecmp, 0, NULL,
   2544                                         &dlb_ecmp_count, TRUE));
   2545         if (dlb_enable /* also indicates it was created before */
   2546             && dlb_ecmp.dynamic_mode == ecmp->dynamic_mode
   2547             && dlb_ecmp.dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_ASSIGNED
   2548             && dlb_ecmp.dynamic_size == ecmp->dynamic_size) {
   2549             int old_id = 0, dlb_id;
   2550 
   2551             /* Do new style replace only if free resources left */
   2552             if (BCM_E_NONE == _bcm_th2_ecmp_dlb_id_alloc(
   2553                                   unit, ecmp, &dlb_id)) {
   2554                 if ((soc_feature(unit, soc_feature_th3_style_dlb))) {
   2555                     BCM_IF_ERROR_RETURN(
   2556                         _bcm_th2_ecmp_dlb_free_resource(unit, ecmp_group_idx,
   2557                                                         old_id, FALSE));
   2558                 }
   2559                 BCM_IF_ERROR_RETURN(
   2560                     _bcm_th2_ecmp_dlb_set(unit, ecmp, intf_count, intf_array,
   2561                                           primary_count, dlb_id,
   2562                                           &old_id, dlb_member_bitmap));
   2563                 if (!(soc_feature(unit, soc_feature_th3_style_dlb))) {
   2564                     BCM_IF_ERROR_RETURN(
   2565                         _bcm_th2_ecmp_dlb_free_resource(unit, ecmp_group_idx,
   2566                                                         old_id, FALSE));
   2567                 }
   2568                 return BCM_E_NONE;
   2569             }
   2570         }
   2571     }
   2572 
   2573 #ifdef BCM_TOMAHAWK3_SUPPORT
   2574     if (soc_feature(unit, soc_feature_th3_style_dlb) && 
   2575             (ecmp->flags & BCM_L3_REPLACE)) {
   2576         int dlb_num, rv = 0;
   2577         dlb_num = _bcm_th3_l3_ecmp_dlb_get_id(unit, ecmp->ecmp_intf
   2578                                    - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit));
   2579 
   2580         /* If the dynamic size for the new dlb id is greater than the one
   2581            being replaced and also greater than the FLOWSET block size (256),
   2582            we need to check if we have enough free resources
   2583            for the extra size. If we do have free resources, we go ahead
   2584            and clean up the old dlb id. Otherwise, we do not clean up and
   2585            this way we do not destroy the old dlb id when replace fails
   2586         */
   2587         if (ecmp->dynamic_size > dlb_ecmp.dynamic_size &&
   2588             ecmp->dynamic_size > (1 << _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT)) {
   2589             rv = _bcm_th3_l3_egress_ecmp_dlb_resource_validate(unit, ecmp,
   2590                                           dlb_num);
   2591         }
   2592 
   2593         if ((rv == BCM_E_NONE)) {
   2594             BCM_IF_ERROR_RETURN(
   2595                 _bcm_th2_ecmp_dlb_free_resource(unit, ecmp_group_idx, -1, TRUE));
   2596         } else {
   2597             return rv;  
   2598         }
   2599     } else
   2600 #endif
   2601     {
   2602         BCM_IF_ERROR_RETURN(
   2603             _bcm_th2_ecmp_dlb_free_resource(unit, ecmp_group_idx, -1, TRUE));
   2604     }
   2605 
   2606     if (dlb_enable) {
   2607         /* Set new DLB group */
   2608         BCM_IF_ERROR_RETURN(
   2609             _bcm_th2_ecmp_dlb_set(unit, ecmp, intf_count, intf_array,
   2610                                   primary_count, -1, NULL, dlb_member_bitmap));
   2611     } else {
   2612         /*  Clear DLB bitmap */
   2613         group_bitmap_ptr =
   2614             BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx);
   2615         SHR_BITCLR_RANGE(group_bitmap_ptr, 0,
   2616                          BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2);
   2617     }
   2618 
   2619     return BCM_E_NONE;
   2620 }
   2621 
   2622 /*
   2623  * Function:
   2624  *      bcm_th2_l3_egress_ecmp_dlb_destroy
   2625  * Purpose:
   2626  *      Destroy an ECMP DLB group.
   2627  * Parameters:
   2628  *      unit       - (IN) bcm device.
   2629  *      mpintf     - (IN) L3 interface id pointing to Egress multipath object.
   2630  * Returns:
   2631  *      BCM_E_XXX
   2632  */
   2633 int
   2634 bcm_th2_l3_egress_ecmp_dlb_destroy(int unit, bcm_if_t mpintf)
   2635 {
   2636     int ecmp_group_idx;
   2637     SHR_BITDCL *group_bitmap_ptr = NULL;
   2638 
   2639     /* Free resources associated with old DLB group, if exists */
   2640     ecmp_group_idx = mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   2641     BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_free_resource(unit,
   2642                                   ecmp_group_idx, -1, TRUE));
   2643     /*  Clear DLB bitmap */
   2644     group_bitmap_ptr =
   2645         BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx);
   2646     SHR_BITCLR_RANGE(group_bitmap_ptr, 0,
   2647                      BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2);
   2648     return BCM_E_NONE;
   2649 }
   2650 
   2651 /*
   2652  * Function:
   2653  *      bcm_th2_l3_egress_ecmp_dlb_get
   2654  * Purpose:
   2655  *      Get info about an ECMP DLB group.
   2656  * Parameters:
   2657  *      unit       - (IN) bcm device.
   2658  *      ecmp       - (IN/OUT) ECMP group info.
   2659  * Returns:
   2660  *      BCM_E_XXX
   2661  */
   2662 int
   2663 bcm_th2_l3_egress_ecmp_dlb_get(int unit, bcm_l3_egress_ecmp_t *ecmp)
   2664 {
   2665     int ecmp_group_idx;
   2666     ecmp_dlb_control_entry_t ecmp_group_entry;
   2667     int group_enable, dlb_id;
   2668     dlb_ecmp_group_control_entry_t dlb_ecmp_group_control_entry;
   2669     int dlb_mode, primary_size, primary_thd, cost, bias;
   2670     int flow_set_size;
   2671 
   2672     /* Get DLB ID */
   2673     ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   2674 
   2675     ecmp->dynamic_mode = 0;
   2676     ecmp->dynamic_size = 0;
   2677     ecmp->dynamic_age = 0;
   2678     ecmp->dgm.threshold = 0;
   2679     ecmp->dgm.cost = 0;
   2680     ecmp->dgm.bias = 0;
   2681 
   2682 #if defined(BCM_TOMAHAWK3_SUPPORT)
   2683     if (soc_feature(unit, soc_feature_th3_style_dlb)) {
   2684         if (ecmp_group_idx < BCM_TH3_L3_ECMP_DLB_START(unit)) {
   2685             return BCM_E_NONE;
   2686         }
   2687         dlb_id = _bcm_th3_l3_ecmp_dlb_get_id(unit, ecmp_group_idx);
   2688     } else
   2689 #endif
   2690     {
   2691         BCM_IF_ERROR_RETURN(READ_ECMP_DLB_CONTROLm(unit, MEM_BLOCK_ANY,
   2692                     ecmp_group_idx, &ecmp_group_entry));
   2693         group_enable = soc_ECMP_DLB_CONTROLm_field32_get(unit,
   2694                                             &ecmp_group_entry,
   2695                                             GROUP_ENABLEf);
   2696         if (!group_enable) {
   2697             return BCM_E_NONE;
   2698         }
   2699         dlb_id = soc_ECMP_DLB_CONTROLm_field32_get(unit,
   2700                             &ecmp_group_entry, DLB_IDf);
   2701     }
   2702 
   2703     /* Get dynamic_mode */
   2704     BCM_IF_ERROR_RETURN(READ_DLB_ECMP_GROUP_CONTROLm(unit, MEM_BLOCK_ANY,
   2705                 dlb_id, &dlb_ecmp_group_control_entry));
   2706     dlb_mode = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   2707             &dlb_ecmp_group_control_entry, PORT_ASSIGNMENT_MODEf);
   2708     primary_size = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   2709             &dlb_ecmp_group_control_entry, PRIMARY_GROUP_SIZEf);
   2710     primary_thd = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   2711             &dlb_ecmp_group_control_entry, PRIMARY_PATH_THRESHOLDf);
   2712     cost = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   2713             &dlb_ecmp_group_control_entry, ALTERNATE_PATH_COSTf);
   2714     bias = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   2715             &dlb_ecmp_group_control_entry, ALTERNATE_PATH_BIASf);
   2716     switch (dlb_mode) {
   2717         case 0:
   2718             if (primary_size == 0 &&
   2719                 !_BCM_ECMP_DLB_ID_DGM_GET(unit, dlb_id)) {
   2720                 ecmp->dynamic_mode = BCM_L3_ECMP_DYNAMIC_MODE_NORMAL;
   2721             } else {
   2722                 ecmp->dynamic_mode = BCM_L3_ECMP_DYNAMIC_MODE_DGM;
   2723                 ecmp->dgm.threshold = primary_thd;
   2724                 ecmp->dgm.cost      = cost;
   2725                 ecmp->dgm.bias      = bias;
   2726             }
   2727             /* In L1 warmboot, empty group's dgm mode cannot be recovered */
   2728 #ifdef BCM_WARM_BOOT_SUPPORT
   2729             if (SOC_WARM_BOOT(unit)) {
   2730                 if (!ECMP_DLB_INFO(unit)->recovered_from_scache &&
   2731                     ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) {
   2732                     /* If already recovered from scache, do nothing. */
   2733                     _BCM_ECMP_DLB_ID_DGM_SET(unit, dlb_id);
   2734                 }
   2735             }
   2736 #endif /* BCM_WARM_BOOT_SUPPORT */
   2737 
   2738             break;
   2739         case 1:
   2740             ecmp->dynamic_mode = BCM_L3_ECMP_DYNAMIC_MODE_ASSIGNED;
   2741             break;
   2742         case 2:
   2743             ecmp->dynamic_mode = BCM_L3_ECMP_DYNAMIC_MODE_OPTIMAL;
   2744             break;
   2745         default:
   2746             return BCM_E_INTERNAL;
   2747     }
   2748 
   2749     /* Get dynamic_size */
   2750     flow_set_size = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   2751             &dlb_ecmp_group_control_entry, FLOW_SET_SIZEf);
   2752     BCM_IF_ERROR_RETURN
   2753         (_bcm_th2_ecmp_dlb_dynamic_size_decode(flow_set_size,
   2754                                                (int *)&ecmp->dynamic_size));
   2755 
   2756     /* Get dynamic_age */
   2757     ecmp->dynamic_age = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   2758             &dlb_ecmp_group_control_entry, INACTIVITY_DURATIONf);
   2759 
   2760     return BCM_E_NONE;
   2761 }
   2762 
   2763 /*
   2764  * Function:
   2765  *      _bcm_th2_l3_egress_ecmp_port_status_set
   2766  * Purpose:
   2767  *      Set ECMP DLB port status.
   2768  * Parameters:
   2769  *      unit    - (IN) SOC unit number.
   2770  *      port    - (IN) Port, not Gport.
   2771  *      status  - (IN) ECMP port status.
   2772  * Returns:
   2773  *      BCM_E_xxx
   2774  */
   2775 int
   2776 _bcm_th2_l3_egress_ecmp_port_status_set(int unit, bcm_port_t port, int status)
   2777 {
   2778     dlb_ecmp_link_control_entry_t link_control_entry;
   2779     int status_width, alloc_size;
   2780     SHR_BITDCL *status_bitmap = NULL;
   2781     SHR_BITDCL *override_bitmap = NULL;
   2782     int rv = BCM_E_NONE;
   2783 
   2784     soc_mem_lock(unit, DLB_ECMP_LINK_CONTROLm);
   2785     /* Get status bitmap */
   2786     rv = READ_DLB_ECMP_LINK_CONTROLm(unit, MEM_BLOCK_ANY, 0,
   2787                 &link_control_entry);
   2788     if (BCM_FAILURE(rv)) {
   2789         soc_mem_unlock(unit, DLB_ECMP_LINK_CONTROLm);
   2790         return rv;
   2791     }
   2792     status_width = soc_mem_field_length(unit, DLB_ECMP_LINK_CONTROLm,
   2793             SW_PORT_STATEf);
   2794     alloc_size = SHR_BITALLOCSIZE(status_width);
   2795     status_bitmap = sal_alloc(alloc_size, "DLB ECMP port status bitmap");
   2796     if (NULL == status_bitmap) {
   2797         soc_mem_unlock(unit, DLB_ECMP_LINK_CONTROLm);
   2798         return BCM_E_MEMORY;
   2799     }
   2800     sal_memset(status_bitmap, 0, alloc_size);
   2801     soc_DLB_ECMP_LINK_CONTROLm_field_get(unit, &link_control_entry,
   2802             SW_PORT_STATEf, status_bitmap);
   2803 
   2804     /* Get override bitmap */
   2805     override_bitmap = sal_alloc(alloc_size, "DLB ECMP port override bitmap");
   2806     if (NULL == override_bitmap) {
   2807         soc_mem_unlock(unit, DLB_ECMP_LINK_CONTROLm);
   2808         sal_free(status_bitmap);
   2809         return BCM_E_MEMORY;
   2810     }
   2811     sal_memset(override_bitmap, 0, alloc_size);
   2812     soc_DLB_ECMP_LINK_CONTROLm_field_get(unit, &link_control_entry,
   2813             SW_OVERRIDE_PORT_MAPf, override_bitmap);
   2814 
   2815     /* Update status and override bitmaps*/
   2816 
   2817     switch (status) {
   2818         case BCM_L3_ECMP_DYNAMIC_MEMBER_FORCE_DOWN:
   2819             SHR_BITSET(override_bitmap, port);
   2820             SHR_BITCLR(status_bitmap, port);
   2821             break;
   2822         case BCM_L3_ECMP_DYNAMIC_MEMBER_FORCE_UP:
   2823             SHR_BITSET(override_bitmap, port);
   2824             SHR_BITSET(status_bitmap, port);
   2825             break;
   2826         case BCM_L3_ECMP_DYNAMIC_MEMBER_HW:
   2827             SHR_BITCLR(override_bitmap, port);
   2828             SHR_BITCLR(status_bitmap, port);
   2829             break;
   2830         default:
   2831             sal_free(status_bitmap);
   2832             sal_free(override_bitmap);
   2833             soc_mem_unlock(unit, DLB_ECMP_LINK_CONTROLm);
   2834             return BCM_E_PARAM;
   2835     }
   2836 
   2837     /* Write status and override bitmaps to hardware */
   2838     soc_DLB_ECMP_LINK_CONTROLm_field_set(unit, &link_control_entry,
   2839             SW_PORT_STATEf, status_bitmap);
   2840     soc_DLB_ECMP_LINK_CONTROLm_field_set(unit, &link_control_entry,
   2841             SW_OVERRIDE_PORT_MAPf, override_bitmap);
   2842     sal_free(status_bitmap);
   2843     sal_free(override_bitmap);
   2844     rv = WRITE_DLB_ECMP_LINK_CONTROLm(unit, MEM_BLOCK_ALL, 0,
   2845                                          &link_control_entry);
   2846 
   2847     soc_mem_unlock(unit, DLB_ECMP_LINK_CONTROLm);
   2848     return rv;
   2849 }
   2850 
   2851 /*
   2852  * Function:
   2853  *      _bcm_th2_l3_egress_ecmp_port_status_get
   2854  * Purpose:
   2855  *      Get ECMP DLB port status.
   2856  * Parameters:
   2857  *      unit    - (IN) SOC unit number.
   2858  *      port    - (IN) Port, not Gport.
   2859  *      status  - (OUT) ECMP port status.
   2860  * Returns:
   2861  *      BCM_E_xxx
   2862  */
   2863 int
   2864 _bcm_th2_l3_egress_ecmp_port_status_get(int unit, bcm_port_t port, int *status)
   2865 {
   2866     int rv = BCM_E_NONE;
   2867     dlb_ecmp_link_control_entry_t link_control_entry;
   2868     int status_width, alloc_size;
   2869     SHR_BITDCL *status_bitmap = NULL;
   2870     SHR_BITDCL *override_bitmap = NULL;
   2871     SHR_BITDCL *hw_status_bitmap = NULL;
   2872     dlb_ecmp_port_state_entry_t hw_state;
   2873 
   2874     /* Get status bitmap */
   2875     BCM_IF_ERROR_RETURN(READ_DLB_ECMP_LINK_CONTROLm(unit, MEM_BLOCK_ANY, 0,
   2876                 &link_control_entry));
   2877     status_width = soc_mem_field_length(unit, DLB_ECMP_LINK_CONTROLm,
   2878             SW_PORT_STATEf);
   2879     alloc_size = SHR_BITALLOCSIZE(status_width);
   2880     status_bitmap = sal_alloc(alloc_size, "DLB ECMP port status bitmap");
   2881     if (NULL == status_bitmap) {
   2882         return BCM_E_MEMORY;
   2883     }
   2884     sal_memset(status_bitmap, 0, alloc_size);
   2885     soc_DLB_ECMP_LINK_CONTROLm_field_get(unit, &link_control_entry,
   2886             SW_PORT_STATEf, status_bitmap);
   2887 
   2888     /* Get override bitmap */
   2889     override_bitmap = sal_alloc(alloc_size, "DLB ECMP port override bitmap");
   2890     if (NULL == override_bitmap) {
   2891         sal_free(status_bitmap);
   2892         return BCM_E_MEMORY;
   2893     }
   2894     sal_memset(override_bitmap, 0, alloc_size);
   2895     soc_DLB_ECMP_LINK_CONTROLm_field_get(unit, &link_control_entry,
   2896             SW_OVERRIDE_PORT_MAPf, override_bitmap);
   2897 
   2898     /* Derive status from software override and status bitmaps or
   2899      * hardware state bitmap.
   2900      */
   2901     if (SHR_BITGET(override_bitmap, port)) {
   2902         if (SHR_BITGET(status_bitmap, port)) {
   2903             *status = BCM_L3_ECMP_DYNAMIC_MEMBER_FORCE_UP;
   2904         } else {
   2905             *status = BCM_L3_ECMP_DYNAMIC_MEMBER_FORCE_DOWN;
   2906         }
   2907     } else {
   2908         /* Get hardware bitmap */
   2909         hw_status_bitmap = sal_alloc(alloc_size, "DLB ECMP member hw status bitmap");
   2910         if (NULL == hw_status_bitmap) {
   2911             sal_free(status_bitmap);
   2912             sal_free(override_bitmap);
   2913             return BCM_E_MEMORY;
   2914         }
   2915         sal_memset(hw_status_bitmap, 0, alloc_size);
   2916 
   2917         rv = READ_DLB_ECMP_PORT_STATEm(unit, MEM_BLOCK_ANY, 0, &hw_state);
   2918         if (BCM_FAILURE(rv)) {
   2919             sal_free(status_bitmap);
   2920             sal_free(override_bitmap);
   2921             sal_free(hw_status_bitmap);
   2922             return rv;
   2923         }
   2924         soc_DLB_ECMP_PORT_STATEm_field_get(unit, &hw_state,
   2925                 BITMAPf, hw_status_bitmap);
   2926         if (SHR_BITGET(hw_status_bitmap, port)) {
   2927             *status = BCM_L3_ECMP_DYNAMIC_MEMBER_HW_UP;
   2928         } else {
   2929             *status = BCM_L3_ECMP_DYNAMIC_MEMBER_HW_DOWN;
   2930         }
   2931     }
   2932 
   2933     /* Cleanup */
   2934     sal_free(status_bitmap);
   2935     sal_free(override_bitmap);
   2936     if (NULL != hw_status_bitmap) {
   2937         sal_free(hw_status_bitmap);
   2938     }
   2939 
   2940     return BCM_E_NONE;
   2941 }
   2942 
   2943 
   2944 /*
   2945  * Function:
   2946  *      bcm_th2_l3_egress_ecmp_member_status_set
   2947  * Purpose:
   2948  *      Set ECMP DLB member status.
   2949  * Parameters:
   2950  *      unit    - (IN) SOC unit number.
   2951  *      intf    - (IN) L3 Interface ID pointing to an Egress forwarding object.
   2952  *      status  - (IN) ECMP member status.
   2953  * Returns:
   2954  *      BCM_E_xxx
   2955  */
   2956 int
   2957 bcm_th2_l3_egress_ecmp_member_status_set(int unit, bcm_if_t intf, int status)
   2958 {
   2959     int nh_index;
   2960     int old_status;
   2961     int mod = 0, port;
   2962     int is_local;
   2963     ing_l3_next_hop_entry_t ing_nh_entry;
   2964     _th2_ecmp_dlb_port_membership_t *current_ptr;
   2965 #ifdef BCM_TRIDENT3_SUPPORT
   2966     uint32 dt, dv;
   2967 #endif
   2968 
   2969     /* Derive next hop index */
   2970     if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) {
   2971         nh_index = intf - BCM_XGS3_EGRESS_IDX_MIN(unit);
   2972     } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) {
   2973         nh_index = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   2974     } else {
   2975         return BCM_E_PARAM;
   2976     }
   2977 
   2978     /* Derive port from nh_index */
   2979     BCM_IF_ERROR_RETURN(READ_ING_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY,
   2980                 nh_index, &ing_nh_entry));
   2981 
   2982 #ifdef BCM_TRIDENT3_SUPPORT
   2983     if (soc_feature(unit, soc_feature_generic_dest)) {
   2984         dv = soc_mem_field32_dest_get(unit, ING_L3_NEXT_HOPm, &ing_nh_entry,
   2985                 DESTINATIONf, &dt);
   2986         if (dt == SOC_MEM_FIF_DEST_LAG) {
   2987             /* Next hop correspond to Trunk group */
   2988             return BCM_E_CONFIG;
   2989         } else if (dt == SOC_MEM_FIF_DEST_DGPP) {
   2990             mod = (dv & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >>
   2991                 SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS;
   2992             port = dv & SOC_MEM_FIF_DGPP_PORT_MASK;
   2993         } else {
   2994             return BCM_E_PARAM;
   2995         }
   2996     } else
   2997 #endif
   2998         {
   2999             if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, Tf)) {
   3000                 /* Next hop should correspond to a single physical port. */
   3001                 return BCM_E_CONFIG;
   3002             }
   3003             if (!(soc_feature(unit, soc_feature_th3_style_dlb))) {
   3004                 mod = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry,
   3005                         MODULE_IDf);
   3006             }
   3007             port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry,
   3008                     PORT_NUMf);
   3009         }
   3010     if (!(soc_feature(unit, soc_feature_th3_style_dlb))) {
   3011         (void) _bcm_esw_modid_is_local(unit, mod, &is_local);
   3012         if (!is_local) {
   3013             return BCM_E_PARAM;
   3014         }
   3015     }
   3016 
   3017     /* Verify that the nh_index is with DLB arrtibutes. */
   3018     current_ptr = ECMP_DLB_PORT_LIST(unit, port);
   3019     while (current_ptr) {
   3020         if (nh_index == current_ptr->nh_index &&
   3021             current_ptr->dlb_id != -1) {
   3022             break;
   3023         }
   3024         current_ptr = current_ptr->next;
   3025     }
   3026 
   3027     if (current_ptr == NULL) {
   3028         return BCM_E_NOT_FOUND;
   3029     }
   3030 
   3031     if (!ECMP_DLB_INFO(unit)->ecmp_dlb_property_force_set &&
   3032         ECMP_DLB_PORT_INFO(unit, port).nh_count > 1) {
   3033         BCM_IF_ERROR_RETURN
   3034         (_bcm_th2_l3_egress_ecmp_port_status_get(unit, port, &old_status));
   3035 
   3036         if (old_status == BCM_L3_ECMP_DYNAMIC_MEMBER_HW_UP ||
   3037             old_status == BCM_L3_ECMP_DYNAMIC_MEMBER_HW_DOWN) {
   3038             old_status = BCM_L3_ECMP_DYNAMIC_MEMBER_HW;
   3039         }
   3040 
   3041         if (status != old_status) {
   3042             return BCM_E_BUSY;
   3043         } else {
   3044             return BCM_E_NONE;
   3045         }
   3046     }
   3047 
   3048     return _bcm_th2_l3_egress_ecmp_port_status_set(unit, port, status);
   3049 }
   3050 
   3051 /*
   3052  * Function:
   3053  *      bcm_th2_l3_egress_ecmp_member_status_get
   3054  * Purpose:
   3055  *      Get ECMP DLB member status.
   3056  * Parameters:
   3057  *      unit    - (IN) SOC unit number.
   3058  *      intf    - (IN) L3 Interface ID pointing to an Egress forwarding object.
   3059  *      status  - (OUT) ECMP member status.
   3060  * Returns:
   3061  *      BCM_E_xxx
   3062  */
   3063 int
   3064 bcm_th2_l3_egress_ecmp_member_status_get(int unit, bcm_if_t intf, int *status)
   3065 {
   3066     int nh_index;
   3067     int port = 0;
   3068     ing_l3_next_hop_entry_t ing_nh_entry;
   3069     _th2_ecmp_dlb_port_membership_t *current_ptr;
   3070 #ifdef BCM_TRIDENT3_SUPPORT
   3071     uint32 dt, dv;
   3072 #endif
   3073 
   3074     if (NULL == status) {
   3075         return BCM_E_PARAM;
   3076     }
   3077 
   3078     /* Derive next hop index */
   3079     if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) {
   3080         nh_index = intf - BCM_XGS3_EGRESS_IDX_MIN(unit);
   3081     } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) {
   3082         nh_index = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   3083     } else {
   3084         return BCM_E_PARAM;
   3085     }
   3086 
   3087     /* Derive port from nh_index */
   3088     BCM_IF_ERROR_RETURN(READ_ING_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY,
   3089                 nh_index, &ing_nh_entry));
   3090 #ifdef BCM_TRIDENT3_SUPPORT
   3091     if (soc_feature(unit, soc_feature_generic_dest)) {
   3092         dv = soc_mem_field32_dest_get(unit, ING_L3_NEXT_HOPm, &ing_nh_entry,
   3093                 DESTINATIONf, &dt);
   3094         if (dt == SOC_MEM_FIF_DEST_DGPP) {
   3095             port = dv & SOC_MEM_FIF_DGPP_PORT_MASK;
   3096         } else {
   3097             return BCM_E_PARAM;
   3098         }
   3099 
   3100     } else
   3101 #endif
   3102     {
   3103         port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry,
   3104                 PORT_NUMf);
   3105     }
   3106     /* Verify that the nh_index is with DLB arrtibutes. */
   3107     current_ptr = ECMP_DLB_PORT_LIST(unit, port);
   3108     while (current_ptr) {
   3109         if (nh_index == current_ptr->nh_index &&
   3110             current_ptr->dlb_id != -1) {
   3111             break;
   3112         }
   3113         current_ptr = current_ptr->next;
   3114     }
   3115 
   3116     if (current_ptr == NULL) {
   3117         return BCM_E_NOT_FOUND;
   3118     }
   3119 
   3120     return _bcm_th2_l3_egress_ecmp_port_status_get(unit, port, status);
   3121 }
   3122 /*
   3123  * Function:
   3124  *      bcm_th2_l3_egress_ecmp_dlb_ethertype_set
   3125  * Purpose:
   3126  *      Set the Ethertypes that are eligible or ineligible for
   3127  *      ECMP dynamic load balancing.
   3128  * Parameters:
   3129  *      unit            - (IN) Unit number.
   3130  *      flags           - (IN) BCM_L3_ECMP_DYNAMIC_ETHERTYPE_xxx flags.
   3131  *      ethertype_count - (IN) Number of elements in ethertype_array.
   3132  *      ethertype_array - (IN) Array of Ethertypes.
   3133  * Returns:
   3134  *      BCM_E_XXX
   3135  */
   3136 int
   3137 bcm_th2_l3_egress_ecmp_dlb_ethertype_set(
   3138     int unit,
   3139     uint32 flags,
   3140     int ethertype_count,
   3141     int *ethertype_array)
   3142 {
   3143     int i, j;
   3144     dlb_ecmp_eem_configuration_entry_t eem_entry;
   3145     dlb_ecmp_ethertype_eligibility_map_entry_t ethertype_entry;
   3146 #ifdef BCM_TRIDENT3_SUPPORT
   3147     uint32 reg_val = 0;
   3148 #endif
   3149 
   3150     /* Input check */
   3151     if ((ethertype_count > 0) && (NULL == ethertype_array)) {
   3152         return BCM_E_PARAM;
   3153     }
   3154     if (ethertype_count > soc_mem_index_count(unit,
   3155                 DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm)) {
   3156         return BCM_E_RESOURCE;
   3157     }
   3158 #ifdef BCM_TOMAHAWK3_SUPPORT
   3159     if ((soc_feature(unit, soc_feature_th3_style_dlb)) &&
   3160         (flags & BCM_L3_ECMP_DYNAMIC_ETHERTYPE_INNER)) {
   3161         return BCM_E_PARAM;
   3162     }
   3163 #endif
   3164     /* Update quality measure control register */
   3165 #ifdef BCM_TRIDENT3_SUPPORT
   3166     if (soc_feature(unit, soc_feature_td3_dlb)) {
   3167         BCM_IF_ERROR_RETURN(READ_DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr(unit,
   3168                     &reg_val));
   3169         soc_reg_field_set(unit, DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr,
   3170                 &reg_val, CONFIGURATIONf,
   3171                 flags & BCM_L3_ECMP_DYNAMIC_ETHERTYPE_ELIGIBLE ? 1 : 0);
   3172         soc_reg_field_set(unit, DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr,
   3173                 &reg_val, INNER_OUTER_ETHERTYPE_SELECTIONf,
   3174                 flags & BCM_L3_ECMP_DYNAMIC_ETHERTYPE_INNER ? 1 : 0);
   3175         BCM_IF_ERROR_RETURN(WRITE_DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr(unit,
   3176                     reg_val));
   3177     } else
   3178 #endif
   3179     {
   3180         BCM_IF_ERROR_RETURN(READ_DLB_ECMP_EEM_CONFIGURATIONm(unit,
   3181                     MEM_BLOCK_ANY, 0, &eem_entry));
   3182         soc_DLB_ECMP_EEM_CONFIGURATIONm_field32_set(unit,
   3183                 &eem_entry, CONFIGURATIONf,
   3184                 flags & BCM_L3_ECMP_DYNAMIC_ETHERTYPE_ELIGIBLE ? 1 : 0);
   3185         if (!(soc_feature(unit, soc_feature_th3_style_dlb))) {
   3186             soc_DLB_ECMP_EEM_CONFIGURATIONm_field32_set(unit,
   3187                     &eem_entry, INNER_OUTER_ETHERTYPE_SELECTIONf,
   3188                     flags & BCM_L3_ECMP_DYNAMIC_ETHERTYPE_INNER ? 1 : 0);
   3189         }
   3190         BCM_IF_ERROR_RETURN(WRITE_DLB_ECMP_EEM_CONFIGURATIONm(unit,
   3191                     MEM_BLOCK_ALL, 0, &eem_entry));
   3192     }
   3193     /* Update Ethertype eligibility map table */
   3194     for (i = 0; i < ethertype_count; i++) {
   3195         sal_memset(&ethertype_entry, 0,
   3196                 sizeof(dlb_ecmp_ethertype_eligibility_map_entry_t));
   3197         soc_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_set(unit,
   3198                 &ethertype_entry, VALIDf, 1);
   3199         soc_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_set(unit,
   3200                 &ethertype_entry, ETHERTYPEf, ethertype_array[i] & 0xFFFF);
   3201         BCM_IF_ERROR_RETURN(WRITE_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm(unit,
   3202                     MEM_BLOCK_ALL, i, &ethertype_entry));
   3203     }
   3204 
   3205     /* Zero out remaining entries of Ethertype eligibility map table */
   3206     for (j = i; j < soc_mem_index_count(unit,
   3207                 DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm); j++) {
   3208         BCM_IF_ERROR_RETURN(WRITE_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm(unit,
   3209                     MEM_BLOCK_ALL, j, soc_mem_entry_null(unit,
   3210                         DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm)));
   3211     }
   3212 
   3213     return BCM_E_NONE;
   3214 }
   3215 
   3216 /*
   3217  * Function:
   3218  *      bcm_th2_l3_egress_ecmp_dlb_ethertype_get
   3219  * Purpose:
   3220  *      Get the Ethertypes that are eligible or ineligible for
   3221  *      ECMP dynamic load balancing.
   3222  * Parameters:
   3223  *      unit            - (IN) Unit number.
   3224  *      flags           - (IN/OUT) BCM_L3_ECMP_DYNAMIC_ETHERTYPE_xxx flags.
   3225  *      ethertype_max   - (IN) Number of elements in ethertype_array.
   3226  *      ethertype_array - (OUT) Array of Ethertypes.
   3227  *      ethertype_count - (OUT) Number of elements returned in ethertype_array.
   3228  * Returns:
   3229  *      BCM_E_XXX
   3230  */
   3231 int
   3232 bcm_th2_l3_egress_ecmp_dlb_ethertype_get(
   3233     int unit,
   3234     uint32 *flags,
   3235     int ethertype_max,
   3236     int *ethertype_array,
   3237     int *ethertype_count)
   3238 {
   3239     int i;
   3240     int ethertype;
   3241     dlb_ecmp_ethertype_eligibility_map_entry_t ethertype_entry;
   3242     dlb_ecmp_eem_configuration_entry_t eem_entry;
   3243 #ifdef BCM_TRIDENT3_SUPPORT
   3244     uint32 reg_val = 0;
   3245 #endif
   3246 
   3247     /* Input check */
   3248     if (NULL == flags) {
   3249         return BCM_E_PARAM;
   3250     }
   3251     if ((ethertype_max > 0) && (NULL == ethertype_array)) {
   3252         return BCM_E_PARAM;
   3253     }
   3254     if (NULL == ethertype_count) {
   3255         return BCM_E_PARAM;
   3256     }
   3257 
   3258     *ethertype_count = 0;
   3259 
   3260     /* Get flags */
   3261 #ifdef BCM_TRIDENT3_SUPPORT
   3262     if (soc_feature(unit, soc_feature_td3_dlb)) {
   3263         BCM_IF_ERROR_RETURN(READ_DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr(unit,
   3264                     &reg_val));
   3265         if (soc_reg_field_get(unit, DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr,
   3266                     reg_val, CONFIGURATIONf)) {
   3267             *flags |= BCM_L3_ECMP_DYNAMIC_ETHERTYPE_ELIGIBLE;
   3268         }
   3269         if (soc_reg_field_get(unit, DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr,
   3270                     reg_val, INNER_OUTER_ETHERTYPE_SELECTIONf)) {
   3271             *flags |= BCM_L3_ECMP_DYNAMIC_ETHERTYPE_INNER;
   3272         }
   3273     } else
   3274 #endif
   3275     {
   3276         BCM_IF_ERROR_RETURN(READ_DLB_ECMP_EEM_CONFIGURATIONm(unit,
   3277                     MEM_BLOCK_ANY, 0, &eem_entry));
   3278         if (soc_DLB_ECMP_EEM_CONFIGURATIONm_field32_get(unit,
   3279                     &eem_entry, CONFIGURATIONf)) {
   3280             *flags |= BCM_L3_ECMP_DYNAMIC_ETHERTYPE_ELIGIBLE;
   3281         }
   3282         if (!soc_feature(unit, soc_feature_th3_style_dlb)) {
   3283             if (soc_DLB_ECMP_EEM_CONFIGURATIONm_field32_get(unit,
   3284                         &eem_entry, INNER_OUTER_ETHERTYPE_SELECTIONf)) {
   3285                 *flags |= BCM_L3_ECMP_DYNAMIC_ETHERTYPE_INNER;
   3286             }
   3287         }
   3288     }
   3289     /* Get Ethertypes */
   3290     for (i = 0; i < soc_mem_index_count(unit,
   3291                 DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm); i++) {
   3292         BCM_IF_ERROR_RETURN(READ_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm(unit,
   3293                     MEM_BLOCK_ANY, i, &ethertype_entry));
   3294         if (soc_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_get(unit,
   3295                     &ethertype_entry, VALIDf)) {
   3296             ethertype = soc_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_get(unit,
   3297                     &ethertype_entry, ETHERTYPEf);
   3298             if (NULL != ethertype_array) {
   3299                 ethertype_array[*ethertype_count] = ethertype;
   3300             }
   3301             (*ethertype_count)++;
   3302             if ((ethertype_max > 0) && (*ethertype_count == ethertype_max)) {
   3303                 break;
   3304             }
   3305         }
   3306     }
   3307 
   3308     return BCM_E_NONE;
   3309 }
   3310 
   3311 
   3312 /*
   3313  * Function:
   3314  *      bcm_th2_l3_ecmp_dlb_flowset_reset
   3315  * Purpose:
   3316  *      Invalidate matched  flowset entry when deleting ecmp member
   3317  *      so that they can be given new assignments by DLB
   3318  * Parameters:
   3319  *      unit               - (IN) bcm device.
   3320  *      ecmp               - (IN) ECMP group info.
   3321  *      ecmp_member_bitmap - (IN/OUT) Offset of deleted ecmp member.
   3322  * Returns:
   3323  *      BCM_E_XXX
   3324  */
   3325 STATIC int
   3326 bcm_th2_l3_ecmp_dlb_flowset_reset(int unit,
   3327                                   bcm_l3_egress_ecmp_t *ecmp,
   3328                                   SHR_BITDCL *ecmp_member_bitmap)
   3329 {
   3330     int       rv = BCM_E_NONE;
   3331     int       ecmp_group_idx = 0;
   3332     int       i = 0;
   3333     int       dlb_id = 0;
   3334     int       group_enable = 0;
   3335     int       entry_base_ptr = 0;
   3336     int       alloc_size = 0;
   3337     int       index_min = 0;
   3338     int       index_max = 0;
   3339     int       assigned_member = 0;
   3340     int       pipe = 0;
   3341     dlb_ecmp_group_control_entry_t   dlb_ecmp_group_control_entry;
   3342     dlb_ecmp_flowset_entry_t         flowset_entry;
   3343     ecmp_dlb_control_entry_t         ecmp_group_entry;
   3344     dlb_ecmp_flowset_member_entry_t *flowset_member_ptr = NULL;
   3345     uint32                          *flowset_member_buf = NULL;
   3346     soc_mem_t                        ecmp_flowset_member;
   3347     soc_mem_t                        ecmp_flowset;
   3348 
   3349     if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_ASSIGNED) {
   3350         return rv;
   3351     }
   3352 
   3353     sal_memcpy(&flowset_entry, soc_mem_entry_null(unit, DLB_ECMP_FLOWSETm),
   3354                sizeof(dlb_ecmp_flowset_entry_t));
   3355 
   3356     ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   3357 #if defined(BCM_TOMAHAWK3_SUPPORT)
   3358     if (soc_feature(unit, soc_feature_th3_style_dlb)) {
   3359         uint64 dlb_en_bitmap;
   3360         dlb_id = _bcm_th3_l3_ecmp_dlb_get_id(unit, ecmp_group_idx);
   3361         if (dlb_id < soc_reg_field_length(unit,
   3362                      DLB_ID_0_TO_63_ENABLEr, BITMAPf)) {
   3363             SOC_IF_ERROR_RETURN( \
   3364               READ_DLB_ID_0_TO_63_ENABLEr(unit, &dlb_en_bitmap));
   3365             group_enable = COMPILER_64_BITTEST(dlb_en_bitmap, dlb_id);
   3366         } else {
   3367             rv = READ_DLB_ID_64_TO_127_ENABLEr(unit, &dlb_en_bitmap);
   3368             if (rv < 0) {
   3369                 goto error;
   3370             }
   3371             group_enable = COMPILER_64_BITTEST(dlb_en_bitmap, dlb_id -
   3372                                    (soc_reg_field_length(unit,
   3373                                    DLB_ID_0_TO_63_ENABLEr, BITMAPf)));
   3374         }
   3375     } else
   3376 #endif
   3377     {
   3378         SOC_IF_ERROR_RETURN( \
   3379             READ_ECMP_DLB_CONTROLm(unit, MEM_BLOCK_ANY,
   3380                                    ecmp_group_idx, &ecmp_group_entry));
   3381         group_enable =
   3382             soc_ECMP_DLB_CONTROLm_field32_get(unit,
   3383                                               &ecmp_group_entry, GROUP_ENABLEf);
   3384         dlb_id =
   3385             soc_ECMP_DLB_CONTROLm_field32_get(unit, &ecmp_group_entry, DLB_IDf);
   3386     }
   3387     if (!group_enable) {
   3388         return rv;
   3389     }
   3390 
   3391     BCM_IF_ERROR_RETURN(
   3392         READ_DLB_ECMP_GROUP_CONTROLm(unit, MEM_BLOCK_ANY,
   3393                                      dlb_id, &dlb_ecmp_group_control_entry));
   3394 
   3395     entry_base_ptr =
   3396         soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   3397                                                 &dlb_ecmp_group_control_entry,
   3398                                                 FLOW_SET_BASEf);
   3399 
   3400     alloc_size = sizeof(dlb_ecmp_flowset_member_entry_t) * (ecmp->dynamic_size);
   3401     flowset_member_buf = soc_cm_salloc(unit, alloc_size,
   3402                                        "ECMP flowset member entries");
   3403     if (NULL == flowset_member_buf) {
   3404         rv = BCM_E_MEMORY;
   3405         goto error;
   3406     }
   3407 
   3408 
   3409     for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) {
   3410 
   3411         ecmp_flowset_member =
   3412             SOC_MEM_UNIQUE_ACC(unit, DLB_ECMP_FLOWSET_MEMBERm)[pipe];
   3413 
   3414         ecmp_flowset =
   3415             SOC_MEM_UNIQUE_ACC(unit, DLB_ECMP_FLOWSETm)[pipe];
   3416 
   3417         index_min = entry_base_ptr;
   3418         index_max = index_min + ecmp->dynamic_size - 1;
   3419         rv = soc_mem_read_range(unit, ecmp_flowset_member, MEM_BLOCK_ANY,
   3420                                 index_min, index_max, flowset_member_buf);
   3421         if (BCM_FAILURE(rv)) {
   3422             goto error;
   3423         }
   3424 
   3425         /*  Invalidate matched  flowset entry */
   3426         for (i = 0; i < ecmp->dynamic_size; i++) {
   3427             flowset_member_ptr =
   3428                 soc_mem_table_idx_to_pointer(unit, ecmp_flowset_member,
   3429                                              dlb_ecmp_flowset_member_entry_t *,
   3430                                              flowset_member_buf, i);
   3431             assigned_member =
   3432                 soc_mem_field32_get(unit, ecmp_flowset_member,
   3433                                     (uint32 *)flowset_member_ptr,
   3434                                     ECMP_MEMBER_ASSIGNMENTf);
   3435             if (soc_mem_field32_get(unit, ecmp_flowset_member,
   3436                                     (uint32 *)flowset_member_ptr,
   3437                                     ECMP_MEMBER_IS_ALTERNATEf)) {
   3438                 assigned_member = assigned_member + ecmp->max_paths / 2;
   3439             }
   3440             if (SHR_BITGET(ecmp_member_bitmap, assigned_member)) {
   3441 
   3442                 rv = soc_mem_write(unit, ecmp_flowset,
   3443                                    MEM_BLOCK_ALL, (i + entry_base_ptr),
   3444                                    &flowset_entry);
   3445                 if (BCM_FAILURE(rv)) {
   3446                     goto error;
   3447                 }
   3448             }
   3449         }
   3450 
   3451     }
   3452 
   3453     soc_cm_sfree(unit, flowset_member_buf);
   3454 
   3455     return BCM_E_NONE;
   3456 
   3457 error:
   3458 
   3459     if (flowset_member_buf) {
   3460         soc_cm_sfree(unit, flowset_member_buf);
   3461     }
   3462 
   3463     return rv;
   3464 }
   3465 
   3466 /*
   3467  * Function:
   3468  *      bcm_th2_l3_ecmp_dlb_member_delete
   3469  * Purpose:
   3470  *      Delete an Egress forwarding object from an DLB ECMP object
   3471  * Parameters:
   3472  *      unit         - (IN) bcm device.
   3473  *      ecmp         - (IN) ECMP group info.
   3474  *      intf         - (IN) Deleted L3 interface id.
   3475  *      intf_array   - (IN/OUT) Array of Egress forwarding objects.
   3476  *      intf_count   - (IN/OUT) Number of entries of intf_count actually filled in.
   3477  * Returns:
   3478  *      BCM_E_XXX
   3479  */
   3480 int
   3481 bcm_th2_l3_ecmp_dlb_member_delete(int unit,
   3482                                   bcm_l3_egress_ecmp_t *ecmp, bcm_if_t intf,
   3483                                   bcm_if_t *intf_array, int *intf_count)
   3484 {
   3485     int       rv = BCM_E_NONE;
   3486     int       ecmp_group_idx = 0;
   3487     int       remove_member_found = FALSE;
   3488     bcm_if_t *dlb_intf_array = NULL;
   3489     int       i = 0, j = 0;
   3490     int       dlb_member_count = 0; /* Exclude filler */
   3491     int       member_bitmap_width = 0;
   3492     SHR_BITDCL *member_bitmap = NULL;
   3493     SHR_BITDCL *delete_member_bitmap = NULL;
   3494     SHR_BITDCL *group_member_ptr = NULL;
   3495 
   3496 
   3497     /* Check count*/
   3498     if (*intf_count == 0) {
   3499         rv = BCM_E_NOT_FOUND;
   3500         goto clean_up;
   3501     } else if (*intf_count != ecmp->max_paths) {
   3502         /* Should always has max_paths members on expanded DLB group */
   3503         rv = BCM_E_INTERNAL;
   3504         goto clean_up;
   3505     }
   3506 
   3507     /* Allocate DLB member bitmap */
   3508     member_bitmap_width = BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2;
   3509     member_bitmap = sal_alloc(SHR_BITALLOCSIZE(member_bitmap_width),
   3510                               "DLB ECMP member bitmap");
   3511     if (NULL == member_bitmap) {
   3512         rv = BCM_E_MEMORY;
   3513         goto clean_up;
   3514     }
   3515 
   3516     sal_memset(member_bitmap, 0, SHR_BITALLOCSIZE(member_bitmap_width));
   3517 
   3518     /* Allocate Deleted DLB member bitmap */
   3519     delete_member_bitmap = sal_alloc(SHR_BITALLOCSIZE(member_bitmap_width),
   3520                                      "Deleted DLB ECMP member bitmap");
   3521     if (NULL == delete_member_bitmap) {
   3522         rv = BCM_E_MEMORY;
   3523         goto clean_up;
   3524     }
   3525 
   3526     sal_memset(delete_member_bitmap, 0, SHR_BITALLOCSIZE(member_bitmap_width));
   3527 
   3528     /* Allocate DLB member array */
   3529     dlb_intf_array = sal_alloc((*intf_count) * sizeof(bcm_if_t),
   3530                                "ecmp member array");
   3531     if (NULL == dlb_intf_array) {
   3532         rv = BCM_E_MEMORY;
   3533         goto clean_up;
   3534     }
   3535 
   3536     /* Get currrent group bitmap */
   3537     ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   3538     group_member_ptr =
   3539         BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx);
   3540     sal_memcpy(member_bitmap, group_member_ptr,
   3541                SHR_BITALLOCSIZE(member_bitmap_width));
   3542 
   3543     /*
   3544         * Get the DLB members (excluding deleted member and filler members)
   3545         * and Clear DLB member bitmap
   3546         */
   3547     for (i = 0; i < ecmp->max_paths; i++) {
   3548          if (SHR_BITGET(member_bitmap, i)) {
   3549              if (!remove_member_found && (intf_array[i] == intf)) {
   3550                  SHR_BITCLR(member_bitmap, i);
   3551                  SHR_BITSET(delete_member_bitmap, i);
   3552                  remove_member_found = TRUE;
   3553              } else {
   3554                  dlb_intf_array[dlb_member_count++] = intf_array[i];
   3555              }
   3556          }
   3557     }
   3558 
   3559     if (!remove_member_found) {
   3560         rv = BCM_E_NOT_FOUND;
   3561         goto clean_up;
   3562     }
   3563 
   3564     /* Refill the location of deleted members with existing members randomly */
   3565     for (i = 0; i < ecmp->max_paths; i++) {
   3566         if (dlb_member_count > 0) {
   3567              /* Just reset filler*/
   3568             if (!SHR_BITGET(member_bitmap, i)) {
   3569                 intf_array[i] =
   3570                         dlb_intf_array[j % dlb_member_count];
   3571                 j++;
   3572             }
   3573         } else {
   3574             /* All the DLB members are deleted */
   3575             intf_array[i] = 0;
   3576             (*intf_count)--;
   3577         }
   3578     }
   3579 
   3580     /* Update ECMP group */
   3581     ecmp->flags |= BCM_L3_REPLACE | BCM_L3_WITH_ID;
   3582     rv = _bcm_esw_l3_ecmp_create(unit, ecmp, *intf_count, intf_array,
   3583                                  BCM_L3_ECMP_MEMBER_OP_DELETE,
   3584                                  1, &intf, *intf_count, member_bitmap);
   3585     if (BCM_SUCCESS(rv)) {
   3586         sal_memcpy(group_member_ptr, member_bitmap,
   3587                    SHR_BITALLOCSIZE(member_bitmap_width));
   3588         rv = bcm_th2_l3_ecmp_dlb_flowset_reset(unit, ecmp,
   3589                                                delete_member_bitmap);
   3590     }
   3591 
   3592 clean_up:
   3593 
   3594     if (member_bitmap) {
   3595         sal_free(member_bitmap);
   3596     }
   3597 
   3598     if (delete_member_bitmap) {
   3599         sal_free(delete_member_bitmap);
   3600     }
   3601 
   3602     if (dlb_intf_array) {
   3603         sal_free(dlb_intf_array);
   3604     }
   3605 
   3606     return rv;
   3607 }
   3608 
   3609 /*
   3610  * Function:
   3611  *      bcm_th2_l3_ecmp_dlb_dgm_member_delete
   3612  * Purpose:
   3613  *      Delete an Egress forwarding object from an DLB/DGM ECMP object
   3614  * Parameters:
   3615  *      unit                - (IN) bcm device.
   3616  *      ecmp                - (IN) ECMP group info.
   3617  *      ecmp_member         - (IN) Deleted L3 interface id pointing to Egress forwarding object.
   3618  *      ecmp_member_array   - (IN/OUT) Member array of Egress forwarding objects.
   3619  *      ecmp_member_count   - (IN/OUT) Number of members of ecmp_member_count actually filled in.
   3620  *
   3621  * Returns:
   3622  *      BCM_E_XXX
   3623  */
   3624 int
   3625 bcm_th2_l3_ecmp_dlb_dgm_member_delete(int unit,
   3626                                       bcm_l3_egress_ecmp_t *ecmp,
   3627                                       bcm_l3_ecmp_member_t *ecmp_member,
   3628                                       bcm_l3_ecmp_member_t *ecmp_member_array,
   3629                                       int *ecmp_member_count)
   3630 {
   3631     int rv = BCM_E_NONE;
   3632     int alloc_size = 0;
   3633     bcm_if_t *intf_array = 0;
   3634     int ecmp_group_idx = 0;
   3635     int start = 0, end = 0;
   3636     int i = 0, j = 0;
   3637     int location_offset = 0;
   3638     int copy_offset = 0;
   3639     int remove_member_found = FALSE;
   3640     int alternate_count = 0;   /* Include filler */
   3641     int primary_count = 0;     /* Include filler */
   3642     int dlb_member_count = 0;  /* Exclude filler */
   3643     int member_bitmap_width = 0;
   3644     SHR_BITDCL *member_bitmap = NULL;
   3645     SHR_BITDCL *delete_member_bitmap = NULL;
   3646     SHR_BITDCL *group_member_ptr = NULL;
   3647     bcm_l3_ecmp_member_t *dlb_member_array = NULL; /* Exclude filler */
   3648 
   3649 
   3650     /* Allocate DLB member bitmap */
   3651     member_bitmap_width = BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2;
   3652     member_bitmap = sal_alloc(SHR_BITALLOCSIZE(member_bitmap_width),
   3653                                "DLB ECMP member bitmap");
   3654     if (NULL == member_bitmap) {
   3655        rv = BCM_E_MEMORY;
   3656        goto clean_up;
   3657     }
   3658 
   3659     sal_memset(member_bitmap, 0, SHR_BITALLOCSIZE(member_bitmap_width));
   3660 
   3661     /* Allocate Deleted DLB member bitmap */
   3662     delete_member_bitmap = sal_alloc(SHR_BITALLOCSIZE(member_bitmap_width),
   3663                                      "Deleted DLB ECMP member bitmap");
   3664     if (NULL == delete_member_bitmap) {
   3665         rv = BCM_E_MEMORY;
   3666         goto clean_up;
   3667     }
   3668 
   3669     sal_memset(delete_member_bitmap, 0, SHR_BITALLOCSIZE(member_bitmap_width));
   3670 
   3671     /* Allocate DLB member array */
   3672     dlb_member_array = sal_alloc((*ecmp_member_count) *
   3673                                  sizeof(bcm_l3_ecmp_member_t),
   3674                                  "ecmp member array");
   3675     if (NULL == dlb_member_array) {
   3676         rv = BCM_E_MEMORY;
   3677         goto clean_up;
   3678 
   3679     }
   3680 
   3681     /* Get currrent group bitmap */
   3682     ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   3683     group_member_ptr =
   3684         BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx);
   3685     sal_memcpy(member_bitmap, group_member_ptr,
   3686                SHR_BITALLOCSIZE(member_bitmap_width));
   3687 
   3688     /* Allocate interface array */
   3689     alloc_size = sizeof(bcm_if_t) * BCM_XGS3_L3_ECMP_MAX(unit);
   3690     intf_array = sal_alloc(alloc_size, "intf array");
   3691     if (NULL == intf_array) {
   3692         rv = BCM_E_MEMORY;
   3693         goto clean_up;
   3694 
   3695     }
   3696     sal_memset(intf_array, 0, alloc_size);
   3697 
   3698     /*
   3699      * Index of ecmp_member_array
   3700      * - Both primary and alternate members exist: Primary members start
   3701      *    from 0 and Alternate members start from max_paths / 2
   3702      * - Only primary members exist: Primary members start from 0
   3703      * - Only alternate members exist: Alternate members start from 0
   3704      * Offset of DLB members bitmap
   3705      * - Primary members always start from 0
   3706      * - Alternate members always start from max_paths / 2
   3707      * Member count (including filler)
   3708      * - DLB count: 0 or max_paths if any
   3709      * - DGM primary count: 0 or max_paths/2 if any
   3710      *    DGM alternate count: 0 or max_paths/2 if any
   3711      */
   3712     if ((ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) &&
   3713         (ecmp_member->flags & BCM_L3_ECMP_MEMBER_DGM_ALTERNATE)) {
   3714         /* Delete alternate member */
   3715         start = ecmp->max_paths / 2;
   3716         end = start * 2;
   3717 
   3718         /* Get the count of  alternate members  (without filler) */
   3719         SHR_BITCOUNT_RANGE(group_member_ptr, dlb_member_count,
   3720                            start, end - start);
   3721 
   3722         if (dlb_member_count == 0) {
   3723             rv = BCM_E_NOT_FOUND;
   3724             goto clean_up;
   3725         } else {
   3726             alternate_count = ecmp->max_paths / 2;
   3727             primary_count = (*ecmp_member_count) - alternate_count;
   3728         }
   3729 
   3730         /*
   3731          *  Only alternate members exist:
   3732          *  Alternate members start from 0, offset should be max_paths / 2.
   3733          */
   3734         if (0 == primary_count) {
   3735             location_offset = ecmp->max_paths / 2;
   3736         }
   3737 
   3738         /* Internal check */
   3739         if (end - location_offset > (*ecmp_member_count)) {
   3740             rv = BCM_E_INTERNAL;
   3741             goto clean_up;
   3742         }
   3743     } else {
   3744         /* Delete DGM primary member or DLB member */
   3745         start = 0;
   3746         if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) {
   3747             end = ecmp->max_paths / 2;
   3748         } else {
   3749             end = ecmp->max_paths;
   3750         }
   3751 
   3752         /* Get the count of  DGM primary members or DLB members (without filler) */
   3753         SHR_BITCOUNT_RANGE(group_member_ptr, dlb_member_count, start, end);
   3754 
   3755         if (dlb_member_count == 0) {
   3756             rv = BCM_E_NOT_FOUND;
   3757             goto clean_up;
   3758         }
   3759 
   3760         if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) {
   3761             primary_count = ecmp->max_paths / 2;
   3762             alternate_count = (*ecmp_member_count) - primary_count;
   3763             /*
   3764              * If delete the lastest primary member, alternate members shoud be
   3765              * moved,  and start from 0 instead of max_paths / 2.
   3766              */
   3767             if (alternate_count > 0) {
   3768                 copy_offset =  ecmp->max_paths / 2;
   3769             }
   3770         } else {
   3771             primary_count = ecmp->max_paths;
   3772         }
   3773 
   3774         /* Internal check */
   3775         if (end + copy_offset > (*ecmp_member_count)) {
   3776             rv = BCM_E_INTERNAL;
   3777             goto clean_up;
   3778         }
   3779     }
   3780 
   3781     /*
   3782      * Get the DLB members (excluding deleted member and filler members)
   3783      * and Clear DLB member bitmap
   3784      */
   3785     dlb_member_count = 0;
   3786     for (i = start - location_offset; i < end - location_offset; i++) {
   3787 
   3788          if (SHR_BITGET(member_bitmap, i + location_offset)) {
   3789              if (!remove_member_found &&
   3790                  (ecmp_member_array[i].egress_if == ecmp_member->egress_if)) {
   3791 
   3792                  SHR_BITCLR(member_bitmap, i + location_offset);
   3793                  SHR_BITSET(delete_member_bitmap, i + location_offset);
   3794                  remove_member_found  = TRUE;
   3795              } else {
   3796                  sal_memcpy(&dlb_member_array[dlb_member_count++],
   3797                             &ecmp_member_array[i],
   3798                             sizeof(bcm_l3_ecmp_member_t));
   3799              }
   3800          }
   3801     }
   3802 
   3803     if (!remove_member_found) {
   3804         rv = BCM_E_NOT_FOUND;
   3805         goto clean_up;
   3806     }
   3807 
   3808     /* Refill the location of deleted members with existing members randomly */
   3809     for (i = start - location_offset; i < end - location_offset; i++) {
   3810         if (dlb_member_count > 0) {
   3811             if (!SHR_BITGET(member_bitmap, i + location_offset)) {
   3812                 sal_memcpy(&ecmp_member_array[i],
   3813                            &dlb_member_array[j % dlb_member_count],
   3814                            sizeof(bcm_l3_ecmp_member_t));
   3815                 j++;
   3816             }
   3817         } else {
   3818             /*
   3819              * 1. All the DLB members are deleted
   3820              * 2. or all the DGM primary members are deleted
   3821              * 3. or all the DGM alternate members are deleted
   3822              */
   3823             if (copy_offset) {
   3824                 /*
   3825                  * DGM - if delete the last primary member, alternate members
   3826                  * shoud be moved,  and start from 0 instead of max_paths / 2
   3827                  */
   3828                 sal_memcpy(&ecmp_member_array[i],
   3829                            &ecmp_member_array[i + copy_offset],
   3830                            sizeof(bcm_l3_ecmp_member_t));
   3831                 sal_memset(&ecmp_member_array[i + copy_offset], 0,
   3832                            sizeof(bcm_l3_ecmp_member_t));
   3833             } else {
   3834                 sal_memset(&ecmp_member_array[i], 0,
   3835                            sizeof(bcm_l3_ecmp_member_t));
   3836             }
   3837             (*ecmp_member_count)--;
   3838             if (!(ecmp_member->flags & BCM_L3_ECMP_MEMBER_DGM_ALTERNATE)) {
   3839                 primary_count--;
   3840             }
   3841         }
   3842     }
   3843 
   3844     for (i = 0; i < (*ecmp_member_count); i++) {
   3845         intf_array[i] = ecmp_member_array[i].egress_if;
   3846     }
   3847 
   3848     /* Update ECMP group */
   3849     ecmp->flags |= BCM_L3_REPLACE | BCM_L3_WITH_ID;
   3850     rv = _bcm_esw_l3_ecmp_create(unit, ecmp, *ecmp_member_count,
   3851                                  intf_array, BCM_L3_ECMP_MEMBER_OP_DELETE,
   3852                                  1, &(ecmp_member->egress_if),
   3853                                  primary_count, member_bitmap);
   3854 
   3855     if (BCM_SUCCESS(rv)) {
   3856         sal_memcpy(group_member_ptr, member_bitmap,
   3857                    SHR_BITALLOCSIZE(member_bitmap_width));
   3858         rv = bcm_th2_l3_ecmp_dlb_flowset_reset(unit, ecmp,
   3859                                                delete_member_bitmap);
   3860     }
   3861 
   3862 clean_up:
   3863 
   3864     if (member_bitmap) {
   3865         sal_free(member_bitmap);
   3866     }
   3867 
   3868     if (delete_member_bitmap) {
   3869         sal_free(delete_member_bitmap);
   3870     }
   3871 
   3872     if (dlb_member_array) {
   3873         sal_free(dlb_member_array);
   3874     }
   3875 
   3876     if (intf_array) {
   3877         sal_free(intf_array);
   3878     }
   3879 
   3880     return rv;
   3881 
   3882 }
   3883 
   3884 /*
   3885  * Function:
   3886  *      bcm_th2_l3_ecmp_dlb_member_create
   3887  * Purpose:
   3888  *      Create or modify an Egress DLB ECMP forwarding object.
   3889  * Parameters:
   3890  *      unit         - (IN) bcm device.
   3891  *      ecmp         - (IN) ECMP group info.
   3892  *      intf_array   - (IN/OUT) Array of Egress forwarding objects.
   3893  *      intf_count   - (IN/OUT) Number of entries of intf_count actually filled in.
   3894  * Returns:
   3895  *      BCM_E_XXX
   3896  */
   3897 int
   3898 bcm_th2_l3_ecmp_dlb_member_create(int unit,
   3899                                   bcm_l3_egress_ecmp_t *ecmp,
   3900                                   bcm_if_t *intf_array,
   3901                                   int intf_count)
   3902 {
   3903     int       rv = BCM_E_NONE;
   3904     int       i = 0, j = 0;
   3905     int       alloc_size = 0;
   3906     int       ecmp_group_idx = 0;
   3907     bcm_if_t *dlb_intf_array = NULL;   /* Include filler*/
   3908     bcm_if_t *dlb_intf_array_2 = NULL; /* Exclude filler */
   3909     int       dlb_intf_count = 0;
   3910     int       dlb_intf_count_2 = 0;
   3911     int       member_chg = TRUE;
   3912     bcm_l3_egress_ecmp_t  dlb_ecmp;
   3913     int                   member_bitmap_width = 0;
   3914     SHR_BITDCL           *member_bitmap = NULL;
   3915     SHR_BITDCL           *group_member_ptr = NULL;
   3916 
   3917     /* Check max_paths */
   3918     if ((ecmp->max_paths > BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit)) ||
   3919         (ecmp->max_paths < 2)) {
   3920         return BCM_E_PARAM;
   3921     } else if (ecmp->max_paths == 0) {
   3922         ecmp->max_paths = BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit);
   3923     }
   3924 
   3925     if (intf_count > ecmp->max_paths) {
   3926         return BCM_E_RESOURCE;
   3927     }
   3928 
   3929     /* Allocate interface array */
   3930     alloc_size = sizeof(bcm_if_t) * BCM_XGS3_L3_ECMP_MAX(unit);
   3931     dlb_intf_array = sal_alloc(alloc_size, "dlb intf array");
   3932     if (NULL == dlb_intf_array) {
   3933         return BCM_E_MEMORY;
   3934     }
   3935 
   3936     sal_memset(dlb_intf_array, 0, alloc_size);
   3937 
   3938     /* Allocate DLB member bitmap */
   3939     member_bitmap_width = BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2;
   3940     member_bitmap = sal_alloc(SHR_BITALLOCSIZE(member_bitmap_width),
   3941                               "DLB ECMP member bitmap");
   3942     if (NULL == member_bitmap) {
   3943         rv = BCM_E_MEMORY;
   3944         goto clean_up;
   3945     }
   3946 
   3947     sal_memset(member_bitmap, 0, SHR_BITALLOCSIZE(member_bitmap_width));
   3948 
   3949     if (ecmp->flags & BCM_L3_REPLACE) {
   3950         if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp->ecmp_intf)) {
   3951             rv = BCM_E_PARAM;
   3952             goto clean_up;
   3953         }
   3954 
   3955         /* Get currrent group bitmap */
   3956         ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   3957         group_member_ptr =
   3958             BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx);
   3959 
   3960         /* Get DLB group's existing interface array including filler */
   3961         bcm_l3_egress_ecmp_t_init(&dlb_ecmp);
   3962         dlb_ecmp.ecmp_intf = ecmp->ecmp_intf;
   3963         rv = _bcm_esw_l3_egress_ecmp_get(unit, &dlb_ecmp,
   3964                                          BCM_XGS3_L3_ECMP_MAX(unit),
   3965                                          dlb_intf_array, &dlb_intf_count, TRUE);
   3966         if (BCM_FAILURE(rv)) {
   3967             goto clean_up;
   3968         }
   3969 
   3970         if (dlb_ecmp.dynamic_mode == ecmp->dynamic_mode) {
   3971 
   3972             if (dlb_ecmp.max_paths != ecmp->max_paths) {
   3973                 rv = BCM_E_PARAM;
   3974                 goto clean_up;
   3975             }
   3976 
   3977             /* Get DLB group's existing interface array excluding filler */
   3978             alloc_size = sizeof(bcm_if_t) * dlb_intf_count;
   3979             dlb_intf_array_2 = sal_alloc(alloc_size, "dlb intf array_2");
   3980             if (NULL == dlb_intf_array_2) {
   3981                 rv = BCM_E_MEMORY;
   3982                 goto clean_up;
   3983             }
   3984             sal_memset(dlb_intf_array_2, 0, alloc_size);
   3985             /* Exclude filler members of expanded DLB group */
   3986             for (i = 0; i < dlb_intf_count; i++) {
   3987                 if (SHR_BITGET(group_member_ptr, i)) {
   3988                     dlb_intf_array_2[dlb_intf_count_2++] = dlb_intf_array[i];
   3989                 }
   3990             }
   3991 
   3992             /* Compare new members(intf_array) with exisiting members(dlb_intf_array_2) */
   3993             if ((intf_count == dlb_intf_count_2) &&
   3994                 !sal_memcmp((void *)intf_array, (void *)dlb_intf_array_2,
   3995                              (intf_count * sizeof(bcm_if_t)))) {
   3996                 member_chg = FALSE;
   3997             }
   3998         }
   3999     }
   4000 
   4001     /*
   4002      * To keep the traffic resiliency, the offset of DLB members in L3 ECMP tables should
   4003      * not be changed when an DLB ECMP member is deleted or added.
   4004      * - An expanded ecmp group will be used for DLB. SDK always allocates member entries
   4005      *   based on the configuration of max_paths. i.e. DLB(max_paths entries).
   4006      *   Up to max_paths next hops can be supported in DLB group. The DLB bitmap
   4007      *   will always reflect the TRUE DLB membership(specified by SDK API),
   4008      *   and the remaining entries will contain fillers which won't be selected by DLB.
   4009      * - When an DLB ECMP member is deleted, the space previously occupied by the deleted
   4010      *   member will be filled as a duplicate of any existing member.
   4011      * - When an DLB ECMP member is added, SDK will choose the space used by a filler
   4012      *   for the new member.
   4013      */
   4014     if (member_chg) {
   4015         sal_memset(dlb_intf_array, 0,
   4016                    sizeof(bcm_if_t) * BCM_XGS3_L3_ECMP_MAX(unit));
   4017         if (intf_count) {
   4018             for (i = 0; i < ecmp->max_paths; i++) {
   4019                 j = i % intf_count;
   4020                 dlb_intf_array[i] = intf_array[j];
   4021                 if (i < intf_count) {
   4022                     SHR_BITSET(member_bitmap, i);
   4023                 }
   4024             }
   4025             /*  Should be expanded to max_paths with filler */
   4026             dlb_intf_count = ecmp->max_paths;
   4027         } else {
   4028             dlb_intf_count = 0;
   4029         }
   4030     } else {
   4031         /* No member change */
   4032         sal_memcpy(member_bitmap, group_member_ptr,
   4033                    SHR_BITALLOCSIZE(member_bitmap_width));
   4034     }
   4035 
   4036     rv = _bcm_esw_l3_ecmp_create(unit, ecmp, dlb_intf_count,
   4037                                  dlb_intf_array, BCM_L3_ECMP_MEMBER_OP_SET,
   4038                                  0, NULL, dlb_intf_count, member_bitmap);
   4039     if (member_chg && BCM_SUCCESS(rv)) {
   4040         ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   4041         group_member_ptr =
   4042             BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx);
   4043         sal_memcpy(group_member_ptr, member_bitmap,
   4044                    SHR_BITALLOCSIZE(member_bitmap_width));
   4045     }
   4046 
   4047 clean_up:
   4048 
   4049     if (dlb_intf_array) {
   4050         sal_free(dlb_intf_array);
   4051     }
   4052 
   4053     if (member_bitmap) {
   4054         sal_free(member_bitmap);
   4055     }
   4056 
   4057     if (dlb_intf_array_2) {
   4058         sal_free(dlb_intf_array_2);
   4059     }
   4060 
   4061     return rv;
   4062 }
   4063 
   4064 /*
   4065  * Function:
   4066  *      bcm_th2_l3_ecmp_dlb_dgm_member_create
   4067  * Purpose:
   4068  *      Create or modify an Egress DLB/DGM ECMP forwarding object.
   4069  * Parameters:
   4070  *      unit              - (IN) bcm device.
   4071  *      ecmp              - (IN) ECMP group info.
   4072  *      ecmp_member_array - (IN) Member array of Egress forwarding objects.
   4073  *      ecmp_member_count - (IN) Number of elements in ecmp_member_array.
   4074  *
   4075  * Returns:
   4076  *      BCM_E_XXX
   4077  */
   4078 int
   4079 bcm_th2_l3_ecmp_dlb_dgm_member_create(int unit,
   4080                                       bcm_l3_egress_ecmp_t *ecmp,
   4081                                       bcm_l3_ecmp_member_t *ecmp_member_array,
   4082                                       int ecmp_member_count)
   4083 {
   4084     int         rv = BCM_E_NONE;
   4085     int         i = 0, j = 0;
   4086     int         alloc_size = 0;
   4087     int         ecmp_group_idx = 0;
   4088     bcm_if_t   *dlb_intf_array = NULL;   /* Include filler */
   4089     int         dlb_intf_count = 0;
   4090     bcm_if_t   *dlb_intf_array_2 = NULL; /* Exclude filler */
   4091     int         dlb_intf_count_2 = 0;
   4092     int         grand_max_paths = 0;
   4093     int         dlb_primary_count = 0;   /* Include filler */
   4094     int         dlb_primary_count_2 = 0; /* Exclude filler */
   4095     int         location_offset = 0;
   4096     int         member_bitmap_width = 0;
   4097     int         member_chg = TRUE;
   4098     SHR_BITDCL *member_bitmap = NULL;
   4099     SHR_BITDCL *group_member_ptr = NULL;
   4100     bcm_if_t   *intf_array = NULL;
   4101     int         primary_count = 0;
   4102     int         intf_count = 0;
   4103     int         dlb_member_count = 0;
   4104     bcm_l3_ecmp_member_t *dlb_member_array = NULL; /* Include filler */
   4105     bcm_l3_egress_ecmp_t  dlb_ecmp;
   4106 
   4107     grand_max_paths =
   4108         (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) ?
   4109                                BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2 :
   4110                                BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit);
   4111     /* Check max_paths */
   4112     if ((ecmp->max_paths > grand_max_paths) || (ecmp->max_paths < 2)) {
   4113         return BCM_E_PARAM;
   4114     } else if (ecmp->max_paths == 0) {
   4115         ecmp->max_paths = grand_max_paths;
   4116     }
   4117 
   4118     if (ecmp_member_count > ecmp->max_paths) {
   4119         return BCM_E_RESOURCE;
   4120     }
   4121 
   4122     /* Convert the ecmp_member_array to intf_array */
   4123     intf_count = ecmp_member_count;
   4124     alloc_size = BCM_XGS3_L3_ECMP_MAX(unit) * sizeof(bcm_if_t);
   4125     intf_array = sal_alloc(alloc_size, "L3 ECMP intf_array");
   4126     if (intf_array == NULL) {
   4127         rv = BCM_E_MEMORY;
   4128         goto clean_up;
   4129     }
   4130     sal_memset(intf_array, 0, alloc_size);
   4131 
   4132     if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) {
   4133         for (i = 0; i < intf_count; i++) {
   4134             if (!(ecmp_member_array[i].flags & BCM_L3_ECMP_MEMBER_DGM_ALTERNATE)) {
   4135                 intf_array[j++] = ecmp_member_array[i].egress_if;
   4136                 primary_count++;
   4137             }
   4138         }
   4139         for (i = 0; i < intf_count; i++) {
   4140             if (ecmp_member_array[i].flags & BCM_L3_ECMP_MEMBER_DGM_ALTERNATE) {
   4141                 intf_array[j++] = ecmp_member_array[i].egress_if;
   4142             }
   4143         }
   4144         /* Either primary or alternate cannot exceed half  max paths */
   4145         if (primary_count > (ecmp->max_paths >> 1) ||
   4146             (intf_count - primary_count) > (ecmp->max_paths >> 1)) {
   4147             rv = BCM_E_RESOURCE;
   4148             goto clean_up;
   4149         }
   4150     } else {
   4151         for (i = 0; i < intf_count; i++) {
   4152             intf_array[i] = ecmp_member_array[i].egress_if;
   4153         }
   4154         primary_count = intf_count;
   4155     }
   4156 
   4157     /* Allocate interface array */
   4158     alloc_size = sizeof(bcm_if_t) * BCM_XGS3_L3_ECMP_MAX(unit);
   4159     dlb_intf_array = sal_alloc(alloc_size, "dlb intf array");
   4160     if (NULL == dlb_intf_array) {
   4161         rv = BCM_E_MEMORY;
   4162         goto clean_up;
   4163     }
   4164     sal_memset(dlb_intf_array, 0, alloc_size);
   4165 
   4166     /* Allocate DLB member bitmap */
   4167     member_bitmap_width = BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2;
   4168     member_bitmap = sal_alloc(SHR_BITALLOCSIZE(member_bitmap_width),
   4169                               "DLB ECMP member bitmap");
   4170     if (NULL == member_bitmap) {
   4171         rv = BCM_E_MEMORY;
   4172         goto clean_up;
   4173     }
   4174 
   4175     sal_memset(member_bitmap, 0, SHR_BITALLOCSIZE(member_bitmap_width));
   4176 
   4177     if (ecmp->flags & BCM_L3_REPLACE) {
   4178         if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp->ecmp_intf)) {
   4179             rv = BCM_E_PARAM;
   4180             goto clean_up;
   4181         }
   4182         /* Get currrent group bitmap */
   4183         ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   4184         group_member_ptr =
   4185             BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx);
   4186 
   4187         /* Get DLB group's existing member array including filler  */
   4188         bcm_l3_egress_ecmp_t_init(&dlb_ecmp);
   4189         dlb_ecmp.ecmp_intf = ecmp->ecmp_intf;
   4190 
   4191         alloc_size = sizeof(bcm_l3_ecmp_member_t) * BCM_XGS3_L3_ECMP_MAX(unit);
   4192         dlb_member_array = sal_alloc(alloc_size, "dlb intf array");
   4193         if (NULL == dlb_member_array) {
   4194             rv = BCM_E_MEMORY;
   4195             goto clean_up;
   4196         }
   4197         sal_memset(dlb_member_array, 0, alloc_size);
   4198         rv = bcm_xgs3_l3_ecmp_get(unit, &dlb_ecmp, BCM_XGS3_L3_ECMP_MAX(unit),
   4199                                   dlb_member_array, &dlb_member_count);
   4200         if (BCM_FAILURE(rv)) {
   4201             goto clean_up;
   4202         }
   4203 
   4204         if (dlb_ecmp.dynamic_mode == ecmp->dynamic_mode) {
   4205             /* Max_paths can not be changed for DLB/DGM group*/
   4206             if (dlb_ecmp.max_paths != ecmp->max_paths) {
   4207                 rv = BCM_E_PARAM;
   4208                 goto clean_up;
   4209             }
   4210 
   4211             /* Get DLB group's existing interface array including filler */
   4212             for (i = 0; i < dlb_member_count; i++) {
   4213                 dlb_intf_array[i] = dlb_member_array[i].egress_if;
   4214             }
   4215 
   4216             dlb_intf_count = dlb_member_count;
   4217 
   4218             /* Get DLB group's existing interface array excluding filler */
   4219             alloc_size = sizeof(bcm_if_t) * dlb_member_count;
   4220 
   4221             dlb_intf_array_2 = sal_alloc(alloc_size, "dlb intf array_2");
   4222             if (NULL == dlb_intf_array_2) {
   4223                 rv = BCM_E_MEMORY;
   4224                 goto clean_up;
   4225             }
   4226 
   4227             sal_memset(dlb_intf_array_2, 0, alloc_size);
   4228 
   4229             if (dlb_ecmp.dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) {
   4230                 SHR_BITCOUNT_RANGE(group_member_ptr, dlb_primary_count_2,
   4231                                    0, dlb_ecmp.max_paths / 2);
   4232                 if (dlb_primary_count_2) {
   4233                     /*  Should be expanded to max_paths / 2 with filler */
   4234                     dlb_primary_count = dlb_ecmp.max_paths / 2;
   4235                 } else {
   4236                     /* Only alternate members exist , start from 0 instead of max_paths / 2 */
   4237                     location_offset = dlb_ecmp.max_paths / 2;
   4238                 }
   4239             } else {
   4240                 SHR_BITCOUNT_RANGE(group_member_ptr, dlb_primary_count_2,
   4241                                    0, dlb_ecmp.max_paths);
   4242                 if (dlb_primary_count_2) {
   4243                      /*  Should be expanded to max_paths with filler */
   4244                     dlb_primary_count = dlb_ecmp.max_paths;
   4245                 }
   4246             }
   4247 
   4248             /* Exclude filler members of expanded DLB group */
   4249             for (i = 0; i < dlb_member_count; i++) {
   4250                 if (SHR_BITGET(group_member_ptr, i + location_offset)) {
   4251                     dlb_intf_array_2[dlb_intf_count_2++] =
   4252                         dlb_member_array[i].egress_if;
   4253                 }
   4254             }
   4255 
   4256             /* Compare new members(intf_array) with exisiting members(dlb_intf_array_2) */
   4257             if ((intf_count == dlb_intf_count_2) &&
   4258                 (primary_count == dlb_primary_count_2) &&
   4259                 !sal_memcmp((void *)intf_array, (void *)dlb_intf_array_2,
   4260                              (intf_count * sizeof(bcm_if_t)))) {
   4261                 member_chg = FALSE;
   4262             }
   4263         }
   4264     }
   4265 
   4266     /*
   4267      * To keep the traffic resiliency, the offset of DLB members in L3 ECMP tables should
   4268      * not be changed when an DLB ECMP member is deleted or added.
   4269      * - An expanded ecmp group will be used for DLB. SDK always allocates member entries
   4270      *   based on the configuration of max_paths. i.e. DLB(max_paths entries) or
   4271      *   DGM (max_paths/2 primary entries , max_paths/2 alternate entries).
   4272      *   Up to max_paths next hops can be supported in DLB group.
   4273      *   With DGM, it will support the groups with up to max_paths/2 primary
   4274      *   next hops and up to max_paths/2 alternate next hops. The DLB bitmap will always
   4275      *   reflect the TRUE DLB membership(specified by SDK API),
   4276      *   and the remaining entries will contain fillers which won't be selected by DLB.
   4277      * - When an DLB ECMP member is deleted, the space previously occupied by the deleted
   4278      *   member will be filled as a duplicate of any existing member.
   4279      * - When an DLB ECMP member is added, SDK will choose the space used by a filler
   4280      *   for the new member.
   4281      */
   4282     if (member_chg) {
   4283         sal_memset(dlb_intf_array, 0,
   4284                    sizeof(bcm_if_t) * BCM_XGS3_L3_ECMP_MAX(unit));
   4285         if (intf_count) {
   4286             if ((0 == primary_count) &&
   4287                 (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM)) {
   4288                 for (i = 0; i < ecmp->max_paths / 2; i++) {
   4289                     j = i % intf_count;
   4290                     dlb_intf_array[i] = intf_array[j];
   4291                     if (i < intf_count) {
   4292                         SHR_BITSET(member_bitmap, i + ecmp->max_paths / 2);
   4293                     }
   4294                 }
   4295                 /*  If only alternate exist, expand ecmp group to max_paths / 2 with filler */
   4296                 dlb_intf_count = ecmp->max_paths / 2;
   4297                 dlb_primary_count = 0;
   4298             } else if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) {
   4299 
   4300                 for (i = 0; i < ecmp->max_paths / 2; i++) {
   4301                     j = i % primary_count;
   4302                     dlb_intf_array[i] = intf_array[j];
   4303                     if (i < primary_count) {
   4304                         SHR_BITSET(member_bitmap, i);
   4305                     }
   4306                 }
   4307 
   4308                 /*  If primary exist, expand ecmp group to max_paths / 2 with filler */
   4309                 dlb_intf_count = ecmp->max_paths / 2;
   4310                 dlb_primary_count = ecmp->max_paths / 2;
   4311 
   4312                 if (intf_count - primary_count) {
   4313                     for (i = 0; i < ecmp->max_paths / 2; i++) {
   4314                         j = primary_count + i % (intf_count - primary_count);
   4315                         dlb_intf_array[i + ecmp->max_paths / 2] = intf_array[j];
   4316                         if (i < (intf_count - primary_count)) {
   4317                             SHR_BITSET(member_bitmap, i + ecmp->max_paths / 2);
   4318                         }
   4319                     }
   4320 
   4321                     /*  If alternate also exist, expand ecmp group to max_paths with filler */
   4322                     dlb_intf_count = dlb_intf_count + ecmp->max_paths / 2;
   4323                 }
   4324             } else {
   4325                 for (i = 0; i < ecmp->max_paths; i++) {
   4326                     j = i % intf_count;
   4327                     dlb_intf_array[i] = intf_array[j];
   4328                     if (i < intf_count) {
   4329                         SHR_BITSET(member_bitmap, i);
   4330                     }
   4331                 }
   4332 
   4333                 /*  expand ecmp group  to max_paths with filler */
   4334                 dlb_intf_count = ecmp->max_paths;
   4335                 dlb_primary_count = ecmp->max_paths;
   4336             }
   4337         } else {
   4338             dlb_intf_count = 0;
   4339             dlb_primary_count = 0;
   4340         }
   4341     } else {
   4342         sal_memcpy(member_bitmap, group_member_ptr,
   4343                    SHR_BITALLOCSIZE(member_bitmap_width));
   4344     }
   4345 
   4346     rv = _bcm_esw_l3_ecmp_create(unit, ecmp, dlb_intf_count,
   4347                                  dlb_intf_array, BCM_L3_ECMP_MEMBER_OP_SET,
   4348                                  0, NULL, dlb_primary_count, member_bitmap);
   4349     if (member_chg && BCM_SUCCESS(rv)) {
   4350         ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   4351         group_member_ptr =
   4352             BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx);
   4353         sal_memcpy(group_member_ptr, member_bitmap,
   4354                    SHR_BITALLOCSIZE(member_bitmap_width));
   4355     }
   4356 
   4357 clean_up:
   4358 
   4359     if (intf_array) {
   4360         sal_free(intf_array);
   4361     }
   4362 
   4363     if (dlb_intf_array) {
   4364         sal_free(dlb_intf_array);
   4365     }
   4366 
   4367     if (member_bitmap) {
   4368         sal_free(member_bitmap);
   4369     }
   4370 
   4371     if (dlb_member_array) {
   4372         sal_free(dlb_member_array);
   4373     }
   4374 
   4375     if (dlb_intf_array_2) {
   4376         sal_free(dlb_intf_array_2);
   4377     }
   4378 
   4379     return rv;
   4380 }
   4381 
   4382 /*
   4383  * Function:
   4384  *      bcm_th2_l3_ecmp_dlb_member_add
   4385  * Purpose:
   4386  *      Add an Egress forwarding object to an Egress DLB ECMP forwarding object.
   4387  * Parameters:
   4388  *      unit        - (IN) bcm device.
   4389  *      ecmp        - (IN) ECMP group info.
   4390  *      intf        - (IN) Deleted L3 interface id.
   4391  *      intf_array  - (IN/OUT) Array of Egress forwarding objects.
   4392  *      intf_count  - (IN/OUT) Number of entries of intf_count actually filled in.
   4393  * Returns:
   4394  *      BCM_E_XXX
   4395  */
   4396 int
   4397 bcm_th2_l3_ecmp_dlb_member_add(int unit,
   4398                                   bcm_l3_egress_ecmp_t *ecmp, bcm_if_t intf,
   4399                                   bcm_if_t *intf_array, int *intf_count)
   4400 
   4401 {
   4402     int rv = BCM_E_NONE;
   4403     int ecmp_group_idx = 0;
   4404     int i = 0, j = 0;
   4405     int dlb_member_add_flag = FALSE;
   4406     int dlb_member_count = 0;   /* Exclude filler */
   4407     int member_bitmap_width = 0;
   4408     SHR_BITDCL *member_bitmap = NULL;
   4409     SHR_BITDCL *group_member_ptr = NULL;
   4410     bcm_if_t   *dlb_intf_array = NULL; /* Exclude filler */
   4411 
   4412     /* Allocate DLB member bitmap */
   4413     member_bitmap_width = BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2;
   4414     member_bitmap = sal_alloc(SHR_BITALLOCSIZE(member_bitmap_width),
   4415                               "DLB ECMP member bitmap");
   4416     if (NULL == member_bitmap) {
   4417         rv = BCM_E_MEMORY;
   4418         goto clean_up;
   4419     }
   4420 
   4421     sal_memset(member_bitmap, 0, SHR_BITALLOCSIZE(member_bitmap_width));
   4422 
   4423     /* Get currrent group bitmap */
   4424     ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   4425     group_member_ptr =
   4426         BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx);
   4427 
   4428     if ((*intf_count != ecmp->max_paths) && (*intf_count != 0)) {
   4429         /* Should always has max_paths or 0 members on expanded DLB group */
   4430         rv = BCM_E_INTERNAL;
   4431         goto clean_up;
   4432     }
   4433 
   4434     sal_memcpy(member_bitmap, group_member_ptr,
   4435                SHR_BITALLOCSIZE(member_bitmap_width));
   4436 
   4437     /* Allocate DLB intf array */
   4438     dlb_intf_array = sal_alloc(BCM_XGS3_L3_ECMP_MAX(unit) *
   4439                                sizeof(bcm_if_t),
   4440                                "ecmp intf array");
   4441     if (NULL == dlb_intf_array) {
   4442         rv = BCM_E_MEMORY;
   4443         goto clean_up;
   4444     }
   4445 
   4446     /* Get the DLB intf (including added intf) without filler */
   4447     dlb_member_count = 0;
   4448     for (i = 0; i < ecmp->max_paths; i++) {
   4449         if (SHR_BITGET(member_bitmap, i)) {
   4450             dlb_intf_array[dlb_member_count++] = intf_array[i];
   4451         } else {
   4452             if(!dlb_member_add_flag) {
   4453                 dlb_intf_array[dlb_member_count++] = intf;
   4454                 dlb_member_add_flag = TRUE;
   4455             }
   4456         }
   4457     }
   4458 
   4459     if (!dlb_member_add_flag) {
   4460         rv = BCM_E_FULL;
   4461         goto clean_up;
   4462     }
   4463 
   4464     /* Refill the members of expanded DLB group */
   4465     dlb_member_add_flag = FALSE;
   4466     for (i = 0; i < ecmp->max_paths; i++) {
   4467         if (dlb_member_count > 1) {
   4468             if (!SHR_BITGET(member_bitmap, i)) {
   4469                 if (dlb_member_add_flag) {
   4470                     intf_array[i] = dlb_intf_array[j % dlb_member_count];
   4471                     j++;
   4472                 } else {
   4473                     SHR_BITSET(member_bitmap, i);
   4474                     intf_array[i] = intf;
   4475                     dlb_member_add_flag = TRUE;
   4476                 }
   4477             }
   4478         } else {
   4479             /* Add first primary member into DLB group */
   4480             intf_array[i] = intf;
   4481             if (!dlb_member_add_flag) {
   4482                 SHR_BITSET(member_bitmap, i);
   4483                 dlb_member_add_flag = TRUE;
   4484             }
   4485             (*intf_count)++;
   4486         }
   4487     }
   4488 
   4489     if (!dlb_member_add_flag) {
   4490         rv = BCM_E_INTERNAL;
   4491         goto clean_up;
   4492     }
   4493 
   4494     /* Update ECMP group */
   4495     ecmp->flags |= BCM_L3_REPLACE | BCM_L3_WITH_ID;
   4496     rv = _bcm_esw_l3_ecmp_create(unit, ecmp, *intf_count,
   4497                                  intf_array, BCM_L3_ECMP_MEMBER_OP_ADD,
   4498                                  1, &intf, *intf_count, member_bitmap);
   4499     if (BCM_SUCCESS(rv)) {
   4500         sal_memcpy(group_member_ptr, member_bitmap,
   4501                    SHR_BITALLOCSIZE(member_bitmap_width));
   4502     }
   4503 
   4504 clean_up:
   4505 
   4506     if (member_bitmap) {
   4507         sal_free(member_bitmap);
   4508     }
   4509 
   4510     if (dlb_intf_array) {
   4511         sal_free(dlb_intf_array);
   4512     }
   4513 
   4514     return rv;
   4515 }
   4516 
   4517 /*
   4518  * Function:
   4519  *      bcm_th2_l3_ecmp_dlb_dgm_member_add
   4520  * Purpose:
   4521  *      Add an Egress forwarding object to an Egress DLB/DGM ECMP forwarding object.
   4522  * Parameters:
   4523  *      unit              - (IN) bcm device.
   4524  *      ecmp              - (IN) ECMP group info.
   4525  *      ecmp_member       - (IN) Deleted L3 interface id pointing to Egress forwarding object.
   4526  *      ecmp_member_array - (IN/OUT) Member array of Egress forwarding objects.
   4527  *      ecmp_member_count - (IN/OUT) Number of members of ecmp_member_count actually  filled in.
   4528  *
   4529  * Returns:
   4530  *      BCM_E_XXX
   4531  */
   4532 int
   4533 bcm_th2_l3_ecmp_dlb_dgm_member_add(int unit,
   4534                                    bcm_l3_egress_ecmp_t *ecmp,
   4535                                    bcm_l3_ecmp_member_t *ecmp_member,
   4536                                    bcm_l3_ecmp_member_t *ecmp_member_array,
   4537                                    int *ecmp_member_count)
   4538 {
   4539     int rv = BCM_E_NONE;
   4540     int alloc_size = 0;
   4541     bcm_if_t *intf_array = 0;      /* Include filler */
   4542     bcm_l3_ecmp_member_t *dlb_member_array = 0; /* Exclude filler */
   4543     int ecmp_group_idx = 0;
   4544     int dlb_member_add_flag = FALSE;
   4545     int dlb_member_count = 0;   /* Exclude filler */
   4546     int alternate_count = 0;   /* Include filler */
   4547     int primary_count = 0;     /* Include filler */
   4548     int start = 0, end = 0;
   4549     int i = 0, j = 0;
   4550     int location_offset = 0, copy_offset = 0;
   4551     int member_bitmap_width = 0;
   4552     SHR_BITDCL *member_bitmap = NULL;
   4553     SHR_BITDCL *group_member_ptr = NULL;
   4554 
   4555     /* Allocate DLB member bitmap */
   4556     member_bitmap_width = BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2;
   4557     member_bitmap = sal_alloc(SHR_BITALLOCSIZE(member_bitmap_width),
   4558                               "DLB ECMP member bitmap");
   4559     if (NULL == member_bitmap) {
   4560         rv = BCM_E_MEMORY;
   4561         goto clean_up;
   4562     }
   4563 
   4564     sal_memset(member_bitmap, 0, SHR_BITALLOCSIZE(member_bitmap_width));
   4565 
   4566     /* Get currrent group bitmap */
   4567     ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   4568     group_member_ptr =
   4569         BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx);
   4570     SHR_BITCOUNT_RANGE(group_member_ptr, dlb_member_count, 0, ecmp->max_paths);
   4571 
   4572     sal_memcpy(member_bitmap, group_member_ptr,
   4573                SHR_BITALLOCSIZE(member_bitmap_width));
   4574 
   4575     /* Allocate interface array */
   4576     alloc_size = sizeof(bcm_if_t) * BCM_XGS3_L3_ECMP_MAX(unit);
   4577     intf_array = sal_alloc(alloc_size, "intf array");
   4578     if (NULL == intf_array) {
   4579         rv = BCM_E_MEMORY;
   4580         goto clean_up;
   4581 
   4582     }
   4583     sal_memset(intf_array, 0, alloc_size);
   4584 
   4585     /*
   4586      * Index of ecmp_member_array
   4587      * - Both primary and alternate members exist: Primary members start
   4588      *    from 0 and Alternate members start from max_paths / 2
   4589      * - Only primary members exist: Primary members start from 0
   4590      * - Only alternate members exist: Alternate members start from 0
   4591      * Offset of DLB members bitmap
   4592      * - Primary members always start from 0
   4593      * - Alternate members always start from max_paths / 2
   4594      * Member count (including filler)
   4595      * - DLB count: 0 or max_paths if exist
   4596      * - DGM primary count: 0 or max_paths/2 if exsit
   4597      *   DGM alternate count: 0 or max_paths/2 if exist
   4598      */
   4599     if ((ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) &&
   4600         (ecmp_member->flags & BCM_L3_ECMP_MEMBER_DGM_ALTERNATE)) {
   4601         /* Add alternate member */
   4602         start = ecmp->max_paths / 2;
   4603         end = start * 2;
   4604 
   4605         /* Get the count of  alternate members (without filler) */
   4606         SHR_BITCOUNT_RANGE(group_member_ptr, dlb_member_count,
   4607                            start, end - start);
   4608         alternate_count =
   4609             dlb_member_count ? ecmp->max_paths / 2 : 0;
   4610         primary_count = (*ecmp_member_count) - alternate_count;
   4611 
   4612         /*
   4613          *  Only alternate members exist:
   4614          *  Alternate members start from 0, there should a location offset.
   4615          */
   4616         if (0 == primary_count) {
   4617             location_offset = ecmp->max_paths / 2;
   4618         }
   4619 
   4620     } else {
   4621         /* Add primary member */
   4622         start = 0;
   4623         if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) {
   4624             end = ecmp->max_paths / 2;
   4625         } else {
   4626             end = ecmp->max_paths;
   4627         }
   4628 
   4629         /* Get the count of  primary members (without filler) */
   4630         SHR_BITCOUNT_RANGE(group_member_ptr, dlb_member_count, start, end);
   4631 
   4632         primary_count = dlb_member_count ? end : 0;
   4633         alternate_count = (*ecmp_member_count) - primary_count;
   4634 
   4635         if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) {
   4636             /*
   4637              * Add first primary member - Alternate members shoud be moved,
   4638              * and start from max_paths / 2 if any.
   4639              */
   4640             if (alternate_count > 0) {
   4641                 copy_offset =  ecmp->max_paths / 2;
   4642             }
   4643         }
   4644     }
   4645 
   4646     /* Allocate DLB member array */
   4647     dlb_member_array = sal_alloc(BCM_XGS3_L3_ECMP_MAX(unit) *
   4648                                  sizeof(bcm_l3_ecmp_member_t),
   4649                                  "ecmp member array");
   4650     if (NULL == dlb_member_array) {
   4651         rv = BCM_E_MEMORY;
   4652         goto clean_up;
   4653     }
   4654 
   4655     /* Get the DLB members (including added member) without filler */
   4656     dlb_member_count = 0;
   4657     for (i = start - location_offset; i < end - location_offset; i++) {
   4658         if (SHR_BITGET(member_bitmap, i + location_offset)) {
   4659             sal_memcpy(&dlb_member_array[dlb_member_count++],
   4660                        &ecmp_member_array[i],
   4661                        sizeof(bcm_l3_ecmp_member_t));
   4662         } else {
   4663             if(!dlb_member_add_flag) {
   4664                 sal_memcpy(&dlb_member_array[dlb_member_count++],
   4665                            ecmp_member,
   4666                            sizeof(bcm_l3_ecmp_member_t));
   4667                 dlb_member_add_flag = TRUE;
   4668             }
   4669         }
   4670     }
   4671 
   4672     if (!dlb_member_add_flag) {
   4673         rv = BCM_E_FULL;
   4674         goto clean_up;
   4675     }
   4676 
   4677     /* Refill the members of expanded DLB group */
   4678     dlb_member_add_flag = FALSE;
   4679     for (i = start - location_offset; i < end - location_offset; i++) {
   4680         if (dlb_member_count > 1) {
   4681             if (!SHR_BITGET(member_bitmap, i + location_offset)) {
   4682                 if (dlb_member_add_flag) {
   4683                     sal_memcpy(&ecmp_member_array[i],
   4684                                &dlb_member_array[j % dlb_member_count],
   4685                                sizeof(bcm_l3_ecmp_member_t));
   4686                     j++;
   4687                 } else {
   4688                     SHR_BITSET(member_bitmap, i + location_offset);
   4689                     sal_memcpy(&ecmp_member_array[i], ecmp_member,
   4690                                sizeof(bcm_l3_ecmp_member_t));
   4691                     dlb_member_add_flag = TRUE;
   4692                 }
   4693             }
   4694         } else {
   4695             /*
   4696              * 1. Add first DLB member
   4697              * 2. or Add first DGM primary member
   4698              * 3. or Add first DGM alternate member
   4699              */
   4700             if (copy_offset) {
   4701                /*
   4702                 * DGM - Add the first primary member -
   4703                 * Alternate members shoud be moved,
   4704                 * and start from max_paths / 2 instead of 0.
   4705                 */
   4706                 sal_memcpy(&ecmp_member_array[i + copy_offset],
   4707                            &ecmp_member_array[i],
   4708                            sizeof(bcm_l3_ecmp_member_t));
   4709             }
   4710             sal_memcpy(&ecmp_member_array[i], ecmp_member,
   4711                        sizeof(bcm_l3_ecmp_member_t));
   4712 
   4713             if (!dlb_member_add_flag) {
   4714                 SHR_BITSET(member_bitmap, i + location_offset);
   4715                 dlb_member_add_flag = TRUE;
   4716             }
   4717 
   4718             (*ecmp_member_count)++;
   4719             if (!(ecmp_member->flags &
   4720                 BCM_L3_ECMP_MEMBER_DGM_ALTERNATE)) {
   4721                 primary_count++;
   4722             }
   4723         }
   4724     }
   4725 
   4726     for (i = 0; i < (*ecmp_member_count); i++) {
   4727         intf_array[i] = ecmp_member_array[i].egress_if;
   4728     }
   4729 
   4730     /* Update ECMP group */
   4731     ecmp->flags |= BCM_L3_REPLACE | BCM_L3_WITH_ID;
   4732     rv = _bcm_esw_l3_ecmp_create(unit, ecmp, *ecmp_member_count,
   4733                                  intf_array, BCM_L3_ECMP_MEMBER_OP_ADD,
   4734                                  1, &(ecmp_member->egress_if),
   4735                                  primary_count, member_bitmap);
   4736     if (BCM_SUCCESS(rv)) {
   4737         sal_memcpy(group_member_ptr, member_bitmap,
   4738                    SHR_BITALLOCSIZE(member_bitmap_width));
   4739     }
   4740 
   4741 clean_up:
   4742 
   4743      if (member_bitmap) {
   4744          sal_free(member_bitmap);
   4745      }
   4746 
   4747      if (intf_array) {
   4748          sal_free(intf_array);
   4749      }
   4750 
   4751      if (dlb_member_array) {
   4752          sal_free(dlb_member_array);
   4753      }
   4754 
   4755      return rv;
   4756 }
   4757 
   4758 /*
   4759  * Function:
   4760  *      bcm_th2_l3_ecmp_dlb_member_get
   4761  * Purpose:
   4762  *      Get an Egress DLB ECMP forwarding object.
   4763  * Parameters:
   4764  *      unit       - (IN) bcm device.
   4765  *      ecmp       - (INOUT) ECMP group info.
   4766  *      intf_size  - (IN) Size of allocated entries in intf_array.
   4767  *      intf_array - (OUT) Array of Egress forwarding objects.
   4768  *      intf_count - (OUT) Number of entries of intf_count actually filled in.
   4769  *
   4770  * Returns:
   4771  *      BCM_E_XXX
   4772  */
   4773 int
   4774 bcm_th2_l3_ecmp_dlb_member_get(int unit,
   4775                                bcm_l3_egress_ecmp_t *ecmp, int intf_size,
   4776                                bcm_if_t *intf_array, int *intf_count)
   4777 {
   4778     int         rv = BCM_E_NONE;
   4779     bcm_if_t   *dlb_intf_array = NULL;  /* Include filler */
   4780     int         dlb_intf_count = 0;     /* Include filler */
   4781     int         dlb_intf_size = 0;
   4782     int         ecmp_group_idx = 0;
   4783     int         i = 0, j = 0;
   4784     SHR_BITDCL *group_bitmap_ptr = NULL;
   4785 
   4786     /* input check*/
   4787     if ((NULL == intf_count) ||
   4788         ((NULL == intf_array) && (0 != intf_size))) {
   4789         rv = BCM_E_PARAM;
   4790         goto clean_up;
   4791     }
   4792 
   4793     if (intf_size) {
   4794         dlb_intf_array = sal_alloc(sizeof(bcm_if_t) *
   4795                                    BCM_XGS3_L3_ECMP_MAX(unit),
   4796                                    "ecmp intf array");
   4797         if (NULL == dlb_intf_array) {
   4798             rv = BCM_E_MEMORY;
   4799             goto clean_up;
   4800         }
   4801         dlb_intf_size = BCM_XGS3_L3_ECMP_MAX(unit);
   4802     }
   4803 
   4804     /* Get the ECMP member's information including filler  */
   4805     rv = _bcm_esw_l3_egress_ecmp_get(unit, ecmp, dlb_intf_size,
   4806                                      dlb_intf_array, &dlb_intf_count, TRUE);
   4807     if (BCM_FAILURE(rv)) {
   4808         goto clean_up;
   4809     }
   4810 
   4811     ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   4812     group_bitmap_ptr =
   4813         BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx);
   4814 
   4815     /* Exclude filler members from expanded DLB group */
   4816     if (intf_size) {
   4817         for (i = 0; i < dlb_intf_count; i++) {
   4818             if (SHR_BITGET(group_bitmap_ptr, i)) {
   4819                 intf_array[j++] = dlb_intf_array[i];
   4820             }
   4821             if (j == intf_size) {
   4822                 break;
   4823             }
   4824         }
   4825         *intf_count = j;
   4826     } else {
   4827         SHR_BITCOUNT_RANGE(group_bitmap_ptr, *intf_count, 0, ecmp->max_paths);
   4828     }
   4829 
   4830 clean_up:
   4831 
   4832     if (dlb_intf_array) {
   4833         sal_free(dlb_intf_array);
   4834     }
   4835 
   4836     return rv;
   4837 }
   4838 
   4839 
   4840 /*
   4841  * Function:
   4842  *      bcm_th2_l3_ecmp_dlb_dgm_member_get
   4843  * Purpose:
   4844  *      Get an Egress DLB/DGM ECMP forwarding object.
   4845  * Parameters:
   4846  *      unit              - (IN) bcm device.
   4847  *      ecmp_info         - (INOUT) ECMP group info.
   4848  *      ecmp_member_size  - (IN) Size of allocated entries in ecmp_member_array.
   4849  *      ecmp_member_array - (OUT) Member array of Egress forwarding objects.
   4850  *      ecmp_member_count - (OUT) Number of members of ecmp_member_count actually
   4851  *                                filled in.
   4852  * Returns:
   4853  *      BCM_E_XXX
   4854  */
   4855 int
   4856 bcm_th2_l3_ecmp_dlb_dgm_member_get(int unit,
   4857                                    bcm_l3_egress_ecmp_t *ecmp_info,
   4858                                    int ecmp_member_size,
   4859                                    bcm_l3_ecmp_member_t *ecmp_member_array,
   4860                                    int *ecmp_member_count)
   4861 {
   4862     int         rv = BCM_E_NONE;
   4863     int         ecmp_group_idx = 0;
   4864     int         location_offset = 0;
   4865     int         primary_count = 0;
   4866     int         i = 0, j = 0;
   4867     SHR_BITDCL *group_bitmap_ptr = NULL;
   4868     int         dlb_member_count = 0;     /* Include filler */
   4869     int         dlb_member_size = 0;
   4870     bcm_l3_ecmp_member_t *dlb_member_array = NULL;  /* Include filler */
   4871 
   4872     /* Input check */
   4873     if ((NULL == ecmp_member_count) ||
   4874         ((NULL == ecmp_member_array) && (0 != ecmp_member_size))) {
   4875         rv = BCM_E_PARAM;
   4876         goto clean_up;
   4877     }
   4878 
   4879     if (ecmp_member_size) {
   4880         dlb_member_array = sal_alloc(sizeof(bcm_l3_ecmp_member_t) *
   4881                                      BCM_XGS3_L3_ECMP_MAX(unit),
   4882                                      "ecmp member array");
   4883         if (NULL == dlb_member_array) {
   4884             rv = BCM_E_MEMORY;
   4885             goto clean_up;
   4886         }
   4887         sal_memset(dlb_member_array, 0, sizeof(bcm_l3_ecmp_member_t) *
   4888                    BCM_XGS3_L3_ECMP_MAX(unit));
   4889         dlb_member_size = BCM_XGS3_L3_ECMP_MAX(unit);
   4890     }
   4891 
   4892     /* Get the ECMP member's information including filler  */
   4893     rv = _bcm_xgs3_l3_ecmp_member_get(
   4894              unit, ecmp_info, dlb_member_size,
   4895              dlb_member_array, &dlb_member_count);
   4896 
   4897     if (BCM_FAILURE(rv)) {
   4898         goto clean_up;
   4899     }
   4900 
   4901     ecmp_group_idx = ecmp_info->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   4902     group_bitmap_ptr =
   4903         BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx);
   4904 
   4905     if (ecmp_member_size) {
   4906         if (ecmp_info->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) {
   4907 
   4908             SHR_BITCOUNT_RANGE(group_bitmap_ptr, primary_count,
   4909                                0, ecmp_info->max_paths / 2);
   4910 
   4911             /* Only alternate members exist */
   4912             if (0 == primary_count) {
   4913                 location_offset = ecmp_info->max_paths / 2;
   4914             }
   4915         }
   4916 
   4917         /* Exclude filler members from expanded DLB group */
   4918         for (i = 0; i < dlb_member_count; i++) {
   4919             if (SHR_BITGET(group_bitmap_ptr, i + location_offset)) {
   4920                 sal_memcpy(&ecmp_member_array[j++],
   4921                            &dlb_member_array[i],
   4922                            sizeof(bcm_l3_ecmp_member_t));
   4923             }
   4924             if (j == ecmp_member_size) {
   4925                 break;
   4926             }
   4927         }
   4928         *ecmp_member_count = j;
   4929     } else {
   4930         SHR_BITCOUNT_RANGE(group_bitmap_ptr, *ecmp_member_count,
   4931                            0, ecmp_info->max_paths);
   4932     }
   4933 
   4934 clean_up:
   4935 
   4936     if (dlb_member_array) {
   4937         sal_free(dlb_member_array);
   4938     }
   4939 
   4940     return rv;
   4941 }
   4942 
   4943 /*
   4944  * Function:
   4945  *      _bcm_th2_ecmp_dlb_random_seed_set
   4946  * Purpose:
   4947  *      Set ECMP DLB random seed.
   4948  * Parameters:
   4949  *      unit - (IN) SOC unit number.
   4950  *      seed - (IN) Random seed.
   4951  * Returns:
   4952  *      BCM_E_xxx
   4953  */
   4954 STATIC int
   4955 _bcm_th2_ecmp_dlb_random_seed_set(int unit, int seed)
   4956 {
   4957 
   4958     uint32 rval;
   4959     uint32 hw_limit;
   4960 
   4961     hw_limit = (1 << soc_reg_field_length(unit, DLB_ECMP_RANDOM_SELECTION_CONTROLr,
   4962                                           SEEDf)) - 1;
   4963     if (seed < 0 ||
   4964         seed > hw_limit) {
   4965         /* Hardware limits */
   4966         return BCM_E_PARAM;
   4967     }
   4968 
   4969     BCM_IF_ERROR_RETURN(READ_DLB_ECMP_RANDOM_SELECTION_CONTROLr(unit, &rval));
   4970     soc_reg_field_set(unit, DLB_ECMP_RANDOM_SELECTION_CONTROLr, &rval, SEEDf,
   4971                       seed);
   4972 
   4973     BCM_IF_ERROR_RETURN(WRITE_DLB_ECMP_RANDOM_SELECTION_CONTROLr(unit, rval));
   4974     return BCM_E_NONE;
   4975 }
   4976 
   4977 
   4978 
   4979 
   4980 /*
   4981  * Function:
   4982  *      _bcm_th2_ecmp_dlb_random_seed_get
   4983  * Purpose:
   4984  *      Set ECMP DLB random seed.
   4985  * Parameters:
   4986  *      unit - (IN)  SOC unit number.
   4987  *      seed - (OUT) Random seed.
   4988  * Returns:
   4989  *      BCM_E_xxx
   4990  */
   4991 STATIC int
   4992 _bcm_th2_ecmp_dlb_random_seed_get(int unit, int *seed)
   4993 {
   4994 
   4995     uint32 rval;
   4996 
   4997     BCM_IF_ERROR_RETURN(READ_DLB_ECMP_RANDOM_SELECTION_CONTROLr(unit, &rval));
   4998     *seed = soc_reg_field_get(unit, DLB_ECMP_RANDOM_SELECTION_CONTROLr, rval,
   4999                         SEEDf);
   5000     return BCM_E_NONE;
   5001 }
   5002 
   5003 
   5004 /*
   5005  * Function:
   5006  *      _bcm_th2_ecmp_dlb_sample_rate_thresholds_set
   5007  * Purpose:
   5008  *      Set ECMP DLB sample period and physical link accounting thresholds.
   5009  * Parameters:
   5010  *      unit        - (IN) SOC unit number.
   5011  *      sample_rate - (IN) Number of samplings per second.
   5012  *      min_th      - (IN) Minimum port load threshold, in mbps.
   5013  *      max_th      - (IN) Maximum port load threshold, in mbps.
   5014  * Returns:
   5015  *      BCM_E_xxx
   5016  */
   5017 STATIC int
   5018 _bcm_th2_ecmp_dlb_sample_rate_thresholds_set(int unit, int sample_rate,
   5019                                              int min_th, int max_th)
   5020 {
   5021     int num_time_units;
   5022     uint32 measure_control_reg;
   5023     int max_th_bytes;
   5024     int th_increment;
   5025     dlb_ecmp_glb_quantize_threshold_entry_t quantize_threshold_entry;
   5026     int i;
   5027     int th_bytes[7];
   5028     uint32 hw_limit;
   5029 
   5030     if (sample_rate <= 0 || min_th < 0 || max_th < 0) {
   5031         return BCM_E_PARAM;
   5032     }
   5033 
   5034     if (min_th > max_th) {
   5035         max_th = min_th;
   5036     }
   5037 
   5038     /* Compute sampling period in units of 1us:
   5039      *     number of 1us time units = 10^6 / sample_rate
   5040      */
   5041     num_time_units = 1000000 / sample_rate;
   5042     hw_limit = (1 << soc_reg_field_length(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   5043                                             SAMPLING_PERIODf)) - 1;
   5044     if (num_time_units < 1 || num_time_units > hw_limit) {
   5045         /* Hardware limits */
   5046         return BCM_E_PARAM;
   5047     }
   5048 
   5049     /* Compute threshold in bytes per sampling period:
   5050      * bytes per 1us = (million bits per sec) * 10^6 / 8 * 10^(-6),
   5051      * bytes per sampling period = (bytes per 1us) * (number of 1us
   5052      *                             time units in sampling period)
   5053      *                           = mbps * num_time_units / 8
   5054      */
   5055     max_th_bytes = max_th * num_time_units / 8;
   5056     hw_limit = (1 << soc_mem_field_length(unit, DLB_ECMP_GLB_QUANTIZE_THRESHOLDm,
   5057                                             PORT_LOADING_THRESHOLDf)) - 1;
   5058     if (max_th_bytes > hw_limit) {
   5059         /* Hardware limits */
   5060         return BCM_E_PARAM;
   5061     }
   5062 
   5063     BCM_IF_ERROR_RETURN
   5064         (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   5065     soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   5066             &measure_control_reg, SAMPLING_PERIODf, num_time_units);
   5067     BCM_IF_ERROR_RETURN
   5068         (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg));
   5069     ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate = sample_rate;
   5070 
   5071     /* Use min threshold as threshold 0, and max threshold as threshold 6.
   5072      * Thresholds 1 to 5 will be evenly spread out between min and max
   5073      * thresholds.
   5074      */
   5075     th_increment = (max_th - min_th) / 6;
   5076     for (i = 0; i < 7; i++) {
   5077         BCM_IF_ERROR_RETURN
   5078             (READ_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm(unit, MEM_BLOCK_ANY, i,
   5079                                               &quantize_threshold_entry));
   5080         th_bytes[i] = (min_th + i * th_increment) * num_time_units / 8;
   5081         soc_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm_field32_set
   5082             (unit, &quantize_threshold_entry, PORT_LOADING_THRESHOLDf,
   5083              th_bytes[i]);
   5084         BCM_IF_ERROR_RETURN
   5085             (WRITE_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm(unit, MEM_BLOCK_ALL, i,
   5086                                                &quantize_threshold_entry));
   5087     }
   5088 
   5089     ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th = min_th;
   5090     ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th = max_th;
   5091 
   5092     return BCM_E_NONE;
   5093 }
   5094 
   5095 /*
   5096  * Function:
   5097  *      _bcm_th2_ecmp_dlb_sample_rate_set
   5098  * Purpose:
   5099  *      Set ECMP dynamic load balancing sample rate.
   5100  * Parameters:
   5101  *      unit - (IN) SOC unit number.
   5102  *      sample_rate - (IN) Number of samplings per second.
   5103  * Returns:
   5104  *      BCM_E_xxx
   5105  */
   5106 STATIC int
   5107 _bcm_th2_ecmp_dlb_sample_rate_set(int unit, int sample_rate)
   5108 {
   5109     BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_sample_rate_thresholds_set(unit,
   5110                 sample_rate, ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th,
   5111                 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th));
   5112 
   5113     return BCM_E_NONE;
   5114 }
   5115 
   5116 
   5117 /*
   5118  * Function:
   5119  *      _bcm_th2_ecmp_dlb_tx_load_min_th_set
   5120  * Purpose:
   5121  *      Set ECMP DLB port load minimum threshold.
   5122  * Parameters:
   5123  *      unit    - (IN) SOC unit number.
   5124  *      min_th  - (IN) Minimum port loading threshold.
   5125  * Returns:
   5126  *      BCM_E_xxx
   5127  */
   5128 STATIC int
   5129 _bcm_th2_ecmp_dlb_tx_load_min_th_set(int unit, int min_th)
   5130 {
   5131     BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_sample_rate_thresholds_set(unit,
   5132                 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate, min_th,
   5133                 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th));
   5134     return BCM_E_NONE;
   5135 }
   5136 
   5137 /*
   5138  * Function:
   5139  *      _bcm_trident_ecmp_dlb_tx_load_max_th_set
   5140  * Purpose:
   5141  *      Set ECMP DLB port load maximum threshold.
   5142  * Parameters:
   5143  *      unit    - (IN) SOC unit number.
   5144  *      max_th  - (IN) Maximum port loading threshold.
   5145  * Returns:
   5146  *      BCM_E_xxx
   5147  */
   5148 STATIC int
   5149 _bcm_th2_ecmp_dlb_tx_load_max_th_set(int unit, int max_th)
   5150 {
   5151     BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_sample_rate_thresholds_set(unit,
   5152                 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate,
   5153                 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th,
   5154                 max_th));
   5155     return BCM_E_NONE;
   5156 }
   5157 
   5158 
   5159 
   5160 
   5161 /*
   5162  * Function:
   5163  *      _bcm_th2_ecmp_dlb_qsize_thresholds_set
   5164  * Purpose:
   5165  *      Set ECMP DLB queue size thresholds.
   5166  * Parameters:
   5167  *      unit    - (IN) SOC unit number.
   5168  *      min_th  - (IN) Minimum queue size threshold, in bytes.
   5169  *      max_th  - (IN) Maximum queue size threshold, in bytes.
   5170  * Returns:
   5171  *      BCM_E_xxx
   5172  */
   5173 STATIC int
   5174 _bcm_th2_ecmp_dlb_qsize_thresholds_set(int unit, int min_th, int max_th)
   5175 {
   5176     int max_th_cells;
   5177     int th_increment;
   5178     dlb_ecmp_glb_quantize_threshold_entry_t quantize_threshold_entry;
   5179     int i;
   5180     int th_cells[7];
   5181     uint32 hw_limit;
   5182 
   5183     if (min_th < 0 || max_th < 0) {
   5184         return BCM_E_PARAM;
   5185     }
   5186 
   5187     if (min_th > max_th) {
   5188         max_th = min_th;
   5189     }
   5190 
   5191     /* Convert threshold to number of cells */
   5192     max_th_cells = max_th / _BCM_ECMP_DLB_CELL_BYTES;
   5193     hw_limit = (1 << soc_mem_field_length(unit, DLB_ECMP_GLB_QUANTIZE_THRESHOLDm,
   5194                                            TOTAL_PORT_QSIZE_THRESHOLDf)) - 1;
   5195     if (max_th_cells > hw_limit) {
   5196         /* Hardware limits */
   5197         return BCM_E_PARAM;
   5198     }
   5199 
   5200     /* Use min threshold as threshold 0, and max threshold as threshold 6.
   5201      * Thresholds 1 to 5 will be evenly spread out between min and max
   5202      * thresholds.
   5203      */
   5204     th_increment = (max_th - min_th) / 6;
   5205     for (i = 0; i < 7; i++) {
   5206         BCM_IF_ERROR_RETURN
   5207             (READ_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm(unit, MEM_BLOCK_ANY, i,
   5208                                               &quantize_threshold_entry));
   5209         th_cells[i] = (min_th + i * th_increment) / _BCM_ECMP_DLB_CELL_BYTES;
   5210         soc_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm_field32_set
   5211             (unit, &quantize_threshold_entry, TOTAL_PORT_QSIZE_THRESHOLDf,
   5212              th_cells[i]);
   5213         BCM_IF_ERROR_RETURN
   5214             (WRITE_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm(unit, MEM_BLOCK_ALL, i,
   5215                                                &quantize_threshold_entry));
   5216     }
   5217 
   5218     ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th = min_th;
   5219     ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th = max_th;
   5220 
   5221     return BCM_E_NONE;
   5222 }
   5223 
   5224 /*
   5225  * Function:
   5226  *      _bcm_th2_ecmp_dlb_qsize_min_th_set
   5227  * Purpose:
   5228  *      Set ECMP DLB queue size minimum threshold.
   5229  * Parameters:
   5230  *      unit    - (IN) SOC unit number.
   5231  *      min_th  - (IN) Minimum queue size threshold, in bytes.
   5232  * Returns:
   5233  *      BCM_E_xxx
   5234  */
   5235 STATIC int
   5236 _bcm_th2_ecmp_dlb_qsize_min_th_set(int unit, int min_th)
   5237 {
   5238     BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_qsize_thresholds_set(unit,
   5239                 min_th, ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th));
   5240 
   5241     return BCM_E_NONE;
   5242 }
   5243 
   5244 /*
   5245  * Function:
   5246  *      _bcm_th2_ecmp_dlb_qsize_max_th_set
   5247  * Purpose:
   5248  *      Set ECMP DLB queue size maximum threshold.
   5249  * Parameters:
   5250  *      unit    - (IN) SOC unit number.
   5251  *      max_th  - (IN) Maximum queue size threshold, in bytes.
   5252  * Returns:
   5253  *      BCM_E_xxx
   5254  */
   5255 STATIC int
   5256 _bcm_th2_ecmp_dlb_qsize_max_th_set(int unit, int max_th)
   5257 {
   5258     BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_qsize_thresholds_set(unit,
   5259                 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th, max_th));
   5260 
   5261     return BCM_E_NONE;
   5262 }
   5263 
   5264 
   5265 /*
   5266  * Function:
   5267  *      _bcm_th2_ecmp_dlb_physical_qsize_thresholds_set
   5268  * Purpose:
   5269  *      Set ECMP DLB physical queue size thresholds.
   5270  * Parameters:
   5271  *      unit    - (IN) SOC unit number.
   5272  *      min_th  - (IN) Minimum physical queue size threshold, in bytes.
   5273  *      max_th  - (IN) Maximum physical queue size threshold, in bytes.
   5274  * Returns:
   5275  *      BCM_E_xxx
   5276  */
   5277 STATIC int
   5278 _bcm_th2_ecmp_dlb_physical_qsize_thresholds_set(int unit, int min_th, int max_th)
   5279 {
   5280     int max_th_cells;
   5281     int th_increment;
   5282     dlb_ecmp_glb_quantize_threshold_entry_t quantize_threshold_entry;
   5283     int i;
   5284     int th_cells[7];
   5285     uint32 hw_limit;
   5286     soc_field_t qth_field = XPE_PORT_QSIZE_THRESHOLDf;
   5287     if (min_th < 0 || max_th < 0) {
   5288         return BCM_E_PARAM;
   5289     }
   5290 
   5291     if (soc_feature(unit, soc_feature_th3_style_dlb)) {
   5292         qth_field = ITM_PORT_QSIZE_THRESHOLDf;
   5293     }
   5294 
   5295     if (min_th > max_th) {
   5296         max_th = min_th;
   5297     }
   5298 
   5299     /* Convert threshold to number of cells */
   5300     max_th_cells = max_th / _BCM_ECMP_DLB_CELL_BYTES;
   5301     hw_limit = (1 << soc_mem_field_length(unit, DLB_ECMP_GLB_QUANTIZE_THRESHOLDm,
   5302                                            qth_field)) - 1;
   5303     if (max_th_cells > hw_limit) {
   5304         /* Hardware limits */
   5305         return BCM_E_PARAM;
   5306     }
   5307 
   5308     /* Use min threshold as threshold 0, and max threshold as threshold 6.
   5309      * Thresholds 1 to 5 will be evenly spread out between min and max
   5310      * thresholds.
   5311      */
   5312     th_increment = (max_th - min_th) / 6;
   5313     for (i = 0; i < 7; i++) {
   5314         BCM_IF_ERROR_RETURN
   5315             (READ_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm(unit, MEM_BLOCK_ANY, i,
   5316                                               &quantize_threshold_entry));
   5317         th_cells[i] = (min_th + i * th_increment) / _BCM_ECMP_DLB_CELL_BYTES;
   5318         soc_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm_field32_set
   5319             (unit, &quantize_threshold_entry, qth_field,
   5320              th_cells[i]);
   5321         BCM_IF_ERROR_RETURN
   5322             (WRITE_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm(unit, MEM_BLOCK_ALL, i,
   5323                                                &quantize_threshold_entry));
   5324     }
   5325 
   5326     ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_min_th = min_th;
   5327     ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_max_th = max_th;
   5328 
   5329     return BCM_E_NONE;
   5330 }
   5331 
   5332 
   5333 
   5334 /*
   5335  * Function:
   5336  *      _bcm_th2_ecmp_dlb_physical_qsize_min_th_set
   5337  * Purpose:
   5338  *      Set ECMP DLB physical queue size minimum threshold.
   5339  * Parameters:
   5340  *      unit    - (IN) SOC unit number.
   5341  *      min_th  - (IN) Minimum physical queue size threshold, in bytes.
   5342  * Returns:
   5343  *      BCM_E_xxx
   5344  */
   5345 STATIC int
   5346 _bcm_th2_ecmp_dlb_physical_qsize_min_th_set(int unit, int min_th)
   5347 {
   5348     BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_physical_qsize_thresholds_set(unit,
   5349                 min_th, ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_max_th));
   5350 
   5351     return BCM_E_NONE;
   5352 }
   5353 
   5354 /*
   5355  * Function:
   5356  *      _bcm_th2_ecmp_dlb_physical_qsize_max_th_set
   5357  * Purpose:
   5358  *      Set ECMP DLB physical queue size maximum threshold.
   5359  * Parameters:
   5360  *      unit    - (IN) SOC unit number.
   5361  *      max_th  - (IN) Maximum physical queue size threshold, in bytes.
   5362  * Returns:
   5363  *      BCM_E_xxx
   5364  */
   5365 STATIC int
   5366 _bcm_th2_ecmp_dlb_physical_qsize_max_th_set(int unit, int max_th)
   5367 {
   5368     BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_physical_qsize_thresholds_set(unit,
   5369                 ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_min_th, max_th));
   5370 
   5371     return BCM_E_NONE;
   5372 }
   5373 
   5374 
   5375 /*
   5376  * Function:
   5377  *      _bcm_th2_ecmp_dlb_tx_load_weight_set
   5378  * Purpose:
   5379  *      Set ECMP DLB port load weight.
   5380  * Parameters:
   5381  *      unit    - (IN) SOC unit number.
   5382  *      weight  - (IN) Port load weight.
   5383  * Returns:
   5384  *      BCM_E_xxx
   5385  */
   5386 STATIC int
   5387 _bcm_th2_ecmp_dlb_tx_load_weight_set(int unit, int weight)
   5388 {
   5389     uint32 measure_control_reg;
   5390     uint32 hw_limit;
   5391 
   5392     hw_limit = (1 << soc_reg_field_length(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   5393                                           PORT_LOADING_WEIGHTf)) - 1;
   5394     if (weight < 0 ||
   5395         weight > hw_limit) {
   5396         /* Hardware limits */
   5397         return BCM_E_PARAM;
   5398     }
   5399 
   5400     BCM_IF_ERROR_RETURN
   5401         (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   5402     soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   5403         &measure_control_reg, PORT_LOADING_WEIGHTf, weight);
   5404     BCM_IF_ERROR_RETURN
   5405         (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg));
   5406     return BCM_E_NONE;
   5407 }
   5408 
   5409 /*
   5410  * Function:
   5411  *      _bcm_th2_ecmp_dlb_tx_load_weight_get
   5412  * Purpose:
   5413  *      Get ECMP DLB port load weight.
   5414  * Parameters:
   5415  *      unit    - (IN) SOC unit number.
   5416  *      weight  - (OUT) Port load weight.
   5417  * Returns:
   5418  *      BCM_E_xxx
   5419  */
   5420 STATIC int
   5421 _bcm_th2_ecmp_dlb_tx_load_weight_get(int unit, int *weight)
   5422 {
   5423     uint32 measure_control_reg;
   5424 
   5425     BCM_IF_ERROR_RETURN
   5426         (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   5427     *weight = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   5428         measure_control_reg, PORT_LOADING_WEIGHTf);
   5429 
   5430     return BCM_E_NONE;
   5431 }
   5432 
   5433 /*
   5434  * Function:
   5435  *      _bcm_th2_ecmp_dlb_qsize_weight_set
   5436  * Purpose:
   5437  *      Set ECMP DLB qsize weight.
   5438  * Parameters:
   5439  *      unit    - (IN) SOC unit number.
   5440  *      weight  - (IN) Qsize weight.
   5441  * Returns:
   5442  *      BCM_E_xxx
   5443  */
   5444 STATIC int
   5445 _bcm_th2_ecmp_dlb_qsize_weight_set(int unit, int weight)
   5446 {
   5447     uint32 measure_control_reg;
   5448     uint32 hw_limit;
   5449 
   5450     hw_limit = (1 << soc_reg_field_length(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   5451                                            TOTAL_QSIZE_WEIGHTf)) - 1;
   5452     if (weight < 0 ||
   5453         weight > hw_limit) {
   5454         /* Hardware limits */
   5455         return BCM_E_PARAM;
   5456     }
   5457 
   5458     BCM_IF_ERROR_RETURN
   5459         (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   5460     soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   5461         &measure_control_reg, TOTAL_QSIZE_WEIGHTf, weight);
   5462     BCM_IF_ERROR_RETURN
   5463         (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg));
   5464     return BCM_E_NONE;
   5465 }
   5466 
   5467 /*
   5468  * Function:
   5469  *      _bcm_th2_ecmp_dlb_qsize_weight_get
   5470  * Purpose:
   5471  *      Get ECMP DLB qsize weight.
   5472  * Parameters:
   5473  *      unit    - (IN) SOC unit number.
   5474  *      weight  - (OUT) Qsize weight.
   5475  * Returns:
   5476  *      BCM_E_xxx
   5477  */
   5478 STATIC int
   5479 _bcm_th2_ecmp_dlb_qsize_weight_get(int unit, int *weight)
   5480 {
   5481     uint32 measure_control_reg;
   5482 
   5483     BCM_IF_ERROR_RETURN
   5484         (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   5485     *weight = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   5486         measure_control_reg, TOTAL_QSIZE_WEIGHTf);
   5487 
   5488     return BCM_E_NONE;
   5489 }
   5490 
   5491 /*
   5492  * Function:
   5493  *      _bcm_th2_ecmp_dlb_physical_qsize_weight_set
   5494  * Purpose:
   5495  *      Set ECMP DLB physical qsize weight.
   5496  * Parameters:
   5497  *      unit    - (IN) SOC unit number.
   5498  *      weight  - (IN) Physical Queue size weight.
   5499  * Returns:
   5500  *      BCM_E_xxx
   5501  */
   5502 STATIC int
   5503 _bcm_th2_ecmp_dlb_physical_qsize_weight_set(int unit, int weight)
   5504 {
   5505     uint32 measure_control_reg;
   5506     soc_field_t qweight_field  = XPE_PORT_QSIZE_WEIGHTf;
   5507     uint32 hw_limit;
   5508 
   5509     if (soc_feature(unit, soc_feature_th3_style_dlb)) {
   5510         qweight_field = ITM_PORT_QSIZE_WEIGHTf;
   5511     }
   5512     hw_limit = (1 << soc_reg_field_length(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   5513                                            qweight_field)) - 1;
   5514     if (weight < 0 ||
   5515         weight > hw_limit) {
   5516         /* Hardware limits */
   5517         return BCM_E_PARAM;
   5518     }
   5519 
   5520     BCM_IF_ERROR_RETURN
   5521         (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   5522     soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   5523         &measure_control_reg, qweight_field, weight);
   5524     BCM_IF_ERROR_RETURN
   5525         (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg));
   5526     return BCM_E_NONE;
   5527 }
   5528 
   5529 /*
   5530  * Function:
   5531  *      _bcm_th2_ecmp_dlb_physical_qsize_weight_get
   5532  * Purpose:
   5533  *      Get ECMP DLB physical qsize weight.
   5534  * Parameters:
   5535  *      unit    - (IN) SOC unit number.
   5536  *      weight  - (OUT) Physical Queue size weight.
   5537  * Returns:
   5538  *      BCM_E_xxx
   5539  */
   5540 STATIC int
   5541 _bcm_th2_ecmp_dlb_physical_qsize_weight_get(int unit, int *weight)
   5542 {
   5543     uint32 measure_control_reg;
   5544 
   5545     BCM_IF_ERROR_RETURN
   5546         (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   5547 #if defined(BCM_TOMAHAWK3_SUPPORT)
   5548     if (soc_feature(unit, soc_feature_th3_style_dlb)) {
   5549         *weight = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   5550             measure_control_reg, ITM_PORT_QSIZE_WEIGHTf);
   5551     } else
   5552 #endif
   5553     {
   5554         *weight = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   5555             measure_control_reg, XPE_PORT_QSIZE_WEIGHTf);
   5556     }
   5557 
   5558     return BCM_E_NONE;
   5559 }
   5560 
   5561 /*
   5562  * Function:
   5563  *      _bcm_th2_ecmp_dlb_tx_load_cap_set
   5564  * Purpose:
   5565  *      Set ECMP DLB port load cap control.
   5566  * Parameters:
   5567  *      unit    - (IN) SOC unit number.
   5568  *      cap     - (IN) Port load cap control.
   5569  * Returns:
   5570  *      BCM_E_xxx
   5571  */
   5572 STATIC int
   5573 _bcm_th2_ecmp_dlb_tx_load_cap_set(int unit, int cap)
   5574 {
   5575     uint32 measure_control_reg;
   5576 
   5577     if (cap < 0 ||
   5578         cap > 1) {
   5579         /* Hardware limits port load cap control to 1 bit */
   5580         return BCM_E_PARAM;
   5581     }
   5582 
   5583     BCM_IF_ERROR_RETURN
   5584         (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   5585     soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   5586         &measure_control_reg, CAP_PORT_LOADING_AVERAGEf, cap);
   5587     BCM_IF_ERROR_RETURN
   5588         (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg));
   5589     return BCM_E_NONE;
   5590 }
   5591 
   5592 /*
   5593  * Function:
   5594  *      _bcm_th2_ecmp_dlb_tx_load_cap_get
   5595  * Purpose:
   5596  *      Get ECMP DLB port load cap control.
   5597  * Parameters:
   5598  *      unit    - (IN) SOC unit number.
   5599  *      cap     - (OUT) Cap control.
   5600  * Returns:
   5601  *      BCM_E_xxx
   5602  */
   5603 STATIC int
   5604 _bcm_th2_ecmp_dlb_tx_load_cap_get(int unit, int *cap)
   5605 {
   5606     uint32 measure_control_reg;
   5607 
   5608     BCM_IF_ERROR_RETURN
   5609         (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   5610     *cap = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   5611         measure_control_reg, CAP_PORT_LOADING_AVERAGEf);
   5612 
   5613     return BCM_E_NONE;
   5614 }
   5615 /*
   5616  * Function:
   5617  *      _bcm_th2_ecmp_dlb_qsize_cap_set
   5618  * Purpose:
   5619  *      Set ECMP DLB queue size cap control.
   5620  * Parameters:
   5621  *      unit    - (IN) SOC unit number.
   5622  *      cap     - (IN) Queue size cap control.
   5623  * Returns:
   5624  *      BCM_E_xxx
   5625  */
   5626 STATIC int
   5627 _bcm_th2_ecmp_dlb_qsize_cap_set(int unit, int cap)
   5628 {
   5629     uint32 measure_control_reg;
   5630 
   5631     if (cap < 0 ||
   5632         cap > 1) {
   5633         /* Hardware limits port load cap control to 1 bit */
   5634         return BCM_E_PARAM;
   5635     }
   5636 
   5637     BCM_IF_ERROR_RETURN
   5638         (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   5639     soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   5640         &measure_control_reg, CAP_TOTAL_PORT_QSIZE_AVERAGEf, cap);
   5641     BCM_IF_ERROR_RETURN
   5642         (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg));
   5643     return BCM_E_NONE;
   5644 }
   5645 
   5646 /*
   5647  * Function:
   5648  *      _bcm_th2_ecmp_dlb_qsize_cap_get
   5649  * Purpose:
   5650  *      Get ECMP DLB queue size cap control.
   5651  * Parameters:
   5652  *      unit    - (IN) SOC unit number.
   5653  *      cap     - (OUT) Cap control.
   5654  * Returns:
   5655  *      BCM_E_xxx
   5656  */
   5657 STATIC int
   5658 _bcm_th2_ecmp_dlb_qsize_cap_get(int unit, int *cap)
   5659 {
   5660     uint32 measure_control_reg;
   5661 
   5662     BCM_IF_ERROR_RETURN
   5663         (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   5664     *cap = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   5665         measure_control_reg, CAP_TOTAL_PORT_QSIZE_AVERAGEf);
   5666 
   5667     return BCM_E_NONE;
   5668 }
   5669 
   5670 /*
   5671  * Function:
   5672  *      _bcm_th2_ecmp_dlb_physical_qsize_cap_set
   5673  * Purpose:
   5674  *      Set ECMP DLB physical queue size cap control.
   5675  * Parameters:
   5676  *      unit    - (IN) SOC unit number.
   5677  *      cap     - (IN) Physical Queue size cap control.
   5678  * Returns:
   5679  *      BCM_E_xxx
   5680  */
   5681 STATIC int
   5682 _bcm_th2_ecmp_dlb_physical_qsize_cap_set(int unit, int cap)
   5683 {
   5684     uint32 measure_control_reg;
   5685     soc_field_t qsizeavg_field  = CAP_XPE_PORT_QSIZE_AVERAGEf;
   5686 
   5687     if (cap < 0 ||
   5688         cap > 1) {
   5689         /* Hardware limits port load cap control to 1 bit */
   5690         return BCM_E_PARAM;
   5691     }
   5692 
   5693 #if defined(BCM_TOMAHAWK3_SUPPORT)
   5694     if (soc_feature(unit, soc_feature_th3_style_dlb)) {
   5695         qsizeavg_field = CAP_ITM_PORT_QSIZE_AVERAGEf;
   5696     }
   5697 #endif
   5698 
   5699     BCM_IF_ERROR_RETURN
   5700         (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   5701     soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   5702         &measure_control_reg, qsizeavg_field, cap);
   5703     BCM_IF_ERROR_RETURN
   5704         (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg));
   5705     return BCM_E_NONE;
   5706 }
   5707 
   5708 /*
   5709  * Function:
   5710  *      _bcm_th2_ecmp_dlb_physical_qsize_cap_get
   5711  * Purpose:
   5712  *      Get ECMP DLB physical queue size cap control.
   5713  * Parameters:
   5714  *      unit    - (IN) SOC unit number.
   5715  *      cap     - (OUT) Physical Queue size cap control.
   5716  * Returns:
   5717  *      BCM_E_xxx
   5718  */
   5719 STATIC int
   5720 _bcm_th2_ecmp_dlb_physical_qsize_cap_get(int unit, int *cap)
   5721 {
   5722     uint32 measure_control_reg;
   5723 
   5724     BCM_IF_ERROR_RETURN
   5725         (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   5726 #if defined(BCM_TOMAHAWK3_SUPPORT)
   5727     if (soc_feature(unit, soc_feature_th3_style_dlb)) {
   5728         *cap = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   5729             measure_control_reg, CAP_ITM_PORT_QSIZE_AVERAGEf);
   5730     } else
   5731 #endif
   5732     {
   5733         *cap = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   5734             measure_control_reg, CAP_XPE_PORT_QSIZE_AVERAGEf);
   5735     }
   5736 
   5737     return BCM_E_NONE;
   5738 }
   5739 
   5740 
   5741 /*
   5742  * Function:
   5743  *      _bcm_th2_ecmp_dlb_config_set
   5744  * Purpose:
   5745  *      Set per-chip ECMP dynamic load balancing configuration parameters.
   5746  * Parameters:
   5747  *      unit - (IN) SOC unit number.
   5748  *      type - (IN) Configuration parameter type.
   5749  *      arg  - (IN) Configuration paramter value.
   5750  * Returns:
   5751  *      BCM_E_xxx
   5752  */
   5753 int
   5754 _bcm_th2_ecmp_dlb_config_set(int unit, bcm_switch_control_t type, int arg)
   5755 {
   5756     switch (type) {
   5757         case bcmSwitchEcmpDynamicSampleRate:
   5758             return _bcm_th2_ecmp_dlb_sample_rate_set(unit, arg);
   5759 
   5760         case bcmSwitchEcmpDynamicEgressBytesExponent:
   5761             return _bcm_th2_ecmp_dlb_tx_load_weight_set(unit, arg);
   5762 
   5763         case bcmSwitchEcmpDynamicQueuedBytesExponent:
   5764             if (soc_feature(unit, soc_feature_td3_dlb)) {
   5765                 return BCM_E_UNAVAIL;
   5766             } else {
   5767                 return _bcm_th2_ecmp_dlb_qsize_weight_set(unit, arg);
   5768             }
   5769         case bcmSwitchEcmpDynamicPhysicalQueuedBytesExponent:
   5770             return _bcm_th2_ecmp_dlb_physical_qsize_weight_set(unit, arg);
   5771 
   5772         case bcmSwitchEcmpDynamicEgressBytesDecreaseReset:
   5773             return _bcm_th2_ecmp_dlb_tx_load_cap_set(unit, arg);
   5774 
   5775         case bcmSwitchEcmpDynamicQueuedBytesDecreaseReset:
   5776             if (soc_feature(unit, soc_feature_td3_dlb)) {
   5777                 return BCM_E_UNAVAIL;
   5778             } else {
   5779                 return _bcm_th2_ecmp_dlb_qsize_cap_set(unit, arg);
   5780             }
   5781         case bcmSwitchEcmpDynamicPhysicalQueuedBytesDecreaseReset:
   5782             return _bcm_th2_ecmp_dlb_physical_qsize_cap_set(unit, arg);
   5783 
   5784         case bcmSwitchEcmpDynamicEgressBytesMinThreshold:
   5785             return _bcm_th2_ecmp_dlb_tx_load_min_th_set(unit, arg);
   5786 
   5787         case bcmSwitchEcmpDynamicEgressBytesMaxThreshold:
   5788             return _bcm_th2_ecmp_dlb_tx_load_max_th_set(unit, arg);
   5789 
   5790         case bcmSwitchEcmpDynamicQueuedBytesMinThreshold:
   5791             if (soc_feature(unit, soc_feature_td3_dlb)) {
   5792                 return BCM_E_UNAVAIL;
   5793             } else {
   5794                 return _bcm_th2_ecmp_dlb_qsize_min_th_set(unit, arg);
   5795             }
   5796         case bcmSwitchEcmpDynamicQueuedBytesMaxThreshold:
   5797             if (soc_feature(unit, soc_feature_td3_dlb)) {
   5798                 return BCM_E_UNAVAIL;
   5799             } else {
   5800                 return _bcm_th2_ecmp_dlb_qsize_max_th_set(unit, arg);
   5801             }
   5802         case bcmSwitchEcmpDynamicPhysicalQueuedBytesMinThreshold:
   5803             return _bcm_th2_ecmp_dlb_physical_qsize_min_th_set(unit, arg);
   5804 
   5805         case bcmSwitchEcmpDynamicPhysicalQueuedBytesMaxThreshold:
   5806             return _bcm_th2_ecmp_dlb_physical_qsize_max_th_set(unit, arg);
   5807 
   5808         case bcmSwitchEcmpDynamicRandomSeed:
   5809             return _bcm_th2_ecmp_dlb_random_seed_set(unit, arg);
   5810 
   5811         default:
   5812             return BCM_E_PARAM;
   5813     }
   5814 }
   5815 
   5816 /*
   5817  * Function:
   5818  *      _bcm_th2_ecmp_dlb_config_get
   5819  * Purpose:
   5820  *      Get per-chip ECMP dynamic load balancing configuration parameters.
   5821  * Parameters:
   5822  *      unit - (IN) SOC unit number.
   5823  *      type - (IN) Configuration parameter type.
   5824  *      arg  - (OUT) Configuration paramter value.
   5825  * Returns:
   5826  *      BCM_E_xxx
   5827  */
   5828 int
   5829 _bcm_th2_ecmp_dlb_config_get(int unit, bcm_switch_control_t type, int *arg)
   5830 {
   5831     switch (type) {
   5832         case bcmSwitchEcmpDynamicSampleRate:
   5833             *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate;
   5834             break;
   5835 
   5836         case bcmSwitchEcmpDynamicEgressBytesExponent:
   5837             return _bcm_th2_ecmp_dlb_tx_load_weight_get(unit, arg);
   5838 
   5839         case bcmSwitchEcmpDynamicQueuedBytesExponent:
   5840             if (soc_feature(unit, soc_feature_td3_dlb)) {
   5841                 return BCM_E_UNAVAIL;
   5842             } else {
   5843                 return _bcm_th2_ecmp_dlb_qsize_weight_get(unit, arg);
   5844             }
   5845         case bcmSwitchEcmpDynamicPhysicalQueuedBytesExponent:
   5846             return _bcm_th2_ecmp_dlb_physical_qsize_weight_get(unit, arg);
   5847 
   5848         case bcmSwitchEcmpDynamicEgressBytesDecreaseReset:
   5849             return _bcm_th2_ecmp_dlb_tx_load_cap_get(unit, arg);
   5850 
   5851         case bcmSwitchEcmpDynamicQueuedBytesDecreaseReset:
   5852             if (soc_feature(unit, soc_feature_td3_dlb)) {
   5853                 return BCM_E_UNAVAIL;
   5854             } else {
   5855                 return _bcm_th2_ecmp_dlb_qsize_cap_get(unit, arg);
   5856             }
   5857         case bcmSwitchEcmpDynamicPhysicalQueuedBytesDecreaseReset:
   5858             return _bcm_th2_ecmp_dlb_physical_qsize_cap_get(unit, arg);
   5859 
   5860         case bcmSwitchEcmpDynamicEgressBytesMinThreshold:
   5861             *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th;
   5862             break;
   5863 
   5864         case bcmSwitchEcmpDynamicEgressBytesMaxThreshold:
   5865             *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th;
   5866             break;
   5867 
   5868         case bcmSwitchEcmpDynamicQueuedBytesMinThreshold:
   5869             if (soc_feature(unit, soc_feature_td3_dlb)) {
   5870                 return BCM_E_UNAVAIL;
   5871             } else {
   5872                 *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th;
   5873                 break;
   5874             }
   5875 
   5876         case bcmSwitchEcmpDynamicQueuedBytesMaxThreshold:
   5877             if (soc_feature(unit, soc_feature_td3_dlb)) {
   5878                 return BCM_E_UNAVAIL;
   5879             } else {
   5880                 *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th;
   5881                 break;
   5882             }
   5883 
   5884         case bcmSwitchEcmpDynamicPhysicalQueuedBytesMinThreshold:
   5885             *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_min_th;
   5886             break;
   5887 
   5888         case bcmSwitchEcmpDynamicPhysicalQueuedBytesMaxThreshold:
   5889             *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_max_th;
   5890             break;
   5891 
   5892         case bcmSwitchEcmpDynamicRandomSeed:
   5893             return _bcm_th2_ecmp_dlb_random_seed_get(unit, arg);
   5894 
   5895         default:
   5896             return BCM_E_PARAM;
   5897     }
   5898 
   5899     return BCM_E_NONE;
   5900 }
   5901 
   5902 /*
   5903  * Function:
   5904  *      _bcm_th2_ecmp_dlb_quality_map_profile_init
   5905  * Purpose:
   5906  *      Initialize ECMP DLB quality mapping profile.
   5907  * Parameters:
   5908  *      unit - (IN)SOC unit number.
   5909  * Returns:
   5910  *      BCM_X_XXX
   5911  */
   5912 STATIC int
   5913 _bcm_th2_ecmp_dlb_quality_map_profile_init(int unit)
   5914 {
   5915     soc_profile_mem_t *profile;
   5916     soc_mem_t mem;
   5917     int entry_words;
   5918     int entries_per_profile;
   5919     int tx_load_percent;
   5920     int qsize_percent;
   5921     int alloc_size;
   5922     uint32 *entry_arr;
   5923     int rv = BCM_E_NONE;
   5924     void *entries;
   5925     uint32 base_index;
   5926     int i;
   5927     int port;
   5928     dlb_ecmp_quantize_control_entry_t quantize_control_entry;
   5929     int num_quality_map_profiles;
   5930     int field_len;
   5931     void *mask_p[1];
   5932     uint32 ent[1] = {0};
   5933 
   5934     if (NULL == _th2_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile) {
   5935         _th2_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile =
   5936             sal_alloc(sizeof(soc_profile_mem_t),
   5937                       "ECMP DLB Quality Map Profile Mem");
   5938         if (NULL == _th2_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile) {
   5939             return BCM_E_MEMORY;
   5940         }
   5941     } else {
   5942         soc_profile_mem_destroy(unit,
   5943                 _th2_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile);
   5944     }
   5945     profile = _th2_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile;
   5946     soc_profile_mem_t_init(profile);
   5947 
   5948     mem = DLB_ECMP_PORT_QUALITY_MAPPINGm;
   5949     entry_words = sizeof(dlb_ecmp_quality_mapping_entry_t) / sizeof(uint32);
   5950 
   5951     /* Get quality mask */
   5952     field_len = soc_mem_field_length(unit, mem, ASSIGNED_QUALITYf);
   5953     soc_mem_field32_set(unit, mem, ent,
   5954                         ASSIGNED_QUALITYf, (1 << field_len) - 1);
   5955     mask_p[0] = ent;
   5956     BCM_IF_ERROR_RETURN
   5957         (soc_profile_mem_index_create(unit, &mem, &entry_words,
   5958                                       NULL, NULL, mask_p, 1, profile));
   5959 
   5960     num_quality_map_profiles = 1 << soc_mem_field_length(unit,
   5961             DLB_ECMP_QUANTIZE_CONTROLm, PORT_QUALITY_MAPPING_PROFILE_PTRf);
   5962     entries_per_profile =
   5963         soc_mem_index_count(unit, DLB_ECMP_PORT_QUALITY_MAPPINGm) /
   5964         num_quality_map_profiles;
   5965 
   5966     if (!SOC_WARM_BOOT(unit)) {
   5967         alloc_size = entries_per_profile * entry_words * sizeof(uint32);
   5968         entry_arr = sal_alloc(alloc_size, "ECMP DLB Quality Map entries");
   5969         if (entry_arr == NULL) {
   5970             return BCM_E_MEMORY;
   5971         }
   5972         sal_memset(entry_arr, 0, alloc_size);
   5973 
   5974         /* Assign quality in the entry array, with 100% weight for port load,
   5975          * 0% for queue size.
   5976          */
   5977         tx_load_percent = 100;
   5978         qsize_percent   = 0;
   5979         rv = _bcm_th2_ecmp_dlb_quality_assign(unit, tx_load_percent,
   5980                 qsize_percent, entry_arr);
   5981         if (BCM_FAILURE(rv)) {
   5982             sal_free(entry_arr);
   5983             return rv;
   5984         }
   5985 
   5986         entries = entry_arr;
   5987         rv = soc_profile_mem_add(unit, profile, &entries, entries_per_profile,
   5988                                  &base_index);
   5989         sal_free(entry_arr);
   5990         if (BCM_FAILURE(rv)) {
   5991             return rv;
   5992         }
   5993 
   5994         for (port = 0;
   5995              port < soc_mem_index_count(unit, DLB_ECMP_QUANTIZE_CONTROLm);
   5996              port++) {
   5997             BCM_IF_ERROR_RETURN
   5998                 (READ_DLB_ECMP_QUANTIZE_CONTROLm(unit, MEM_BLOCK_ANY,
   5999                                                  port,
   6000                                                  &quantize_control_entry));
   6001             soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_set(unit,
   6002                     &quantize_control_entry, PORT_QUALITY_MAPPING_PROFILE_PTRf,
   6003                     base_index / entries_per_profile);
   6004             BCM_IF_ERROR_RETURN
   6005                 (WRITE_DLB_ECMP_QUANTIZE_CONTROLm(unit, MEM_BLOCK_ALL,
   6006                                                   port,
   6007                                                   &quantize_control_entry));
   6008         }
   6009 
   6010         for (i = 0; i < entries_per_profile; i++) {
   6011             SOC_PROFILE_MEM_REFERENCE(unit, profile, base_index + i,
   6012                                       port - 1);
   6013         }
   6014 
   6015         ECMP_DLB_INFO(unit)->
   6016             ecmp_dlb_load_weight[base_index/entries_per_profile] =
   6017                 tx_load_percent;
   6018         ECMP_DLB_INFO(unit)->
   6019             ecmp_dlb_qsize_weight[base_index/entries_per_profile] =
   6020                 qsize_percent;
   6021 
   6022     } else { /* Warm boot, recover reference counts and entries_per_set */
   6023 
   6024         for (port = 0;
   6025              port < soc_mem_index_count(unit, DLB_ECMP_QUANTIZE_CONTROLm);
   6026              port++) {
   6027             BCM_IF_ERROR_RETURN
   6028                 (READ_DLB_ECMP_QUANTIZE_CONTROLm(unit, MEM_BLOCK_ANY,
   6029                                                  port,
   6030                                                  &quantize_control_entry));
   6031             base_index = soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_get(unit,
   6032                     &quantize_control_entry, PORT_QUALITY_MAPPING_PROFILE_PTRf);
   6033             base_index *= entries_per_profile;
   6034             for (i = 0; i < entries_per_profile; i++) {
   6035                 SOC_PROFILE_MEM_REFERENCE(unit, profile, base_index + i, 1);
   6036                 SOC_PROFILE_MEM_ENTRIES_PER_SET(unit, profile,
   6037                         base_index + i, entries_per_profile);
   6038             }
   6039         }
   6040     }
   6041 
   6042     return BCM_E_NONE;
   6043 }
   6044 
   6045 
   6046 /*
   6047  * Function:
   6048  *      _bcm_th2_ecmp_dlb_deinit
   6049  * Purpose:
   6050  *      Deallocate _th2_ecmp_dlb_bk
   6051  * Parameters:
   6052  *      unit - (IN)SOC unit number.
   6053  * Returns:
   6054  *      None
   6055  */
   6056 void
   6057 _bcm_th2_ecmp_dlb_deinit(int unit)
   6058 {
   6059     if (_th2_ecmp_dlb_bk[unit]) {
   6060         if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_port_info) {
   6061             sal_free(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_port_info);
   6062             _th2_ecmp_dlb_bk[unit]->ecmp_dlb_port_info = NULL;
   6063         }
   6064         if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap) {
   6065             sal_free(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap);
   6066             _th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap = NULL;
   6067         }
   6068         if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_dgm_bitmap) {
   6069             sal_free(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_dgm_bitmap);
   6070             _th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_dgm_bitmap = NULL;
   6071         }
   6072         if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap) {
   6073             sal_free(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap);
   6074             _th2_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap = NULL;
   6075         }
   6076         if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight) {
   6077             sal_free(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight);
   6078             _th2_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight = NULL;
   6079         }
   6080         if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_qsize_weight) {
   6081             sal_free(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_qsize_weight);
   6082             _th2_ecmp_dlb_bk[unit]->ecmp_dlb_qsize_weight = NULL;
   6083         }
   6084         if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile) {
   6085             soc_profile_mem_destroy(unit,
   6086                     _th2_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile);
   6087             sal_free(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile);
   6088             _th2_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile = NULL;
   6089         }
   6090 
   6091         sal_free(_th2_ecmp_dlb_bk[unit]);
   6092         _th2_ecmp_dlb_bk[unit] = NULL;
   6093     }
   6094 
   6095 }
   6096 
   6097 /*
   6098  * Function:
   6099  *      _bcm_th2_ecmp_dlb_init
   6100  * Purpose:
   6101  *      Allocate and initialize _th2_ecmp_dlb_bk
   6102  * Parameters:
   6103  *      unit - (IN)SOC unit number.
   6104  * Returns:
   6105  *      BCM_X_XXX
   6106  */
   6107 int
   6108 _bcm_th2_ecmp_dlb_init(int unit)
   6109 {
   6110     int rv = BCM_E_NONE;
   6111     int num_ecmp_dlb_id;
   6112     int flowset_tbl_size;
   6113     int total_num_blocks;
   6114     int num_quality_map_profiles;
   6115     int port;
   6116     dlb_ecmp_quantize_control_entry_t quantize_control_entry;
   6117     dlb_ecmp_port_quality_update_measure_control_entry_t measure_entry;
   6118     dlb_ecmp_eem_configuration_entry_t eem_entry;
   6119     int max_ecmp_dlb_ports;
   6120     int sample_rate;
   6121     int qsize_sel[4] = {1, 0, 0, 1};
   6122     soc_reg_t reg;
   6123     int pipe;
   6124     uint32 rval;
   6125 #ifdef BCM_TRIDENT3_SUPPORT
   6126     uint32 reg_val = 0;
   6127 #endif
   6128     soc_field_t qsf_field = XPE_PORT_QSIZE_THRESHOLD_SCALING_FACTORf;
   6129 
   6130     _bcm_th2_ecmp_dlb_deinit(unit);
   6131 
   6132     if (_th2_ecmp_dlb_bk[unit] == NULL) {
   6133         _th2_ecmp_dlb_bk[unit] = sal_alloc(
   6134                 sizeof(_th2_ecmp_dlb_bookkeeping_t), "_th2_ecmp_dlb_bk");
   6135         if (_th2_ecmp_dlb_bk[unit] == NULL) {
   6136             return BCM_E_MEMORY;
   6137         }
   6138     }
   6139     sal_memset(_th2_ecmp_dlb_bk[unit], 0, sizeof(_th2_ecmp_dlb_bookkeeping_t));
   6140 
   6141 #if defined(BCM_TOMAHAWK3_SUPPORT)
   6142     if (soc_feature(unit, soc_feature_th3_style_dlb)) {
   6143         qsf_field = ITM_PORT_QSIZE_THRESHOLD_SCALING_FACTORf;
   6144     }
   6145 #endif
   6146 
   6147     _th2_ecmp_dlb_bk[unit]->ecmp_dlb_property_force_set =
   6148         soc_feature(unit, soc_feature_ecmp_dlb_property_force_set);
   6149 
   6150     max_ecmp_dlb_ports = soc_mem_index_count(unit,
   6151             DLB_ECMP_QUANTIZE_CONTROLm);
   6152     if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_port_info == NULL) {
   6153         _th2_ecmp_dlb_bk[unit]->ecmp_dlb_port_info =
   6154             sal_alloc(sizeof(_th2_ecmp_dlb_port_info_t) * max_ecmp_dlb_ports,
   6155                     "ecmp_dlb_port_info");
   6156         if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_port_info == NULL) {
   6157             _bcm_th2_ecmp_dlb_deinit(unit);
   6158             return BCM_E_MEMORY;
   6159         }
   6160     }
   6161     sal_memset(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_port_info, 0,
   6162             sizeof(_th2_ecmp_dlb_port_info_t) * max_ecmp_dlb_ports);
   6163     _th2_ecmp_dlb_bk[unit]->ecmp_dlb_port_info_size = max_ecmp_dlb_ports;
   6164 
   6165 
   6166     num_ecmp_dlb_id = soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm);
   6167     if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap == NULL) {
   6168         _th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap =
   6169             sal_alloc(SHR_BITALLOCSIZE(num_ecmp_dlb_id),
   6170                     "ecmp_dlb_id_used_bitmap");
   6171         if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap == NULL) {
   6172             _bcm_th2_ecmp_dlb_deinit(unit);
   6173             return BCM_E_MEMORY;
   6174         }
   6175     }
   6176     sal_memset(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap, 0,
   6177             SHR_BITALLOCSIZE(num_ecmp_dlb_id));
   6178 
   6179     if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_dgm_bitmap == NULL) {
   6180         _th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_dgm_bitmap =
   6181             sal_alloc(SHR_BITALLOCSIZE(num_ecmp_dlb_id),
   6182                     "ecmp_dlb_id_dgm_bitmap");
   6183         if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_dgm_bitmap == NULL) {
   6184             _bcm_th2_ecmp_dlb_deinit(unit);
   6185             return BCM_E_MEMORY;
   6186         }
   6187     }
   6188     sal_memset(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_dgm_bitmap, 0,
   6189             SHR_BITALLOCSIZE(num_ecmp_dlb_id));
   6190 
   6191     flowset_tbl_size = soc_mem_index_count(unit, DLB_ECMP_FLOWSETm);
   6192     /* Each bit in ecmp_dlb_flowset_block_bitmap corresponds to a block of 256
   6193      * flow set table entries.
   6194      */
   6195     total_num_blocks = flowset_tbl_size >> _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT;
   6196     if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap == NULL) {
   6197         _th2_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap =
   6198             sal_alloc(SHR_BITALLOCSIZE(total_num_blocks),
   6199                     "ecmp_dlb_flowset_block_bitmap");
   6200         if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap == NULL) {
   6201             _bcm_th2_ecmp_dlb_deinit(unit);
   6202             return BCM_E_MEMORY;
   6203         }
   6204     }
   6205     sal_memset(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap, 0,
   6206             SHR_BITALLOCSIZE(total_num_blocks));
   6207 
   6208     num_quality_map_profiles = 1 << soc_mem_field_length(unit,
   6209             DLB_ECMP_QUANTIZE_CONTROLm, PORT_QUALITY_MAPPING_PROFILE_PTRf);
   6210     if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight == NULL) {
   6211         _th2_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight =
   6212             sal_alloc(num_quality_map_profiles * sizeof(uint8),
   6213                     "ecmp_dlb_load_weight");
   6214         if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight == NULL) {
   6215             _bcm_th2_ecmp_dlb_deinit(unit);
   6216             return BCM_E_MEMORY;
   6217         }
   6218     }
   6219     sal_memset(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight, 0,
   6220             num_quality_map_profiles * sizeof(uint8));
   6221 
   6222 
   6223     if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_qsize_weight == NULL) {
   6224         _th2_ecmp_dlb_bk[unit]->ecmp_dlb_qsize_weight =
   6225             sal_alloc(num_quality_map_profiles * sizeof(uint8),
   6226                     "ecmp_dlb_qsize_weight");
   6227         if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_qsize_weight == NULL) {
   6228             _bcm_th2_ecmp_dlb_deinit(unit);
   6229             return BCM_E_MEMORY;
   6230         }
   6231     }
   6232     sal_memset(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_qsize_weight, 0,
   6233             num_quality_map_profiles * sizeof(uint8));
   6234 
   6235 
   6236     /* Initialize port quality mapping profile */
   6237     rv = _bcm_th2_ecmp_dlb_quality_map_profile_init(unit);
   6238     if (BCM_FAILURE(rv)) {
   6239         _bcm_th2_ecmp_dlb_deinit(unit);
   6240         return rv;
   6241     }
   6242 
   6243     if (!SOC_WARM_BOOT(unit)) {
   6244 
   6245         /* Set DLB sampling period and thresholds */
   6246         sample_rate = 62500;
   6247         rv = _bcm_th2_ecmp_dlb_sample_rate_thresholds_set(unit, sample_rate,
   6248                                                           65536, (65536 * 7));
   6249         if (BCM_FAILURE(rv)) {
   6250             _bcm_th2_ecmp_dlb_deinit(unit);
   6251             return rv;
   6252         }
   6253 
   6254         /* Configure ECMP DLB load EWMA weight */
   6255         rv = _bcm_th2_ecmp_dlb_config_set(unit,
   6256                 bcmSwitchEcmpDynamicEgressBytesExponent, 0);
   6257         if (BCM_FAILURE(rv)) {
   6258             _bcm_th2_ecmp_dlb_deinit(unit);
   6259             return rv;
   6260         }
   6261 
   6262         /* Configure ECMP DLB queue size EWMA weight */
   6263         if (!soc_feature(unit, soc_feature_td3_dlb)) {
   6264             rv = _bcm_th2_ecmp_dlb_config_set(unit,
   6265                     bcmSwitchEcmpDynamicQueuedBytesExponent, 0);
   6266             if (BCM_FAILURE(rv)) {
   6267                 _bcm_th2_ecmp_dlb_deinit(unit);
   6268                 return rv;
   6269             }
   6270         }
   6271         /* Configure ECMP DLB physical queue size EWMA weight */
   6272         rv = _bcm_th2_ecmp_dlb_config_set(unit,
   6273                 bcmSwitchEcmpDynamicPhysicalQueuedBytesExponent, 0);
   6274         if (BCM_FAILURE(rv)) {
   6275             _bcm_th2_ecmp_dlb_deinit(unit);
   6276             return rv;
   6277         }
   6278 
   6279         /* Configure ECMP DLB load cap control */
   6280         rv = _bcm_th2_ecmp_dlb_config_set(unit,
   6281                 bcmSwitchEcmpDynamicEgressBytesDecreaseReset, 0);
   6282         if (BCM_FAILURE(rv)) {
   6283             _bcm_th2_ecmp_dlb_deinit(unit);
   6284             return rv;
   6285         }
   6286 
   6287         /* Configure ECMP DLB queue size cap control */
   6288         if (!soc_feature(unit, soc_feature_td3_dlb)) {
   6289             rv = _bcm_th2_ecmp_dlb_config_set(unit,
   6290                     bcmSwitchEcmpDynamicQueuedBytesDecreaseReset, 0);
   6291             if (BCM_FAILURE(rv)) {
   6292                 _bcm_th2_ecmp_dlb_deinit(unit);
   6293                 return rv;
   6294             }
   6295         }
   6296 
   6297         /* Configure ECMP DLB physical queue size cap control */
   6298         rv = _bcm_th2_ecmp_dlb_config_set(unit,
   6299                 bcmSwitchEcmpDynamicPhysicalQueuedBytesDecreaseReset, 0);
   6300         if (BCM_FAILURE(rv)) {
   6301             _bcm_th2_ecmp_dlb_deinit(unit);
   6302             return rv;
   6303         }
   6304 
   6305         /* Configure ECMP DLB queue size thresholds */
   6306         if (!soc_feature(unit, soc_feature_td3_dlb)) {
   6307             rv = _bcm_th2_ecmp_dlb_qsize_thresholds_set(unit, 0, 0);
   6308             if (BCM_FAILURE(rv)) {
   6309                 _bcm_th2_ecmp_dlb_deinit(unit);
   6310                 return rv;
   6311             }
   6312         }
   6313         /* Configure ECMP DLB physical queue size thresholds */
   6314         rv = _bcm_th2_ecmp_dlb_physical_qsize_thresholds_set(unit, 0, 0);
   6315         if (BCM_FAILURE(rv)) {
   6316             _bcm_th2_ecmp_dlb_deinit(unit);
   6317             return rv;
   6318         }
   6319 
   6320         /* Disable link status override by software */
   6321         rv = soc_mem_clear(unit, DLB_ECMP_LINK_CONTROLm, MEM_BLOCK_ALL, 0);
   6322         if (BCM_FAILURE(rv)) {
   6323             _bcm_th2_ecmp_dlb_deinit(unit);
   6324             return rv;
   6325         }
   6326 
   6327         /* Clear group membership */
   6328         rv = soc_mem_clear(unit, DLB_ECMP_GROUP_MEMBERSHIPm, MEM_BLOCK_ALL, 0);
   6329         if (BCM_FAILURE(rv)) {
   6330             _bcm_th2_ecmp_dlb_deinit(unit);
   6331             return rv;
   6332         }
   6333 
   6334 #ifdef BCM_TOMAHAWK3_SUPPORT
   6335         if (soc_feature(unit, soc_feature_th3_style_dlb)) {
   6336             uint64 dlb_en_bitmap;
   6337             rv = READ_DLB_ID_0_TO_63_ENABLEr(unit, &dlb_en_bitmap);
   6338             if (BCM_SUCCESS(rv)) {
   6339                 uint64 my_zero;
   6340                 COMPILER_64_ZERO(my_zero);
   6341                 soc_reg64_field_set(unit, DLB_ID_0_TO_63_ENABLEr, &dlb_en_bitmap, 
   6342                                     BITMAPf, my_zero);
   6343                 soc_reg64_field_set(unit, DLB_ID_64_TO_127_ENABLEr, 
   6344                                     &dlb_en_bitmap, BITMAPf, my_zero);
   6345                 BCM_IF_ERROR_RETURN(WRITE_DLB_ID_0_TO_63_ENABLEr(unit, 
   6346                                         dlb_en_bitmap));
   6347                 BCM_IF_ERROR_RETURN(WRITE_DLB_ID_64_TO_127_ENABLEr(unit, 
   6348                                         dlb_en_bitmap));
   6349             }
   6350         }
   6351 #endif
   6352         if (!(soc_feature(unit, soc_feature_th3_style_dlb))) {
   6353             /* Clear group port to member tables */
   6354             rv = soc_mem_clear(unit, DLB_ECMP_GROUP_PORT_TO_MEMBERm,
   6355                     MEM_BLOCK_ALL, 0);
   6356             if (BCM_FAILURE(rv)) {
   6357                 _bcm_th2_ecmp_dlb_deinit(unit);
   6358                 return rv;
   6359             }
   6360         }
   6361 
   6362         /* Configure per member quality measure update control. */
   6363         for (port = 0;
   6364              port < soc_mem_index_count(unit,
   6365                      DLB_ECMP_PORT_QUALITY_UPDATE_MEASURE_CONTROLm);
   6366              port++) {
   6367             rv = READ_DLB_ECMP_PORT_QUALITY_UPDATE_MEASURE_CONTROLm(unit,
   6368                     MEM_BLOCK_ANY, port, &measure_entry);
   6369             if (BCM_FAILURE(rv)) {
   6370                 _bcm_th2_ecmp_dlb_deinit(unit);
   6371                 return rv;
   6372             }
   6373             soc_DLB_ECMP_PORT_QUALITY_UPDATE_MEASURE_CONTROLm_field32_set(unit,
   6374                     &measure_entry, ENABLE_MEASURE_AVERAGE_CALCULATIONf, 1);
   6375             soc_DLB_ECMP_PORT_QUALITY_UPDATE_MEASURE_CONTROLm_field32_set(unit,
   6376                     &measure_entry, ENABLE_PORT_QUALITY_UPDATEf, 1);
   6377             soc_DLB_ECMP_PORT_QUALITY_UPDATE_MEASURE_CONTROLm_field32_set(unit,
   6378                     &measure_entry, ENABLE_CREDIT_COLLECTIONf, 1);
   6379             rv = WRITE_DLB_ECMP_PORT_QUALITY_UPDATE_MEASURE_CONTROLm(unit,
   6380                     MEM_BLOCK_ALL, port, &measure_entry);
   6381             if (BCM_FAILURE(rv)) {
   6382                 _bcm_th2_ecmp_dlb_deinit(unit);
   6383                 return rv;
   6384             }
   6385         }
   6386 
   6387         /* Configure per member threshold scaling factor */
   6388         for (port = 0;
   6389              port < soc_mem_index_count(unit, DLB_ECMP_QUANTIZE_CONTROLm);
   6390              port++) {
   6391             rv = READ_DLB_ECMP_QUANTIZE_CONTROLm(unit, MEM_BLOCK_ANY,
   6392                     port, &quantize_control_entry);
   6393             if (BCM_FAILURE(rv)) {
   6394                 _bcm_th2_ecmp_dlb_deinit(unit);
   6395                 return rv;
   6396             }
   6397             /* default 10G */
   6398             soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_set(unit,
   6399                     &quantize_control_entry,
   6400                     PORT_LOADING_THRESHOLD_SCALING_FACTORf,
   6401                     0);
   6402             if (!soc_feature(unit, soc_feature_td3_dlb)) {
   6403                 soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_set(unit,
   6404                         &quantize_control_entry,
   6405                         TOTAL_PORT_QSIZE_THRESHOLD_SCALING_FACTORf,
   6406                         2);
   6407             }
   6408             soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_set(unit,
   6409                     &quantize_control_entry,
   6410                     qsf_field,
   6411                     0);
   6412             rv = WRITE_DLB_ECMP_QUANTIZE_CONTROLm(unit, MEM_BLOCK_ALL,
   6413                     port, &quantize_control_entry);
   6414             if (BCM_FAILURE(rv)) {
   6415                 _bcm_th2_ecmp_dlb_deinit(unit);
   6416                 return rv;
   6417             }
   6418         }
   6419 
   6420         /* Configure Ethertype eligibility */
   6421         rv = soc_mem_clear(unit, DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm,
   6422                 MEM_BLOCK_ALL, 0);
   6423         if (BCM_FAILURE(rv)) {
   6424             _bcm_th2_ecmp_dlb_deinit(unit);
   6425             return rv;
   6426         }
   6427 
   6428 #ifdef BCM_TRIDENT3_SUPPORT
   6429         if (soc_feature(unit, soc_feature_td3_dlb)) {
   6430             rv = READ_DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr(unit,
   6431                     &reg_val);
   6432             if (BCM_SUCCESS(rv)) {
   6433                 soc_reg_field_set(unit, DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr,
   6434                         &reg_val, CONFIGURATIONf, 0);
   6435                 soc_reg_field_set(unit, DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr,
   6436                         &reg_val, INNER_OUTER_ETHERTYPE_SELECTIONf, 0);
   6437                 rv = WRITE_DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr(unit,
   6438                         reg_val);
   6439             }
   6440         } else
   6441 #endif
   6442         {
   6443             rv = READ_DLB_ECMP_EEM_CONFIGURATIONm(unit,
   6444                     MEM_BLOCK_ANY, 0, &eem_entry);
   6445             if (BCM_SUCCESS(rv)) {
   6446                 soc_DLB_ECMP_EEM_CONFIGURATIONm_field32_set(unit,
   6447                         &eem_entry,
   6448                         CONFIGURATIONf, 0);
   6449                 if (!(soc_feature(unit, soc_feature_th3_style_dlb))) {
   6450                     soc_DLB_ECMP_EEM_CONFIGURATIONm_field32_set(unit,
   6451                             &eem_entry,
   6452                             INNER_OUTER_ETHERTYPE_SELECTIONf, 0);
   6453                 }
   6454                 rv = WRITE_DLB_ECMP_EEM_CONFIGURATIONm(unit,
   6455                         MEM_BLOCK_ALL, 0, &eem_entry);
   6456             }
   6457             if (BCM_FAILURE(rv)) {
   6458                 _bcm_th2_ecmp_dlb_deinit(unit);
   6459                 return rv;
   6460             }
   6461         }
   6462 
   6463 #ifdef BCM_TOMAHAWK3_SUPPORT
   6464         /* Clear all DLB flow monitoring confuration */
   6465         if (SOC_IS_TOMAHAWK3(unit)) {
   6466             int seed = 1; /* Initialize seed to a non-zero value */
   6467 
   6468             if (soc_property_get(unit, spn_DLB_FLOW_MONITOR_EN, 0)) {
   6469                 rv = soc_mem_clear(unit, DLB_ECMP_GROUP_MONITOR_CONTROLm,
   6470                         MEM_BLOCK_ALL, 0);
   6471 
   6472                 if (BCM_FAILURE(rv)) {
   6473                     _bcm_th2_ecmp_dlb_deinit(unit);
   6474                     return rv;
   6475                 }
   6476             }
   6477 
   6478             /* Program DLB monitor's random selection seed */
   6479             rv = WRITE_DLB_ECMP_MONITOR_CONTROLr(unit, seed);
   6480             if (BCM_FAILURE(rv)) {
   6481                 _bcm_th2_ecmp_dlb_deinit(unit);
   6482                 return rv;
   6483             }
   6484 
   6485             /* Program DLB monitor's random selection seed for IFP */
   6486             rv = WRITE_DLB_ECMP_MONITOR_IFP_CONTROLr(unit, seed);
   6487             if (BCM_FAILURE(rv)) {
   6488                 _bcm_th2_ecmp_dlb_deinit(unit);
   6489                 return rv;
   6490             }
   6491         }
   6492 #endif
   6493     }
   6494     if (SOC_REG_IS_VALID(unit, DLB_ECMP_PORT_XPE_A_B_SELECTORr)) {
   6495         for (pipe = 0; pipe < NUM_PIPE(unit); pipe ++) {
   6496             reg = SOC_REG_UNIQUE_ACC(unit, DLB_ECMP_PORT_XPE_A_B_SELECTORr)[pipe];
   6497             rv = soc_reg_field32_modify(unit, reg,
   6498                     REG_PORT_ANY, CAP_SINGLE_QSIZE_SELECTORf, qsize_sel[pipe]);
   6499             if (BCM_FAILURE(rv)) {
   6500                 _bcm_th2_ecmp_dlb_deinit(unit);
   6501                 return rv;
   6502             }
   6503         }
   6504     }
   6505 
   6506     READ_AUX_ARB_CONTROLr(unit, &rval);
   6507     if (soc_reg_field_valid(unit, AUX_ARB_CONTROLr,
   6508                 DLB_HGT_256NS_REFRESH_ENABLEf)) {
   6509         soc_reg_field_set(unit, AUX_ARB_CONTROLr, &rval,
   6510                 DLB_HGT_256NS_REFRESH_ENABLEf, 1);
   6511     }
   6512     WRITE_AUX_ARB_CONTROLr(unit, rval);
   6513 
   6514     return rv;
   6515 }
   6516 
   6517 
   6518 #ifdef BCM_WARM_BOOT_SUPPORT
   6519 
   6520 /*
   6521  * Function:
   6522  *      bcm_th2_ecmp_dlb_wb_alloc_size_get
   6523  * Purpose:
   6524  *      Get level 2 warm boot scache size for ECMP DLB.
   6525  * Parameters:
   6526  *      unit - (IN) SOC unit number.
   6527  *      size - (OUT) Allocation size.
   6528  * Returns:
   6529  *      BCM_E_XXX
   6530  */
   6531 int
   6532 bcm_th2_ecmp_dlb_wb_alloc_size_get(int unit, int *size)
   6533 {
   6534     int alloc_size = 0;
   6535     int num_elements;
   6536 
   6537     /* Allocate size for the following ECMP DLB parameters:
   6538      * int ecmp_dlb_sample_rate;
   6539      * int ecmp_dlb_tx_load_min_th;
   6540      * int ecmp_dlb_tx_load_max_th;
   6541      * int ecmp_dlb_qsize_min_th;
   6542      * int ecmp_dlb_qsize_max_th;
   6543      * int ecmp_dlb_physical_qsize_min_th;
   6544      * int ecmp_dlb_physical_qsize_max_th;
   6545      *     ecmp_dlb_id_dgm_bitmap
   6546      * For TD3, these HW thresholds are absent
   6547      * ecmp_dlb_qsize_min_th & ecmp_dlb_qsize_max_th
   6548      * For TH3, bitmap for Egr objects are also saved.
   6549      */
   6550     if(soc_feature(unit, soc_feature_td3_dlb)) {
   6551         alloc_size += sizeof(int) * 5;
   6552     } else {
   6553         alloc_size += sizeof(int) * 7;
   6554     }
   6555     /* Allocate size of ecmp_dlb_load_weight & ecmp_dlb_qsize_weight array */
   6556     num_elements = 1 << soc_mem_field_length(unit,
   6557             DLB_ECMP_QUANTIZE_CONTROLm, PORT_QUALITY_MAPPING_PROFILE_PTRf);
   6558     alloc_size += sizeof(uint8) * 2 * num_elements;
   6559 
   6560     num_elements = soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm);
   6561     alloc_size += SHR_BITALLOCSIZE(num_elements);
   6562 
   6563 #if defined(BCM_TOMAHAWK3_SUPPORT)
   6564     if (soc_feature(unit, soc_feature_th3_style_dlb)) {
   6565         /* For TH3, add DLB EGR objects which are not a member of the group.
   6566          * Save in a form of bitmap, as this way it always be 4K bytes in size,
   6567          * else if IDs are saved directly it might take upto 64K bytes in worst
   6568          * case scenario (where all EGR Objects not a part of ECMP groups), as
   6569          * there can be max 16K DLB Egr objects.
   6570          */
   6571         num_elements = soc_mem_index_count(unit, ING_L3_NEXT_HOPm);
   6572         alloc_size += SHR_BITALLOCSIZE(num_elements);
   6573 
   6574         /* For TH3, save the member bitmap for the DLB ECMP group */
   6575         alloc_size += BCM_TH3_L3_ECMP_MAX_DLB_GROUPS *
   6576                 SHR_BITALLOCSIZE(BCM_TH3_L3_ECMP_DLB_MAX_PATHS * 2);
   6577     } else
   6578 #endif /* BCM_TOMAHAWK3_SUPPORT */
   6579     {
   6580         num_elements = soc_mem_index_count(unit, ING_L3_NEXT_HOPm);
   6581         alloc_size += SHR_BITALLOCSIZE(num_elements);
   6582     }
   6583     *size = alloc_size;
   6584 
   6585     return BCM_E_NONE;
   6586 }
   6587 
   6588 /*
   6589  * Function:
   6590  *      bcm_th2_ecmp_dlb_member_sync
   6591  * Purpose:
   6592  *      Sync ECMP DLB member info for those members which do not belong
   6593  *      to any DLB ECMP group yet.
   6594  * Parameters:
   6595  *      unit - (IN) SOC unit number.
   6596  *      scache_ptr - (OUT)
   6597  * Returns:
   6598  *      BCM_E_XXX
   6599  */
   6600 int
   6601 bcm_th2_ecmp_dlb_member_sync(int unit, uint8 **scache_ptr)
   6602 {
   6603     int         port;
   6604 
   6605     SHR_BITDCL *bitmap = (SHR_BITDCL *)(*scache_ptr);
   6606     _th2_ecmp_dlb_port_membership_t *current_ptr = NULL;
   6607 
   6608     /* Save the standalone NHOPs from the DLP port based list */
   6609     for (port=0 ;port < ECMP_DLB_INFO(unit)->ecmp_dlb_port_info_size ;port++) {
   6610         current_ptr = ECMP_DLB_PORT_LIST(unit, port);
   6611         while (current_ptr) {
   6612             if (-1 == current_ptr->dlb_id) {
   6613                 if (current_ptr->nh_index < BCM_XGS3_L3_NH_TBL_SIZE(unit)) {
   6614                     SHR_BITSET(bitmap, current_ptr->nh_index);
   6615                 }
   6616             }
   6617             current_ptr = current_ptr->next;
   6618         }
   6619     }
   6620     (*scache_ptr) += SHR_BITALLOCSIZE(BCM_XGS3_L3_NH_TBL_SIZE(unit));
   6621 
   6622     return BCM_E_NONE;
   6623 }
   6624 
   6625 /*
   6626  * Function:
   6627  *      bcm_th2_ecmp_dlb_member_scache_recover
   6628  * Purpose:
   6629  *      Recover ECMP DLB member info for those members which do not belong
   6630  *      to any DLB ECMP group yet.
   6631  * Parameters:
   6632  *      unit - (IN) SOC unit number.
   6633  *      scache_ptr - (OUT)
   6634  * Returns:
   6635  *      BCM_E_XXX
   6636  */
   6637 int
   6638 bcm_th2_ecmp_dlb_member_scache_recover(int unit, uint8 **scache_ptr)
   6639 {
   6640     int         rv = BCM_E_NONE;
   6641 
   6642     int         nh_index;
   6643     char        *l3_tbl_ptr    = NULL;  /* Table dma pointer. */
   6644     uint32      *ing_entry_ptr = NULL;
   6645     uint32      port;
   6646     uint32      hw_entry[SOC_MAX_MEM_WORDS];  /* Buffer to fill nh entry. */
   6647     SHR_BITDCL  *bitmap = (SHR_BITDCL *)(*scache_ptr);
   6648     _th2_ecmp_dlb_port_membership_t *membership;
   6649 #ifdef BCM_TRIDENT3_SUPPORT
   6650     uint32 dest_type = SOC_MEM_FIF_DEST_INVALID;
   6651 #endif
   6652 
   6653     rv = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, nh),
   6654                              BCM_XGS3_L3_ENT_SZ(unit, nh),
   6655                              "l3_tbl", &l3_tbl_ptr, NULL);
   6656     if (BCM_FAILURE(rv)) {
   6657         rv = BCM_E_NONE;
   6658         l3_tbl_ptr = NULL;
   6659         ing_entry_ptr = &hw_entry[0];
   6660     }
   6661 
   6662     /* Create the DLB port based list */
   6663     SHR_BIT_ITER(bitmap, BCM_XGS3_L3_NH_TBL_SIZE(unit), nh_index) {
   6664         /* Read ingress next hop entry. */
   6665         if (l3_tbl_ptr) {
   6666             ing_entry_ptr =
   6667                 soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, nh),
   6668                                              uint32 *, l3_tbl_ptr, nh_index);
   6669         } else {
   6670             BCM_XGS3_L3_MODULE_LOCK(unit);
   6671             rv = BCM_XGS3_MEM_READ(
   6672                      unit, BCM_XGS3_L3_MEM(unit, nh), nh_index, ing_entry_ptr);
   6673             BCM_XGS3_L3_MODULE_UNLOCK(unit);
   6674             if (BCM_FAILURE(rv)) {
   6675                 break;
   6676             }
   6677         }
   6678 
   6679 #ifdef BCM_TRIDENT3_SUPPORT
   6680         if (SOC_IS_TRIDENT3X(unit)) {
   6681             port = soc_mem_field32_dest_get(unit, BCM_XGS3_L3_MEM(unit, nh),
   6682                                             ing_entry_ptr, DESTINATIONf, &dest_type);
   6683             if (dest_type == SOC_MEM_FIF_DEST_DGPP) {
   6684                 port = (port & SOC_MEM_FIF_DGPP_PORT_MASK);
   6685             } else {
   6686                 continue;
   6687             }
   6688         } else
   6689 #endif
   6690         {
   6691             if (soc_mem_field32_get(
   6692                     unit, BCM_XGS3_L3_MEM(unit, nh), ing_entry_ptr, Tf)) {
   6693                 /* DLB Egr object cannot be a trunk, Skip the entry */
   6694                 continue;
   6695             }
   6696             port = soc_mem_field32_get(
   6697                        unit, BCM_XGS3_L3_MEM(unit, nh), ing_entry_ptr, PORT_NUMf);
   6698         }
   6699 
   6700         membership =
   6701             sal_alloc(sizeof(_th2_ecmp_dlb_port_membership_t),
   6702             "ecmp dlb nh membership");
   6703         if (NULL == membership) {
   6704             rv = BCM_E_MEMORY;
   6705             break;
   6706         }
   6707         sal_memset(membership, 0, sizeof(_th2_ecmp_dlb_port_membership_t));
   6708         membership->nh_index = nh_index;
   6709         membership->dlb_id   = -1;
   6710         membership->next = ECMP_DLB_PORT_LIST(unit, port);
   6711         ECMP_DLB_PORT_LIST(unit, port) = membership;
   6712         ECMP_DLB_PORT_INFO(unit, port).nh_count++;
   6713     }
   6714 
   6715     if (l3_tbl_ptr) {
   6716         soc_cm_sfree(unit, l3_tbl_ptr);
   6717         l3_tbl_ptr = NULL;
   6718     }
   6719     (*scache_ptr) += SHR_BITALLOCSIZE(BCM_XGS3_L3_NH_TBL_SIZE(unit));
   6720 
   6721     return rv;
   6722 }
   6723 #if defined(BCM_TOMAHAWK3_SUPPORT)
   6724 /*
   6725  * Function:
   6726  *      _bcm_th3_ecmp_dlb_member_sync
   6727  * Purpose:
   6728  *      Sync ECMP DLB member info for those members which do not belong
   6729  *      to any DLB ECMP group yet.
   6730  * Parameters:
   6731  *      unit - (IN) SOC unit number.
   6732  *      scache_ptr - (OUT)
   6733  * Returns:
   6734  *      BCM_E_XXX
   6735  */
   6736 static int
   6737 _bcm_th3_ecmp_dlb_member_sync(int unit, uint8 **scache_ptr)
   6738 {
   6739     int         port;
   6740     uint32      bytes;
   6741     SHR_BITDCL *bitmap = (SHR_BITDCL *)(*scache_ptr);
   6742     _th2_ecmp_dlb_port_membership_t *current_ptr = NULL;
   6743 
   6744     /* Save the standalone NHOPs from the DLP port based list */
   6745     for (port=0 ;port < ECMP_DLB_INFO(unit)->ecmp_dlb_port_info_size ;port++) {
   6746         current_ptr = ECMP_DLB_PORT_LIST(unit, port);
   6747         while (current_ptr) {
   6748             if (-1 == current_ptr->dlb_id) {
   6749                 if (current_ptr->nh_index < BCM_XGS3_L3_NH_TBL_SIZE(unit)) {
   6750                     SHR_BITSET(bitmap, current_ptr->nh_index);
   6751                 }
   6752             }
   6753             current_ptr = current_ptr->next;
   6754         }
   6755     }
   6756     (*scache_ptr) += SHR_BITALLOCSIZE(BCM_XGS3_L3_NH_TBL_SIZE(unit));
   6757 
   6758     /* Save the member bitmap information for all DLB ECMP groups */
   6759     bitmap = (SHR_BITDCL *)
   6760         BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(
   6761             unit, BCM_TH3_L3_ECMP_DLB_START(unit));
   6762     bytes = BCM_TH3_L3_ECMP_MAX_DLB_GROUPS *
   6763                 SHR_BITALLOCSIZE(BCM_TH3_L3_ECMP_DLB_MAX_PATHS * 2);
   6764     sal_memcpy((*scache_ptr), bitmap, bytes);
   6765     (*scache_ptr) += bytes;
   6766 
   6767     return BCM_E_NONE;
   6768 }
   6769 
   6770 /*
   6771  * Function:
   6772  *      _bcm_th3_ecmp_dlb_scache_recover
   6773  * Purpose:
   6774  *      Recover ECMP DLB member info for those members which do not belong
   6775  *      to any DLB ECMP group yet.
   6776  * Parameters:
   6777  *      unit - (IN) SOC unit number.
   6778  *      scache_ptr - (OUT)
   6779  * Returns:
   6780  *      BCM_E_XXX
   6781  */
   6782 static int
   6783 _bcm_th3_ecmp_dlb_scache_recover(int unit, uint8 **scache_ptr)
   6784 {
   6785     int         rv = BCM_E_NONE;
   6786     int         bytes;
   6787     int         nh_index;
   6788     char        *l3_tbl_ptr    = NULL;  /* Table dma pointer. */
   6789     uint32      *ing_entry_ptr = NULL;
   6790     uint32      port;
   6791     uint32      hw_entry[SOC_MAX_MEM_WORDS];  /* Buffer to fill nh entry. */
   6792     SHR_BITDCL  *bitmap = (SHR_BITDCL *)(*scache_ptr);
   6793     _th2_ecmp_dlb_port_membership_t *membership;
   6794 
   6795     rv = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, nh),
   6796                                   BCM_XGS3_L3_ENT_SZ(unit, nh),
   6797                                   "l3_tbl", &l3_tbl_ptr, NULL);
   6798     if (BCM_FAILURE(rv)) {
   6799         rv = BCM_E_NONE;
   6800         l3_tbl_ptr = NULL;
   6801         ing_entry_ptr = &hw_entry[0];
   6802     }
   6803 
   6804     /* Create the DLB port based list */
   6805     SHR_BIT_ITER(bitmap, BCM_XGS3_L3_NH_TBL_SIZE(unit), nh_index) {
   6806         /* Read ingress next hop entry. */
   6807         if (l3_tbl_ptr) {
   6808             ing_entry_ptr =
   6809                 soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, nh),
   6810                                              uint32 *, l3_tbl_ptr, nh_index);
   6811         } else {
   6812             BCM_XGS3_L3_MODULE_LOCK(unit);
   6813             rv = BCM_XGS3_MEM_READ(
   6814                     unit, BCM_XGS3_L3_MEM(unit, nh), nh_index, ing_entry_ptr);
   6815             BCM_XGS3_L3_MODULE_UNLOCK(unit);
   6816             if (BCM_FAILURE(rv)) {
   6817                 break;
   6818             }
   6819         }
   6820         if (soc_mem_field32_get(
   6821                 unit, BCM_XGS3_L3_MEM(unit, nh), ing_entry_ptr, Tf)) {
   6822             /* DLB Egr object cannot be a trunk, Skip the entry */
   6823             continue;
   6824         }
   6825         port = soc_mem_field32_get(
   6826                     unit, BCM_XGS3_L3_MEM(unit, nh), ing_entry_ptr, PORT_NUMf);
   6827 
   6828         membership = sal_alloc(
   6829             sizeof(_th2_ecmp_dlb_port_membership_t), "ecmp dlb nh membership");
   6830         if (NULL == membership) {
   6831             rv = BCM_E_MEMORY;
   6832             break;
   6833         }
   6834         sal_memset(membership, 0, sizeof(_th2_ecmp_dlb_port_membership_t));
   6835         membership->nh_index = nh_index;
   6836         membership->dlb_id   = -1;
   6837         membership->next = ECMP_DLB_PORT_LIST(unit, port);
   6838         ECMP_DLB_PORT_LIST(unit, port) = membership;
   6839         ECMP_DLB_PORT_INFO(unit, port).nh_count++;
   6840     }
   6841 
   6842     if (l3_tbl_ptr) {
   6843         soc_cm_sfree(unit, l3_tbl_ptr);
   6844         l3_tbl_ptr = NULL;
   6845     }
   6846     (*scache_ptr) += SHR_BITALLOCSIZE(BCM_XGS3_L3_NH_TBL_SIZE(unit));
   6847     if (BCM_FAILURE(rv)) {
   6848         return rv;
   6849     }
   6850 
   6851     /* Retrieve the member bitmap for DLB ECMP groups */
   6852     bitmap = (SHR_BITDCL *)
   6853         BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(
   6854             unit, BCM_TH3_L3_ECMP_DLB_START(unit));
   6855     bytes = BCM_TH3_L3_ECMP_MAX_DLB_GROUPS *
   6856                 SHR_BITALLOCSIZE(BCM_TH3_L3_ECMP_DLB_MAX_PATHS * 2);
   6857     sal_memcpy(bitmap, (*scache_ptr), bytes);
   6858     (*scache_ptr) += bytes;
   6859     return rv;
   6860 }
   6861 #endif
   6862 /*
   6863  * Function:
   6864  *      bcm_th2_ecmp_dlb_sync
   6865  * Purpose:
   6866  *      Store ECMP DLB parameters into scache.
   6867  * Parameters:
   6868  *      unit        - (IN) SOC unit number.
   6869  *      scache_ptr  - (IN/OUT) Scache pointer
   6870  * Returns:
   6871  *      BCM_E_XXX
   6872  */
   6873 int
   6874 bcm_th2_ecmp_dlb_sync(int unit, uint8 **scache_ptr)
   6875 {
   6876     int value;
   6877     int num_elements;
   6878     int i;
   6879     uint8 load_weight;
   6880     uint8 qsize_weight;
   6881 
   6882     /* Store the following ECMP DLB parameters:
   6883      * int ecmp_dlb_sample_rate;
   6884      * int ecmp_dlb_tx_load_min_th;
   6885      * int ecmp_dlb_tx_load_max_th;
   6886      * int ecmp_dlb_qsize_min_th;
   6887      * int ecmp_dlb_qsize_max_th;
   6888      * int ecmp_dlb_physical_qsize_min_th;
   6889      * int ecmp_dlb_physical_qsize_max_th;
   6890      *     ecmp_dlb_id_dgm_bitmap
   6891      */
   6892     value = ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate;
   6893     sal_memcpy((*scache_ptr), &value, sizeof(int));
   6894     (*scache_ptr) += sizeof(int);
   6895 
   6896     value = ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th;
   6897     sal_memcpy((*scache_ptr), &value, sizeof(int));
   6898     (*scache_ptr) += sizeof(int);
   6899 
   6900     value = ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th;
   6901     sal_memcpy((*scache_ptr), &value, sizeof(int));
   6902     (*scache_ptr) += sizeof(int);
   6903 
   6904     if (!soc_feature(unit, soc_feature_td3_dlb)) {
   6905         value = ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th;
   6906         sal_memcpy((*scache_ptr), &value, sizeof(int));
   6907         (*scache_ptr) += sizeof(int);
   6908 
   6909         value = ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th;
   6910         sal_memcpy((*scache_ptr), &value, sizeof(int));
   6911         (*scache_ptr) += sizeof(int);
   6912     }
   6913 
   6914     value = ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_min_th;
   6915     sal_memcpy((*scache_ptr), &value, sizeof(int));
   6916     (*scache_ptr) += sizeof(int);
   6917 
   6918     value = ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_max_th;
   6919     sal_memcpy((*scache_ptr), &value, sizeof(int));
   6920     (*scache_ptr) += sizeof(int);
   6921 
   6922     /* Store ecmp_dlb_load_weight & ecmp_dlb_qsize_weight array */
   6923     num_elements = 1 << soc_mem_field_length(unit,
   6924             DLB_ECMP_QUANTIZE_CONTROLm, PORT_QUALITY_MAPPING_PROFILE_PTRf);
   6925     for (i = 0; i < num_elements; i++) {
   6926         load_weight = ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[i];
   6927         qsize_weight = ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_weight[i];
   6928         sal_memcpy((*scache_ptr), &load_weight, sizeof(uint8));
   6929         (*scache_ptr) += sizeof(uint8);
   6930         sal_memcpy((*scache_ptr), &qsize_weight, sizeof(uint8));
   6931         (*scache_ptr) += sizeof(uint8);
   6932     }
   6933 
   6934     num_elements = soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm);
   6935     num_elements = SHR_BITALLOCSIZE(num_elements);
   6936     sal_memcpy((*scache_ptr), _th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_dgm_bitmap,
   6937                num_elements);
   6938     (*scache_ptr) += num_elements;
   6939 
   6940 #if defined(BCM_TOMAHAWK3_SUPPORT)
   6941     if (soc_feature(unit, soc_feature_th3_style_dlb)) {
   6942         /* For TH3, add DLB EGR objects which are not a member of the group.
   6943          * Save in a form of bitmap, as this way it always be 4K bytes in size,
   6944          * else if IDs are saved directly it might take upto 64K bytes in worst
   6945          * case scenario (where all EGR Objects not a part of ECMP groups), as
   6946          * there can be max 16K DLB Egr objects.
   6947          */
   6948         _bcm_th3_ecmp_dlb_member_sync(unit, scache_ptr);
   6949     }
   6950 #endif /* BCM_TOMAHAWK3_SUPPORT */
   6951     return BCM_E_NONE;
   6952 }
   6953 
   6954 /*
   6955  * Function:
   6956  *      bcm_th2_ecmp_dlb_scache_recover
   6957  * Purpose:
   6958  *      Recover ECMP DLB parameters from scache.
   6959  * Parameters:
   6960  *      unit        - (IN) SOC unit number.
   6961  *      scache_ptr  - (IN/OUT) Scache pointer
   6962  * Returns:
   6963  *      BCM_E_XXX
   6964  */
   6965 int
   6966 bcm_th2_ecmp_dlb_scache_recover(int unit, uint8 **scache_ptr)
   6967 {
   6968     int value;
   6969     int num_elements;
   6970     int i;
   6971     uint8 load_weight;
   6972     uint8 qsize_weight;
   6973 
   6974     /* Recover the following ECMP DLB parameters:
   6975      * int ecmp_dlb_sample_rate;
   6976      * int ecmp_dlb_tx_load_min_th;
   6977      * int ecmp_dlb_tx_load_max_th;
   6978      * int ecmp_dlb_qsize_min_th;
   6979      * int ecmp_dlb_qsize_max_th;
   6980      * int ecmp_dlb_physical_qsize_min_th;
   6981      * int ecmp_dlb_physical_qsize_max_th;
   6982      *     ecmp_dlb_id_dgm_bitmap
   6983      */
   6984     sal_memcpy(&value, (*scache_ptr), sizeof(int));
   6985     ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate = value;
   6986     (*scache_ptr) += sizeof(int);
   6987 
   6988     sal_memcpy(&value, (*scache_ptr), sizeof(int));
   6989     ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th = value;
   6990     (*scache_ptr) += sizeof(int);
   6991 
   6992     sal_memcpy(&value, (*scache_ptr), sizeof(int));
   6993     ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th = value;
   6994     (*scache_ptr) += sizeof(int);
   6995 
   6996     if (!soc_feature(unit, soc_feature_td3_dlb)) {
   6997         sal_memcpy(&value, (*scache_ptr), sizeof(int));
   6998         ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th = value;
   6999         (*scache_ptr) += sizeof(int);
   7000 
   7001         sal_memcpy(&value, (*scache_ptr), sizeof(int));
   7002         ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th = value;
   7003         (*scache_ptr) += sizeof(int);
   7004     }
   7005 
   7006     sal_memcpy(&value, (*scache_ptr), sizeof(int));
   7007     ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_min_th = value;
   7008     (*scache_ptr) += sizeof(int);
   7009 
   7010     sal_memcpy(&value, (*scache_ptr), sizeof(int));
   7011     ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_max_th = value;
   7012     (*scache_ptr) += sizeof(int);
   7013 
   7014 
   7015     /* Recover ecmp_dlb_load_weight & ecmp_dlb_qsize_weight array */
   7016     num_elements = 1 << soc_mem_field_length(unit,
   7017             DLB_ECMP_QUANTIZE_CONTROLm, PORT_QUALITY_MAPPING_PROFILE_PTRf);
   7018     for (i = 0; i < num_elements; i++) {
   7019         sal_memcpy(&load_weight, (*scache_ptr), sizeof(uint8));
   7020         ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[i] = load_weight;
   7021         (*scache_ptr) += sizeof(uint8);
   7022         sal_memcpy(&qsize_weight, (*scache_ptr), sizeof(uint8));
   7023         ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_weight[i] = qsize_weight;
   7024         (*scache_ptr) += sizeof(uint8);
   7025     }
   7026 
   7027     num_elements = soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm);
   7028     num_elements = SHR_BITALLOCSIZE(num_elements);
   7029     sal_memcpy(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_dgm_bitmap, (*scache_ptr), num_elements);
   7030     (*scache_ptr) += num_elements;
   7031 
   7032 #if defined(BCM_TOMAHAWK3_SUPPORT)
   7033     if (soc_feature(unit, soc_feature_th3_style_dlb)) {
   7034         _bcm_th3_ecmp_dlb_scache_recover(unit, scache_ptr);
   7035     }
   7036 #endif /* BCM_TOMAHAWK3_SUPPORT */
   7037 
   7038     ECMP_DLB_INFO(unit)->recovered_from_scache = TRUE;
   7039 
   7040     return BCM_E_NONE;
   7041 }
   7042 
   7043 /*
   7044  * Function:
   7045  *      _bcm_th2_ecmp_dlb_member_recover
   7046  * Purpose:
   7047  *      Recover ECMP DLB ports usage and the next hop indices associated
   7048  *      with the ports.
   7049  * Parameters:
   7050  *      unit - (IN) SOC unit number.
   7051  * Returns:
   7052  *      BCM_E_XXX
   7053  */
   7054 STATIC int
   7055 _bcm_th2_ecmp_dlb_member_recover(int unit)
   7056 {
   7057     int rv = BCM_E_NONE;
   7058     int port_map_width;
   7059     int alloc_size_port_map;
   7060     int alloc_size_member_bitmap;
   7061     SHR_BITDCL *port_map = NULL;
   7062     SHR_BITDCL *port_map2 = NULL;
   7063     SHR_BITDCL *member_bitmap = NULL;
   7064     int i, j, k;
   7065     int port;
   7066     int dlb_id;
   7067     dlb_ecmp_group_membership_entry_t group_membership_entry;
   7068     dlb_ecmp_group_port_to_member_entry_t port2member_entry;
   7069     ecmp_dlb_control_entry_t *ecmp_group_entry;
   7070     _th2_ecmp_dlb_port_membership_t *membership;
   7071     int ecmp_count = 0;           /* Next hop count in the group.        */
   7072     bcm_if_t *ecmp_member = NULL; /* Ecmp group from hw.                 */
   7073     dlb_ecmp_group_control_entry_t group_control_entry;
   7074     _th2_ecmp_dlb_port_membership_t *current_ptr, *first_ptr;
   7075     int membership_pointer;
   7076     int base_addr;
   7077     int group_enable;
   7078     int member_bitmap_width;
   7079     int offset;
   7080     int count;
   7081     int nh_index;
   7082     bcm_l3_egress_ecmp_t tmp_ecmp;
   7083     int primary_size = 0;
   7084     SHR_BITDCL *group_member_ptr = NULL;
   7085     int index_min, index_max,buf_size;
   7086     uint8 *ecmp_dlb_buf = NULL;
   7087     soc_mem_t mem = ECMP_DLB_CONTROLm;
   7088 
   7089     member_bitmap_width = BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2;
   7090 
   7091     /* Allocate port map */
   7092     port_map_width = soc_mem_field_length(unit,
   7093             DLB_ECMP_GROUP_MEMBERSHIPm, PORT_MAPf);
   7094     alloc_size_port_map = SHR_BITALLOCSIZE(port_map_width);
   7095     port_map = sal_alloc(alloc_size_port_map, "DLB ECMP port map");
   7096     if (NULL == port_map) {
   7097         rv = BCM_E_MEMORY;
   7098         goto cleanup;
   7099     }
   7100 
   7101     port_map2 = sal_alloc(alloc_size_port_map, "DLB ECMP port map 2");
   7102     if (NULL == port_map2) {
   7103         rv = BCM_E_MEMORY;
   7104         goto cleanup;
   7105     }
   7106 
   7107     /* Allocate member bitmap */
   7108     alloc_size_member_bitmap = SHR_BITALLOCSIZE(member_bitmap_width);
   7109     member_bitmap = sal_alloc(alloc_size_member_bitmap, "DLB ECMP member bitmap");
   7110     if (NULL == member_bitmap) {
   7111         rv = BCM_E_MEMORY;
   7112         goto cleanup;
   7113     }
   7114 
   7115     /* Allocate ECMP group members */
   7116     ecmp_member = sal_alloc(member_bitmap_width * sizeof(bcm_if_t),
   7117             "ecmp member array");
   7118     if (NULL == ecmp_member) {
   7119         rv = BCM_E_MEMORY;
   7120         goto cleanup;
   7121     }
   7122 
   7123     index_min = soc_mem_index_min(unit, mem);
   7124     index_max = soc_mem_index_max(unit, mem);
   7125     buf_size = SOC_MEM_TABLE_BYTES(unit, mem);
   7126     ecmp_dlb_buf = soc_cm_salloc(unit, buf_size, "ECMP_DLB_CONTROL buffer");
   7127     if (NULL == ecmp_dlb_buf) {
   7128         rv = BCM_E_MEMORY;
   7129         goto cleanup;
   7130     }
   7131     rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, index_min, index_max, ecmp_dlb_buf);
   7132     if (SOC_FAILURE(rv)) {
   7133         goto cleanup;
   7134     }
   7135 
   7136     for (i = index_min; i <= index_max; i++) {
   7137         ecmp_group_entry = (ecmp_dlb_control_entry_t *)
   7138                                soc_mem_table_idx_to_pointer
   7139                                   (unit, mem, void *, ecmp_dlb_buf, i);
   7140 
   7141         group_enable = soc_ECMP_DLB_CONTROLm_field32_get(unit,
   7142                                                          ecmp_group_entry,
   7143                                                          GROUP_ENABLEf);
   7144         if (0 == group_enable) {
   7145             /* DLB not enabled */
   7146             continue;
   7147         }
   7148 
   7149         /* Get DLB group ID */
   7150         dlb_id = soc_ECMP_DLB_CONTROLm_field32_get(unit, ecmp_group_entry,
   7151                                                    DLB_IDf);
   7152 
   7153         rv = READ_DLB_ECMP_GROUP_CONTROLm(unit, MEM_BLOCK_ANY, dlb_id,
   7154                                           &group_control_entry);
   7155         if (BCM_FAILURE(rv)) {
   7156             goto cleanup;
   7157         }
   7158         membership_pointer = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   7159                 &group_control_entry, GROUP_MEMBERSHIP_POINTERf);
   7160 
   7161         base_addr = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   7162                 &group_control_entry, GROUP_PORT_TO_MEMBER_BASE_ADDRf);
   7163 
   7164         primary_size = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   7165                 &group_control_entry, PRIMARY_GROUP_SIZEf);
   7166 
   7167         rv = READ_DLB_ECMP_GROUP_MEMBERSHIPm(unit, MEM_BLOCK_ANY,
   7168                                              membership_pointer,
   7169                                              &group_membership_entry);
   7170         if (BCM_FAILURE(rv)) {
   7171             goto cleanup;
   7172         }
   7173         /* We have the DLB_ID here,
   7174          * now there are 2 ways to recover these info from hw to sw:
   7175          * 1) Use the DLB_ID to get port_map,
   7176          *    the port map will indicate how many port2member entries are set.
   7177          *    traverse the valid port2member entries via port map.
   7178          *    Each port2member entry can be parsed to get the valid bits and then
   7179          *    the nexthops. Got the nexthop, the DLB_ID, the port. It's enough
   7180          *    to recover the sw state.
   7181          * 2) The first method has a side effect, which is traverse all valid
   7182          *    port2member entries, and then traverse the valid bits of each.
   7183          *    That's portnumber * 64 loops in total.
   7184          *    An alternative way is to get the ecmp members (64 members at most)
   7185          *    Parse the entries and then get the ports. Same as above, we got
   7186          *    all the needed info: nexthop, DLB_ID, port.
   7187          *
   7188          *    Actually, the port2member entries are not necessary, if DLB can
   7189          *    traverse the ecmp member table and get all nexthops pointing
   7190          *    to the chosen port, it's done. In fact, port2member is just another
   7191          *    angle of ecmp member table.
   7192          */
   7193 
   7194         /* Get port map */
   7195         sal_memset(port_map, 0, alloc_size_port_map);
   7196         soc_DLB_ECMP_GROUP_MEMBERSHIPm_field_get(unit,
   7197                 &group_membership_entry, PORT_MAPf, port_map);
   7198 
   7199         sal_memset(port_map2, 0, alloc_size_port_map);
   7200         soc_DLB_ECMP_GROUP_MEMBERSHIPm_field_get(unit,
   7201                 &group_membership_entry, PORT_MAP_ALTERNATEf, port_map2);
   7202 
   7203         /* Get ECMP members */
   7204         /* Check if the ECMP group is DLB enabled. */
   7205         bcm_l3_egress_ecmp_t_init(&tmp_ecmp);
   7206         tmp_ecmp.ecmp_intf = i + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   7207         /*
   7208          * Increase entry reference count to avoid the failure of calling
   7209          * ecmp_get since the reference count of ecmp group is recovered along
   7210          * with hash value after the recovery of DLB info.
   7211          */
   7212         BCM_XGS3_L3_ENT_REF_CNT_INC(
   7213             BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), i, _BCM_SINGLE_WIDE);
   7214         rv = _bcm_esw_l3_egress_ecmp_get(unit, &tmp_ecmp, 0,
   7215                                          NULL, &ecmp_count, TRUE);
   7216         BCM_XGS3_L3_ENT_REF_CNT_DEC(
   7217             BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), i, _BCM_SINGLE_WIDE);
   7218         if (BCM_FAILURE(rv)) {
   7219             goto cleanup;
   7220         }
   7221         if (tmp_ecmp.dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_NORMAL &&
   7222             tmp_ecmp.dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_ASSIGNED &&
   7223             tmp_ecmp.dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_OPTIMAL &&
   7224             tmp_ecmp.dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_DGM) {
   7225             rv = BCM_E_INTERNAL;
   7226             goto cleanup;
   7227         }
   7228 
   7229         if (ecmp_count > member_bitmap_width) {
   7230             rv = BCM_E_INTERNAL;
   7231             goto cleanup;
   7232         }
   7233 
   7234         sal_memset(ecmp_member, 0, member_bitmap_width * sizeof(bcm_if_t));
   7235         /*
   7236          * Increase entry reference count to avoid the failure of calling
   7237          * ecmp_get since the reference count of ecmp group is recovered along
   7238          * with hash value after the recovery of DLB info.
   7239          */
   7240         BCM_XGS3_L3_ENT_REF_CNT_INC(
   7241             BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), i, _BCM_SINGLE_WIDE);
   7242         rv = _bcm_esw_l3_egress_ecmp_get(unit, &tmp_ecmp, ecmp_count,
   7243                                          ecmp_member, &count, TRUE);
   7244         BCM_XGS3_L3_ENT_REF_CNT_DEC(
   7245             BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), i, _BCM_SINGLE_WIDE);
   7246         if (BCM_FAILURE(rv)) {
   7247             goto cleanup;
   7248         }
   7249 
   7250         for (j = 0; j < ecmp_count; j++) {
   7251             if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, ecmp_member[j])) {
   7252                 offset = BCM_XGS3_EGRESS_IDX_MIN(unit);
   7253             } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, ecmp_member[j])) {
   7254                 offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   7255             } else {
   7256                 rv = BCM_E_PARAM;
   7257                 goto cleanup;
   7258             }
   7259             ecmp_member[j] -= offset;
   7260         }
   7261 
   7262         SHR_BITOR_RANGE(port_map, port_map2, 0, port_map_width, port_map);
   7263         group_member_ptr =
   7264             BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, i);
   7265         for (port = 0; port < port_map_width; port++) {
   7266             if (!SHR_BITGET(port_map, port)){
   7267                 continue;
   7268             }
   7269 
   7270             rv = (READ_DLB_ECMP_GROUP_PORT_TO_MEMBERm(unit, MEM_BLOCK_ANY,
   7271                                                base_addr + port,
   7272                                                &port2member_entry));
   7273             if (BCM_FAILURE(rv)) {
   7274                 goto cleanup;
   7275             }
   7276 
   7277             /* Get member bitmap */
   7278             sal_memset(member_bitmap, 0, alloc_size_member_bitmap);
   7279             soc_DLB_ECMP_GROUP_PORT_TO_MEMBERm_field_get(unit,
   7280                     &port2member_entry, ECMP_MEMBER_BITMAPf, member_bitmap);
   7281 
   7282             for (k = 0; k < member_bitmap_width; k++) {
   7283                 if (!SHR_BITGET(member_bitmap, k)) {
   7284                     continue;
   7285                 }
   7286                 if (k >= ecmp_count) {
   7287                     rv = BCM_E_INTERNAL;
   7288                     goto cleanup;
   7289                 }
   7290                 if (!SHR_BITGET(port_map2, port)) {
   7291                     nh_index = ecmp_member[k];
   7292                     SHR_BITSET(group_member_ptr, k);
   7293                 } else {  /* an alternate port */
   7294                     nh_index = ecmp_member[k + primary_size];
   7295                     SHR_BITSET(group_member_ptr, k + tmp_ecmp.max_paths / 2);
   7296                 }
   7297 
   7298                 /* now have nh_index (ecmp_member[k]), port (port), dlb_id  */
   7299                 /* find it nexthop exists in specific port list*/
   7300                 current_ptr = ECMP_DLB_PORT_LIST(unit, port);
   7301                 first_ptr = NULL;
   7302                 while (current_ptr) {
   7303                     if (current_ptr->nh_index != nh_index) {
   7304                         current_ptr = current_ptr->next;
   7305                         continue;
   7306                     }
   7307 
   7308                     if (dlb_id == current_ptr->dlb_id) {
   7309                         current_ptr->ref_count++;
   7310                         break;
   7311                     }
   7312                     if (first_ptr == NULL) {
   7313                         first_ptr = current_ptr;
   7314                     }
   7315 
   7316                     current_ptr = current_ptr->next;
   7317                 }
   7318 
   7319                 if (current_ptr == NULL) {
   7320                     /* Insert member ID and group to the next hop's linked list of member
   7321                      * IDs and groups.
   7322                      */
   7323                     membership = sal_alloc(sizeof(_th2_ecmp_dlb_port_membership_t),
   7324                             "ecmp dlb nh membership");
   7325                     if (NULL == membership) {
   7326                         rv = BCM_E_MEMORY;
   7327                         goto cleanup;
   7328                     }
   7329                     sal_memset(membership, 0, sizeof(_th2_ecmp_dlb_port_membership_t));
   7330                     membership->nh_index = nh_index;
   7331                     membership->ref_count = 1;
   7332                     membership->dlb_id    = dlb_id;
   7333 
   7334                     if (first_ptr != NULL) {
   7335                     /* didnt find exact same node(nh_index, dlb_id) ,
   7336                      * but find same nh_index (A).
   7337                      * create B after A.
   7338                      * first_ptr points to A.
   7339                      */
   7340                         membership->next = first_ptr->next;
   7341                         first_ptr->next = membership;
   7342                         ECMP_DLB_PORT_INFO(unit, port).dlb_count++;
   7343                     } else {
   7344                     /* didnt find same nh_index*/
   7345                     /* this is new nh_index, insert it at head */
   7346                         membership->next = ECMP_DLB_PORT_LIST(unit, port);
   7347                         ECMP_DLB_PORT_LIST(unit, port) = membership;
   7348                         ECMP_DLB_PORT_INFO(unit, port).nh_count++;
   7349                         ECMP_DLB_PORT_INFO(unit, port).dlb_count++;
   7350                     }
   7351                 }
   7352             }
   7353         }
   7354     }
   7355 
   7356 cleanup:
   7357     if (ecmp_dlb_buf) {
   7358         soc_cm_sfree(unit, ecmp_dlb_buf);
   7359     }
   7360     if (port_map) {
   7361         sal_free(port_map);
   7362     }
   7363     if (port_map2) {
   7364         sal_free(port_map2);
   7365     }
   7366     if (member_bitmap) {
   7367         sal_free(member_bitmap);
   7368     }
   7369     if (ecmp_member) {
   7370         sal_free(ecmp_member);
   7371     }
   7372     return BCM_E_NONE;
   7373 }
   7374 
   7375 /*
   7376  * Function:
   7377  *      _bcm_th2_ecmp_dlb_group_recover
   7378  * Purpose:
   7379  *      Recover ECMP DLB group usage and flowset table usage.
   7380  * Parameters:
   7381  *      unit - (IN) SOC unit number.
   7382  * Returns:
   7383  *      BCM_E_XXX
   7384  */
   7385 STATIC int
   7386 _bcm_th2_ecmp_dlb_group_recover(int unit)
   7387 {
   7388     int i;
   7389     ecmp_dlb_control_entry_t *ecmp_dlb_control;
   7390     int group_enable, dlb_id;
   7391     dlb_ecmp_group_control_entry_t group_control_entry;
   7392     int entry_base_ptr, dynamic_size_encode, dynamic_size;
   7393     int block_base_ptr, num_blocks;
   7394     uint32 rval;
   7395     int index_min, index_max,buf_size;
   7396     uint8 *ecmp_dlb_buf = NULL;
   7397     soc_mem_t mem = ECMP_DLB_CONTROLm;
   7398     int rv = BCM_E_NONE;
   7399 
   7400     if (soc_reg_field_valid(unit, ENHANCED_HASHING_CONTROLr, RH_DLB_SELECTIONf)) {
   7401         SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROLr(unit, &rval));
   7402         if (1 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROLr, rval,
   7403                 RH_DLB_SELECTIONf)) {
   7404            /* ECMP DLB  hashing is not enabled chip-wide. */
   7405             return BCM_E_NONE;
   7406         }
   7407     }
   7408 
   7409     index_min = soc_mem_index_min(unit, mem);
   7410     index_max = soc_mem_index_max(unit, mem);
   7411     buf_size = SOC_MEM_TABLE_BYTES(unit, mem);
   7412     ecmp_dlb_buf = soc_cm_salloc(unit, buf_size, "ECMP_DLB_CONTROL buffer for group");
   7413     if (NULL == ecmp_dlb_buf) {
   7414         rv = BCM_E_MEMORY;
   7415         goto cleanup;
   7416     }
   7417     rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, index_min, index_max, ecmp_dlb_buf);
   7418     if (SOC_FAILURE(rv)) {
   7419         goto cleanup;
   7420     }
   7421 
   7422     for (i = index_min; i <= index_max; i++) {
   7423         ecmp_dlb_control = (ecmp_dlb_control_entry_t *)
   7424                                soc_mem_table_idx_to_pointer
   7425                                   (unit, mem, void *, ecmp_dlb_buf, i);
   7426         group_enable = soc_ECMP_DLB_CONTROLm_field32_get(unit, ecmp_dlb_control,
   7427                 GROUP_ENABLEf);
   7428         if (0 == group_enable) {
   7429             /* DLB not enabled */
   7430             continue;
   7431         }
   7432 
   7433         /* Get DLB group ID and marked it as used */
   7434         dlb_id = soc_ECMP_DLB_CONTROLm_field32_get(unit, ecmp_dlb_control,
   7435                 DLB_IDf);
   7436         _BCM_ECMP_DLB_ID_USED_SET(unit, dlb_id);
   7437 
   7438         /* Get flow set table usage */
   7439         rv = READ_DLB_ECMP_GROUP_CONTROLm(unit,
   7440                     MEM_BLOCK_ANY, dlb_id, &group_control_entry);
   7441         if (SOC_FAILURE(rv)) {
   7442             goto cleanup;
   7443         }
   7444         entry_base_ptr = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   7445                 &group_control_entry, FLOW_SET_BASEf);
   7446         dynamic_size_encode = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   7447                 &group_control_entry, FLOW_SET_SIZEf);
   7448         rv = _bcm_th2_ecmp_dlb_dynamic_size_decode(dynamic_size_encode,
   7449                                                    &dynamic_size);
   7450         if (SOC_FAILURE(rv)) {
   7451             goto cleanup;
   7452         }
   7453         block_base_ptr = entry_base_ptr >> _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT;
   7454         num_blocks = dynamic_size >> _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT;
   7455         _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr,
   7456                 num_blocks);
   7457 #ifdef BCM_TRIDENT3_SUPPORT
   7458         if (soc_feature(unit, soc_feature_td3_dlb)) {
   7459             ecmp_grp_enhanced_hashing[unit][i] = 1;
   7460         }
   7461 #endif
   7462     }
   7463 
   7464 cleanup:
   7465     if (ecmp_dlb_buf) {
   7466         soc_cm_sfree(unit, ecmp_dlb_buf);
   7467     }
   7468 
   7469     return rv;
   7470 }
   7471 
   7472 #if defined(BCM_TOMAHAWK3_SUPPORT)
   7473 /*
   7474  * Function:
   7475  *      _bcm_th3_ecmp_dlb_group_recover
   7476  * Purpose:
   7477  *      Recover ECMP DLB group usage and flowset table usage.
   7478  * Parameters:
   7479  *      unit - (IN) SOC unit number.
   7480  * Returns:
   7481  *      BCM_E_XXX
   7482  */
   7483 STATIC int
   7484 _bcm_th3_ecmp_dlb_group_recover(int unit)
   7485 {
   7486     int dlb_id;
   7487     uint64 dlb_en_bitmap;
   7488     dlb_ecmp_group_control_entry_t group_control_entry;
   7489     int entry_base_ptr, dynamic_size_encode, dynamic_size;
   7490     int block_base_ptr, num_blocks;
   7491     uint32 rval;
   7492 
   7493     if (soc_reg_field_valid(unit, ENHANCED_HASHING_CONTROLr, RH_DLB_SELECTIONf)) {
   7494         SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROLr(unit, &rval));
   7495         if (1 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROLr, rval,
   7496                 RH_DLB_SELECTIONf)) {
   7497            /* ECMP DLB  hashing is not enabled chip-wide. */
   7498             return BCM_E_NONE;
   7499         }
   7500     }
   7501 
   7502     for (dlb_id = 0; dlb_id < 128; dlb_id++) {
   7503         /* Enable bits for the first 64 groups are in
   7504            DLB_ID_0_TO_63_ENABLE register and the next 64 are in
   7505            DLB_ID_64_TO_127_ENABLE. */
   7506         if (dlb_id < soc_reg_field_length(unit,
   7507                      DLB_ID_0_TO_63_ENABLEr, BITMAPf)) {
   7508             SOC_IF_ERROR_RETURN( \
   7509               READ_DLB_ID_0_TO_63_ENABLEr(unit, &dlb_en_bitmap));
   7510             if (!(COMPILER_64_BITTEST(dlb_en_bitmap, dlb_id))) {
   7511                 continue;
   7512             }
   7513         } else {
   7514             SOC_IF_ERROR_RETURN( \
   7515               READ_DLB_ID_64_TO_127_ENABLEr(unit, &dlb_en_bitmap));
   7516             if (!(COMPILER_64_BITTEST(dlb_en_bitmap, dlb_id -
   7517                 soc_reg_field_length(unit, DLB_ID_0_TO_63_ENABLEr, BITMAPf)))) {
   7518                 continue;
   7519             }
   7520         }
   7521 
   7522         /* Get DLB group ID and marked it as used */
   7523         _BCM_ECMP_DLB_ID_USED_SET(unit, dlb_id);
   7524 
   7525         /* Get flow set table usage */
   7526         BCM_IF_ERROR_RETURN(READ_DLB_ECMP_GROUP_CONTROLm(unit,
   7527                     MEM_BLOCK_ANY, dlb_id, &group_control_entry));
   7528         entry_base_ptr = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   7529                 &group_control_entry, FLOW_SET_BASEf);
   7530         dynamic_size_encode = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   7531                 &group_control_entry, FLOW_SET_SIZEf);
   7532         BCM_IF_ERROR_RETURN
   7533             (_bcm_th2_ecmp_dlb_dynamic_size_decode(dynamic_size_encode,
   7534                                                    &dynamic_size));
   7535         block_base_ptr = entry_base_ptr >> _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT;
   7536         num_blocks = dynamic_size >> _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT;
   7537         _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr,
   7538                 num_blocks);
   7539     }
   7540 
   7541     return BCM_E_NONE;
   7542 }
   7543 #endif
   7544 
   7545 /*
   7546  * Function:
   7547  *      _bcm_th2_ecmp_dlb_quality_parameters_recover
   7548  * Purpose:
   7549  *      Recover ECMP DLB parameters used to derive a member's quality.
   7550  * Parameters:
   7551  *      unit - (IN) SOC unit number.
   7552  * Returns:
   7553  *      BCM_E_XXX
   7554  */
   7555 STATIC int
   7556 _bcm_th2_ecmp_dlb_quality_parameters_recover(int unit)
   7557 {
   7558     uint32 measure_control_reg;
   7559     int num_time_units;
   7560     dlb_ecmp_glb_quantize_threshold_entry_t quantize_threshold_entry;
   7561     int min_th_bytes, min_th_cells;
   7562     int max_th_bytes, max_th_cells;
   7563     int entries_per_profile;
   7564     int profile_ptr, base_index;
   7565     dlb_ecmp_quality_mapping_entry_t quality_mapping_entry;
   7566     int quality;
   7567     int num_profile;
   7568 
   7569     if (ECMP_DLB_INFO(unit)->recovered_from_scache) {
   7570         /* If already recovered from scache, do nothing. */
   7571         return BCM_E_NONE;
   7572     }
   7573 
   7574     /* Recover sampling rate */
   7575     BCM_IF_ERROR_RETURN(READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit,
   7576                 &measure_control_reg));
   7577     num_time_units = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   7578             measure_control_reg, SAMPLING_PERIODf);
   7579     if (num_time_units > 0) {
   7580         ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate = 1000000 / num_time_units;
   7581     }
   7582 
   7583     /* Recover min and max load, queue size and physical queue size thresholds:
   7584      * Load threshold (in mbps)
   7585      *     = (bytes per sampling period) * 8 bits per byte /
   7586      *       (sampling period in seconds) / 10^6
   7587      *     = (bytes per sampling period) * 8 bits per byte /
   7588      *       (num_time_units * 1 us per time unit * 10^-6) / 10^6
   7589      *     = (bytes per sampling period) * 8 / num_time_units
   7590      */
   7591     BCM_IF_ERROR_RETURN(READ_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm(unit,
   7592                 MEM_BLOCK_ANY, 0, &quantize_threshold_entry));
   7593     min_th_bytes = soc_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm_field32_get
   7594         (unit, &quantize_threshold_entry, PORT_LOADING_THRESHOLDf);
   7595     ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th = (min_th_bytes << 3) /
   7596         num_time_units;
   7597 
   7598     if (!soc_feature(unit, soc_feature_td3_dlb)) {
   7599         min_th_cells = soc_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm_field32_get
   7600             (unit, &quantize_threshold_entry, TOTAL_PORT_QSIZE_THRESHOLDf);
   7601         ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th =
   7602             min_th_cells * _BCM_ECMP_DLB_CELL_BYTES;
   7603     }
   7604 
   7605     min_th_cells = soc_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm_field32_get
   7606         (unit, &quantize_threshold_entry, XPE_PORT_QSIZE_THRESHOLDf);
   7607     ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_min_th =
   7608             min_th_cells * _BCM_ECMP_DLB_CELL_BYTES;
   7609 
   7610     BCM_IF_ERROR_RETURN(READ_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm(unit,
   7611                 MEM_BLOCK_ANY, soc_mem_index_max(unit,
   7612                     DLB_ECMP_GLB_QUANTIZE_THRESHOLDm),
   7613                 &quantize_threshold_entry));
   7614     max_th_bytes = soc_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm_field32_get
   7615         (unit, &quantize_threshold_entry, PORT_LOADING_THRESHOLDf);
   7616     ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th = (max_th_bytes << 3) /
   7617         num_time_units;
   7618 
   7619     if (!soc_feature(unit, soc_feature_td3_dlb)) {
   7620         max_th_cells = soc_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm_field32_get
   7621             (unit, &quantize_threshold_entry, TOTAL_PORT_QSIZE_THRESHOLDf);
   7622         ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th =
   7623             max_th_cells * _BCM_ECMP_DLB_CELL_BYTES;
   7624     }
   7625 
   7626     max_th_cells = soc_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm_field32_get
   7627         (unit, &quantize_threshold_entry, XPE_PORT_QSIZE_THRESHOLDf);
   7628     ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_max_th =
   7629             max_th_cells * _BCM_ECMP_DLB_CELL_BYTES;
   7630 
   7631     /* Recover load weights and qsize weights */
   7632     num_profile = 1 << soc_mem_field_length(unit, DLB_ECMP_QUANTIZE_CONTROLm,
   7633                                             PORT_QUALITY_MAPPING_PROFILE_PTRf);
   7634     entries_per_profile =
   7635         soc_mem_index_count(unit, DLB_ECMP_PORT_QUALITY_MAPPINGm) / num_profile;
   7636     for (profile_ptr = 0; profile_ptr < num_profile; profile_ptr++) {
   7637         base_index = profile_ptr * entries_per_profile;
   7638         /* quality = (quantized_tx_load * tx_load_percent +
   7639          *            quantized_qsize * qsize_percent +
   7640          *            quantized_physical_qsize *
   7641          *            (100 - tx_load_percent - qsize_percent)) / 100;
   7642          * The index to DLB_ECMP_PORT_QUALITY_MAPPING table consists of
   7643          * base_index + quantized_tx_load * 64 +
   7644          * quantized_qsize * 8 + quantized_physical_qsize,
   7645          * where quantized_tx_load, quantized_qsize and quantized_physical_qsize
   7646          * range from 0 to 7.
   7647          *
   7648          * With quantized_tx_load = 7, quantized_qsize = quantized_physical_qsize = 0,
   7649          * the index to DLB_ECMP_PORT_QUALITY_MAPPING table is
   7650          * base_index + 448, and the tx_load_percent expression
   7651          * simplifies to quality * 100 / 7;
   7652          *
   7653          * With quantized_qsize = 7, quantized_tx_load = quantized_physical_qsize = 0,
   7654          * the index to DLB_ECMP_PORT_QUALITY_MAPPING table is
   7655          * base_index + 56, and the qsize_percent expression
   7656          * simplifies to quality * 100 / 7;
   7657          */
   7658         BCM_IF_ERROR_RETURN(READ_DLB_ECMP_PORT_QUALITY_MAPPINGm(unit,
   7659                     MEM_BLOCK_ANY, base_index + 448,
   7660                     &quality_mapping_entry));
   7661         quality = soc_DLB_ECMP_PORT_QUALITY_MAPPINGm_field32_get(unit,
   7662                 &quality_mapping_entry, ASSIGNED_QUALITYf);
   7663         ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[profile_ptr] =
   7664             quality * 100 / 7;
   7665         BCM_IF_ERROR_RETURN(READ_DLB_ECMP_PORT_QUALITY_MAPPINGm(unit,
   7666                     MEM_BLOCK_ANY, base_index + 56,
   7667                     &quality_mapping_entry));
   7668         quality = soc_DLB_ECMP_PORT_QUALITY_MAPPINGm_field32_get(unit,
   7669                 &quality_mapping_entry, ASSIGNED_QUALITYf);
   7670         ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_weight[profile_ptr] =
   7671             quality * 100 / 7;
   7672     }
   7673 
   7674     return BCM_E_NONE;
   7675 }
   7676 
   7677 /*
   7678  * Function:
   7679  *      bcm_th2_ecmp_dlb_hw_recover
   7680  * Purpose:
   7681  *      Recover ECMP DLB internal state from hardware.
   7682  * Parameters:
   7683  *      unit        - (IN) SOC unit number.
   7684  *      scache_ptr  - (IN/OUT) Scache pointer
   7685  * Returns:
   7686  *      BCM_E_XXX
   7687  */
   7688 int
   7689 bcm_th2_ecmp_dlb_hw_recover(int unit)
   7690 {
   7691 #if defined(BCM_TOMAHAWK3_SUPPORT)
   7692     if (soc_feature(unit, soc_feature_th3_style_dlb)) {
   7693 
   7694         BCM_IF_ERROR_RETURN(_bcm_th3_ecmp_dlb_member_recover(unit));
   7695         BCM_IF_ERROR_RETURN(_bcm_th3_ecmp_dlb_group_recover(unit));
   7696     } else
   7697 #endif
   7698     {
   7699 
   7700         BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_member_recover(unit));
   7701         BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_group_recover(unit));
   7702     }
   7703     BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_quality_parameters_recover(unit));
   7704     return BCM_E_NONE;
   7705 }
   7706 
   7707 #endif /* BCM_WARM_BOOT_SUPPORT */
   7708 
   7709 
   7710 #ifndef BCM_SW_STATE_DUMP_DISABLE
   7711 /*
   7712  * Function:
   7713  *     bcm_th2_ecmp_dlb_sw_dump
   7714  * Purpose:
   7715  *     Displays ECMP DLB information maintained by software.
   7716  * Parameters:
   7717  *     unit    - (IN) Device unit number.
   7718  * Returns:
   7719  *     None
   7720  */
   7721 void
   7722 bcm_th2_ecmp_dlb_sw_dump(int unit)
   7723 {
   7724     int i;
   7725     _th2_ecmp_dlb_port_membership_t *current_ptr;
   7726     int num_entries_per_profile;
   7727     int num_profiles;
   7728     int rv;
   7729     int ref_count;
   7730 
   7731     LOG_CLI((BSL_META_U(unit,
   7732                         "  ECMP DLB Info -\n")));
   7733 
   7734     /* Print ECMP DLB next hop info */
   7735     LOG_CLI((BSL_META_U(unit,
   7736                         "    ECMP DLB Port Info -\n")));
   7737     for (i = 0; i < ECMP_DLB_INFO(unit)->ecmp_dlb_port_info_size; i++) {
   7738         if (ECMP_DLB_PORT_INFO(unit, i).nh_count > 0) {
   7739             LOG_CLI((BSL_META_U(unit,
   7740                                 "      Port Number %d output by "),
   7741                      i));
   7742             current_ptr = ECMP_DLB_PORT_LIST(unit, i);
   7743             while (NULL != current_ptr) {
   7744                 LOG_CLI((BSL_META_U(unit,
   7745                                     "nexthop %d in DLB ID %d Ref_count %d"),
   7746                          current_ptr->nh_index, current_ptr->dlb_id, current_ptr->ref_count));
   7747                 current_ptr = current_ptr->next;
   7748                 if (NULL == current_ptr) {
   7749                     LOG_CLI((BSL_META_U(unit,
   7750                                         "\n")));
   7751                 } else {
   7752                     LOG_CLI((BSL_META_U(unit,
   7753                                         ", ")));
   7754                 }
   7755             }
   7756         }
   7757     }
   7758 
   7759     /* Print ECMP DLB group usage */
   7760     LOG_CLI((BSL_META_U(unit,
   7761                         "    ECMP DLB Groups Used:")));
   7762     for (i = 0; i < soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm); i++) {
   7763         if (_BCM_ECMP_DLB_ID_USED_GET(unit, i)) {
   7764             LOG_CLI((BSL_META_U(unit,
   7765                                 " %d"), i));
   7766         }
   7767     }
   7768     LOG_CLI((BSL_META_U(unit,
   7769                         "\n")));
   7770 
   7771     /* Print ECMP DLB flowset table usage */
   7772     LOG_CLI((BSL_META_U(unit,
   7773                         "    ECMP DLB Flowset Table Blocks Used:")));
   7774     for (i = 0;
   7775          i < soc_mem_index_count(unit, DLB_ECMP_FLOWSETm) >>
   7776                             _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT;
   7777          i++) {
   7778         if (_BCM_ECMP_DLB_FLOWSET_BLOCK_USED_GET(unit, i)) {
   7779             LOG_CLI((BSL_META_U(unit,
   7780                                 " %d"), i));
   7781         }
   7782     }
   7783     LOG_CLI((BSL_META_U(unit,
   7784                         "\n")));
   7785 
   7786     /* Print sample rate and threshold parameters */
   7787     LOG_CLI((BSL_META_U(unit,
   7788                         "    Sample rate: %d per second\n"),
   7789              ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate));
   7790     LOG_CLI((BSL_META_U(unit,
   7791                         "    Tx load min threshold: %d mbps\n"),
   7792              ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th));
   7793     LOG_CLI((BSL_META_U(unit,
   7794                         "    Tx load max threshold: %d mbps\n"),
   7795              ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th));
   7796     if (!soc_feature(unit, soc_feature_td3_dlb)) {
   7797         LOG_CLI((BSL_META_U(unit,
   7798                         "    Total Queue size min threshold: %d cells\n"),
   7799                     ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th));
   7800         LOG_CLI((BSL_META_U(unit,
   7801                         "    Total Queue size max threshold: %d cells\n"),
   7802                     ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th));
   7803     }
   7804     LOG_CLI((BSL_META_U(unit,
   7805                         "    Physical Queue size min threshold: %d cells\n"),
   7806              ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_min_th));
   7807     LOG_CLI((BSL_META_U(unit,
   7808                         "    Physical Queue size max threshold: %d cells\n"),
   7809              ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_max_th));
   7810 
   7811     /* Print quality mapping profiles */
   7812     LOG_CLI((BSL_META_U(unit,
   7813                         "    Quality mapping profiles:\n")));
   7814     num_entries_per_profile = soc_mem_index_count(unit, DLB_ECMP_PORT_QUALITY_MAPPINGm)/
   7815         (1 << soc_mem_field_length(unit, DLB_ECMP_QUANTIZE_CONTROLm,
   7816                                    PORT_QUALITY_MAPPING_PROFILE_PTRf));
   7817     num_profiles = soc_mem_index_count(unit, DLB_ECMP_PORT_QUALITY_MAPPINGm) /
   7818                     num_entries_per_profile;
   7819     for (i = 0; i < num_profiles; i++) {
   7820         LOG_CLI((BSL_META_U(unit,
   7821                             "      Profile %d: load weight %d percent, "\
   7822                             "qsize weight %d percent, "),
   7823                  i, ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[i],
   7824                  ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_weight[i]));
   7825         rv = soc_profile_mem_ref_count_get(unit,
   7826                 ECMP_DLB_INFO(unit)->ecmp_dlb_quality_map_profile,
   7827                 i * num_entries_per_profile, &ref_count);
   7828         if (BCM_FAILURE(rv)) {
   7829             LOG_CLI((BSL_META_U(unit,
   7830                                 "\n")));
   7831             continue;
   7832         }
   7833         LOG_CLI((BSL_META_U(unit,
   7834                             "ref count %d\n"), ref_count));
   7835     }
   7836 
   7837     return;
   7838 }
   7839 
   7840 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   7841 void
   7842 bcm_th2_dgm_sw_dump(int unit)
   7843 {
   7844     int i;
   7845     LOG_CLI((BSL_META_U(unit,
   7846                         "  DGM Info -\n")));
   7847 
   7848     LOG_CLI((BSL_META_U(unit,
   7849                         "    DGM Alternate Count:(ECMP Group- Alternate Count)")));
   7850     for (i = 0; i < BCM_XGS3_L3_ECMP_MAX_GROUPS(unit); i++) {
   7851         if (BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit)[i] != 0) {
   7852             LOG_CLI((BSL_META_U(unit,
   7853                                 " %d-%d"), i,
   7854                      BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit)[i]));
   7855         }
   7856     }
   7857     LOG_CLI((BSL_META_U(unit,
   7858                         "\n")));
   7859 
   7860     /* Print ECMP DGM group usage */
   7861     LOG_CLI((BSL_META_U(unit,
   7862                         "    DGM Groups Used:")));
   7863     for (i = 0; i < soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm); i++) {
   7864         if (_BCM_ECMP_DLB_ID_DGM_GET(unit, i)) {
   7865             LOG_CLI((BSL_META_U(unit,
   7866                                 " %d"), i));
   7867         }
   7868     }
   7869     LOG_CLI((BSL_META_U(unit,
   7870                         "\n")));
   7871 }
   7872 #endif
   7873 #endif /* ifndef BCM_SW_STATE_DUMP_DISABLE*/
   7874 
   7875 #endif /* INCLUDE_L3 && BCM_TOMAHAWK2_SUPPORT  */
   7876