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 (45006B)


      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: Tomahawk L3 function implementations
      9  */
     10 
     11 #include <soc/defs.h>
     12 #include <shared/bsl.h>
     13 #if defined(INCLUDE_L3) && defined(BCM_TOMAHAWK_SUPPORT) 
     14 
     15 #include <soc/drv.h>
     16 #include <bcm/vlan.h>
     17 #include <bcm/error.h>
     18 
     19 #include <bcm/l3.h>
     20 #include <soc/l3x.h>
     21 #include <soc/lpm.h>
     22 
     23 #include <soc/tomahawk.h>
     24 #include <bcm/tunnel.h>
     25 #include <bcm/debug.h>
     26 #include <bcm/error.h>
     27 #include <bcm/stack.h>
     28 #include <soc/trident2.h>
     29 #include <soc/defragment.h>
     30 
     31 #include <bcm_int/esw/tomahawk.h>
     32 #include <bcm_int/esw/trident2.h>
     33 #include <bcm_int/esw/firebolt.h>
     34 #include <bcm_int/esw/triumph.h>
     35 #include <bcm_int/esw/triumph2.h>
     36 #include <bcm_int/esw/stack.h>
     37 #include <bcm_int/esw/flex_ctr.h>
     38 #include <bcm_int/esw_dispatch.h>
     39 #include <bcm_int/esw/flex_ctr.h>
     40 #include <bcm_int/esw/virtual.h>
     41 #include <bcm_int/esw/qos.h>
     42 
     43 #if defined(BCM_TRIDENT3_SUPPORT)
     44 #include <bcm_int/esw/trident3.h>
     45 #endif
     46 
     47 #if defined(BCM_TRX_SUPPORT) 
     48 #include <bcm_int/esw/trx.h>
     49 #endif /* BCM_TRX_SUPPORT */
     50 
     51 #define _BCM_TD2_L3_MEM_BANKS_ALL     (-1)
     52 #define _BCM_TD2_HOST_ENTRY_NOT_FOUND (-1)
     53 static soc_profile_mem_t *_bcm_th_macda_oui_profile[BCM_MAX_NUM_UNITS];
     54 static soc_profile_mem_t *_bcm_th_vntag_etag_profile[BCM_MAX_NUM_UNITS];
     55 
     56 
     57 /* IP Options Handling */
     58 #define L3_INFO(_unit_) (&_bcm_l3_bk_info[_unit_])
     59 #define _BCM_IP_OPTION_PROFILE_CHUNK 256
     60 #define _BCM_IP4_OPTIONS_LEN    \
     61             (soc_mem_index_count(unit, IP_OPTION_CONTROL_PROFILE_TABLEm)/ \
     62              _BCM_IP_OPTION_PROFILE_CHUNK)
     63 
     64 /*
     65  * Function:
     66  *      _bcm_th_macda_oui_profile_init
     67  * Purpose:
     68  *      Allocate and initialize _bcm_th_macda_oui_profile_init
     69  * Parameters:
     70  *      unit - (IN)SOC unit number. 
     71  * Returns:
     72  *      BCM_X_XXX
     73  */
     74 bcm_error_t
     75 _bcm_th_macda_oui_profile_init(int unit)
     76 {
     77     soc_mem_t mem_profile;
     78     int entry_words[1];
     79     
     80     /* Create profile for MACDA_OUI_PROFILE table*/
     81     if (_bcm_th_macda_oui_profile[unit] == NULL) {
     82         _bcm_th_macda_oui_profile[unit] = sal_alloc(sizeof(soc_profile_mem_t),
     83                                           "MACDA OUI Profile Mem");
     84         if (_bcm_th_macda_oui_profile[unit] == NULL) {
     85             return BCM_E_MEMORY;
     86         }
     87     } else {
     88         BCM_IF_ERROR_RETURN
     89             (soc_profile_mem_destroy(unit, _bcm_th_macda_oui_profile[unit]));
     90     }
     91     soc_profile_mem_t_init(_bcm_th_macda_oui_profile[unit]);
     92     mem_profile = EGR_MACDA_OUI_PROFILEm;
     93     entry_words[0] = BYTES2WORDS(sizeof(egr_macda_oui_profile_entry_t));
     94     SOC_IF_ERROR_RETURN
     95         (soc_profile_mem_create(unit, &mem_profile, entry_words, 1,
     96                                 _bcm_th_macda_oui_profile[unit]));
     97 
     98     return BCM_E_NONE;
     99 }
    100 
    101 
    102 /*
    103  * Function:
    104  *      _bcm_th_macda_oui_profile_deinit
    105  * Purpose:
    106  *      Deallocate _bcm_th_macda_oui_profile
    107  * Parameters:
    108  *      unit - (IN)SOC unit number. 
    109  * Returns:
    110  *      BCM_X_XXX
    111  */
    112 void
    113 _bcm_th_macda_oui_profile_deinit(int unit)
    114 {
    115     if (_bcm_th_macda_oui_profile[unit]) {
    116         (void)soc_profile_mem_destroy(unit, _bcm_th_macda_oui_profile[unit]);
    117         sal_free(_bcm_th_macda_oui_profile[unit]);
    118         _bcm_th_macda_oui_profile[unit] = NULL;
    119     }
    120 }
    121 
    122 /*
    123  * Function:
    124  *      _bcm_th_vntag_etag_profile_init
    125  * Purpose:
    126  *      Allocate and initialize _bcm_th_vntag_etag_profile
    127  * Parameters:
    128  *      unit - (IN)SOC unit number. 
    129  * Returns:
    130  *      BCM_X_XXX
    131  */
    132 bcm_error_t
    133 _bcm_th_vntag_etag_profile_init(int unit)
    134 {
    135     soc_mem_t mem_profile;
    136     int entry_words[1];
    137     void *entries[1];
    138     uint32 profile_idx;
    139     egr_vntag_etag_profile_entry_t vntag_etag_profile_entry;
    140 
    141     /* Create profile for EGR_VNTAG_ETAG_PROFILE table */
    142     if (_bcm_th_vntag_etag_profile[unit] == NULL) {
    143         _bcm_th_vntag_etag_profile[unit] = sal_alloc(sizeof(soc_profile_mem_t),
    144                                           "EGR VNTAG ETAG Profile Mem");
    145         if (_bcm_th_vntag_etag_profile[unit] == NULL) {
    146             return BCM_E_MEMORY;
    147         }
    148     } else {
    149         BCM_IF_ERROR_RETURN
    150             (soc_profile_mem_destroy(unit, _bcm_th_vntag_etag_profile[unit]));
    151     }
    152     soc_profile_mem_t_init(_bcm_th_vntag_etag_profile[unit]);
    153     mem_profile = EGR_VNTAG_ETAG_PROFILEm;
    154     entry_words[0] = BYTES2WORDS(sizeof(egr_vntag_etag_profile_entry_t));
    155     SOC_IF_ERROR_RETURN
    156         (soc_profile_mem_create(unit, &mem_profile, entry_words, 1,
    157                                 _bcm_th_vntag_etag_profile[unit]));
    158 
    159     /* Index 0 in EGR_VNTAG_ETAG_PROFILE table is reserved for non NIV/PE flow
    160      * hence adding this dummy entry at index 0 during init time
    161      */
    162     sal_memset(&vntag_etag_profile_entry, 0, sizeof(vntag_etag_profile_entry));
    163     entries[0] = &vntag_etag_profile_entry;
    164     BCM_IF_ERROR_RETURN
    165         (soc_profile_mem_add(unit, _bcm_th_vntag_etag_profile[unit],
    166                              entries, 1, &profile_idx));
    167     
    168     return BCM_E_NONE;
    169 }
    170 
    171 
    172 /*
    173  * Function:
    174  *      _bcm_th_vntag_etag_profile_deinit
    175  * Purpose:
    176  *      Deallocate _bcm_th_vntag_etag_profile
    177  * Parameters:
    178  *      unit - (IN)SOC unit number. 
    179  * Returns:
    180  *      BCM_X_XXX
    181  */
    182 void
    183 _bcm_th_vntag_etag_profile_deinit(int unit)
    184 {
    185     if (_bcm_th_vntag_etag_profile[unit]) {
    186         (void)soc_profile_mem_destroy(unit, _bcm_th_vntag_etag_profile[unit]);
    187         sal_free(_bcm_th_vntag_etag_profile[unit]);
    188         _bcm_th_vntag_etag_profile[unit] = NULL;
    189     }
    190 }
    191 
    192 /*
    193  * Function:
    194  *      _bcm_th_l3_vp_entry_del
    195  * Purpose:
    196  *      Delete entry from profile table
    197  * Parameters:
    198  *      unit     - (IN) SOC unit number.
    199  *      ipv6     - (IN) IPV4 or IPv6 flag
    200  *      l3cfg    - (IN) L3 entry info.
    201  *      bufentry - (IN) hw buffer
    202  * Returns:
    203  */
    204 bcm_error_t
    205 _bcm_th_l3_vp_entry_del(int unit, _bcm_l3_cfg_t *l3cfg,
    206                         int macda_oui_profile_index ,int vntag_etag_profile_index)
    207 {
    208 
    209     int rv = BCM_E_NONE;
    210 
    211     if (BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) {
    212         
    213         /* delete an entry or decrement ref count from EGR_MACDA_OUI_PROFILE table */
    214         soc_mem_lock(unit, EGR_MACDA_OUI_PROFILEm);
    215         if (macda_oui_profile_index != -1) {
    216             rv = soc_profile_mem_delete(unit, _bcm_th_macda_oui_profile[unit],
    217                                         macda_oui_profile_index);
    218         }
    219         if (BCM_FAILURE(rv)) {
    220             soc_mem_unlock(unit, EGR_MACDA_OUI_PROFILEm);
    221             return rv;
    222         }
    223         soc_mem_unlock(unit, EGR_MACDA_OUI_PROFILEm);
    224         
    225         /* delete an entry or decrement ref count from EGR_VNTAG_ETAG_PROFILE table */
    226         soc_mem_lock(unit, EGR_VNTAG_ETAG_PROFILEm);
    227         /* profile 0 is reserved for NON NIV/PE entries */
    228         if (vntag_etag_profile_index != 0) {
    229             rv = soc_profile_mem_delete(unit, _bcm_th_vntag_etag_profile[unit],
    230                                         vntag_etag_profile_index);
    231         }
    232         if (BCM_FAILURE(rv)) {
    233             soc_mem_unlock(unit, EGR_VNTAG_ETAG_PROFILEm);
    234             return rv;
    235         }
    236         soc_mem_unlock(unit, EGR_VNTAG_ETAG_PROFILEm);
    237 
    238     }
    239     
    240     return rv;
    241 }
    242 
    243 /*
    244  * Function:
    245  *      _bcm_th_l3_vp_ent_parse
    246  * Purpose:
    247  *      TH helper routine used to parse hw l3 entry to api format
    248  * Parameters:
    249  *      unit      - (IN) SOC unit number. 
    250  *      mem       - (IN) L3 table memory.
    251  *      l3cfg     - (IN) L3 entry info.
    252  *      l3x_entry - (IN) hw buffer.
    253  * Returns:
    254  */
    255 bcm_error_t
    256 _bcm_th_l3_vp_ent_parse(int unit, soc_mem_t mem, _bcm_l3_cfg_t *l3cfg, void *l3x_entry)
    257 {
    258 
    259     uint32 profile_index;
    260     uint32 dst_vif;
    261     uint32 mac_field;
    262     bcm_gport_t vp_gport;
    263     uint32 vntag_actions;
    264     int rv = BCM_E_NONE;
    265     uint32 glp;                   /* Global port.                */
    266     int ipv6;                     /* Entry is IPv6 flag.         */
    267     _bcm_l3_fields_t *fld;        /* L3 table common fields.     */
    268     uint32 *buf_p;                /* HW buffer address.          */
    269     egr_macda_oui_profile_entry_t macda_oui_profile_entry;
    270     egr_vntag_etag_profile_entry_t vntag_etag_profile_entry;
    271     int is_trunk = -1;
    272     uint32 HG_VNTAG_MODIFY_ENABLE_FLAG = 0;
    273 
    274     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
    275     buf_p = (uint32 *)l3x_entry;
    276 
    277     /* Set table fields */
    278     BCM_TD2_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
    279     soc_mem_mac_address_get(unit, mem, buf_p, fld->macda_low, 
    280                             l3cfg->l3c_mac_addr,
    281                             SOC_MEM_MAC_LOWER_ONLY);
    282     /* Read upper 3 bytes of MAC address from profile table */
    283     profile_index = soc_mem_field32_get(unit, mem, buf_p,
    284                                               fld->oui_profile_id);
    285     SOC_IF_ERROR_RETURN
    286         (READ_EGR_MACDA_OUI_PROFILEm(unit, MEM_BLOCK_ANY, profile_index,
    287                                      &macda_oui_profile_entry));
    288     soc_EGR_MACDA_OUI_PROFILEm_field_get(unit, &macda_oui_profile_entry,
    289                                          MACDA_OUIf, &mac_field);
    290     l3cfg->l3c_mac_addr[0] = (uint8) (mac_field >> 16 & 0xff);
    291     l3cfg->l3c_mac_addr[1] = (uint8) (mac_field >> 8 & 0xff);
    292     l3cfg->l3c_mac_addr[2] = (uint8) (mac_field & 0xff);
    293     glp = soc_mem_field32_get(unit, mem, buf_p, fld->glp);
    294     _bcm_th_glp_resolve_embedded_nh(unit, glp, &l3cfg->l3c_modid,
    295                                     &l3cfg->l3c_port_tgid, &is_trunk);
    296 #ifdef BCM_TRIDENT3_SUPPORT
    297     if (SOC_IS_TRIDENT3X(unit)) {
    298         uint32 dest, dtype;
    299         dest = soc_mem_field32_dest_get(unit, mem, buf_p,
    300                 fld->dest, &dtype);
    301         if (dtype == SOC_MEM_FIF_DEST_LAG) {
    302             is_trunk = 1;
    303             l3cfg->l3c_port_tgid = (dest & SOC_MEM_FIF_DGPP_TGID_MASK);
    304         } else if (dtype == SOC_MEM_FIF_DEST_DGPP) {
    305             l3cfg->l3c_port_tgid = (dest & SOC_MEM_FIF_DGPP_PORT_MASK);
    306             l3cfg->l3c_modid = (dest & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >>
    307                 SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS;
    308         }
    309     }
    310 #endif
    311     if (is_trunk == 1) {
    312         l3cfg->l3c_flags |= BCM_L3_TGID;
    313     }
    314     
    315     dst_vif = soc_mem_field32_get(unit, mem, buf_p,
    316                                   fld->dst_vif);
    317     profile_index = soc_mem_field32_get(unit, mem, buf_p,
    318                                         fld->vntag_etag_profile_id);
    319 
    320     if (profile_index != L3_EXT_VIEW_INVALID_VNTAG_ETAG_PROFILE) {
    321         SOC_IF_ERROR_RETURN
    322             (READ_EGR_VNTAG_ETAG_PROFILEm(unit, MEM_BLOCK_ANY, profile_index,
    323                                          &vntag_etag_profile_entry));
    324         soc_EGR_VNTAG_ETAG_PROFILEm_field_get(unit, &vntag_etag_profile_entry,
    325                                               HG_VNTAG_MODIFY_ENABLEf,
    326                                               &HG_VNTAG_MODIFY_ENABLE_FLAG);
    327         l3cfg->l3c_flags2 = HG_VNTAG_MODIFY_ENABLE_FLAG;
    328         soc_EGR_VNTAG_ETAG_PROFILEm_field_get(unit, &vntag_etag_profile_entry,
    329                                               VNTAG_ACTIONSf, &vntag_actions);
    330         switch (vntag_actions) {
    331             case VNTAG_ACTIONS_NIV: /* NIV encap */
    332                 if (_bcm_niv_gport_get(unit, is_trunk, l3cfg->l3c_modid,
    333                                        l3cfg->l3c_port_tgid, dst_vif,
    334                                        &vp_gport) == BCM_E_NONE) {
    335                     l3cfg->l3c_port_tgid = vp_gport;
    336                 }
    337                 break;
    338             case VNTAG_ACTIONS_ETAG: /* PE encap */
    339                 if (_bcm_extender_gport_get(unit, is_trunk, l3cfg->l3c_modid,
    340                                             l3cfg->l3c_port_tgid, dst_vif,
    341                                             &vp_gport) == BCM_E_NONE) {
    342                     l3cfg->l3c_port_tgid = vp_gport;
    343                 }
    344                 break;
    345             default:
    346                 break;
    347         }
    348     }
    349     
    350     return rv;
    351 }
    352 
    353 
    354 /*
    355  * Function:
    356  *      _bcm_th_l3_vp_entry_add
    357  * Purpose:
    358  *      TH helper routine used to parse hw l3 entry to api format
    359  * Parameters:
    360  *      unit      - (IN) SOC unit number. 
    361  *      mem       - (IN) L3 table memory.
    362  *      l3cfg     - (IN) L3 entry info.
    363  *      buf_p     - (IN) hw buffer.
    364  * Returns:
    365  *      BCM_X_XXX
    366  */
    367 bcm_error_t
    368 _bcm_th_l3_vp_entry_add(int unit, soc_mem_t mem, _bcm_l3_cfg_t *l3cfg,
    369                         uint32 *buf_p, int *macda_oui_profile_index,
    370                         int *vntag_etag_profile_index)
    371 {
    372 
    373     int rv = BCM_E_NONE;
    374     int rv1 = BCM_E_NONE;
    375     int ipv6;                     /* Entry is IPv6 flag.         */
    376     _bcm_l3_fields_t *fld;        /* L3 table common fields.     */
    377     uint32 *bufp;                 /* HW buffer address.          */
    378     uint32 profile_idx;
    379     uint32 mac_field;
    380     uint32 vntag_actions;
    381     void *entries[1];
    382     egr_macda_oui_profile_entry_t macda_oui_profile_entry;
    383     egr_vntag_etag_profile_entry_t vntag_etag_profile_entry;
    384 
    385     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
    386     /* Set table fields */
    387     BCM_TD2_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
    388     bufp = buf_p;
    389     
    390     if (soc_feature(unit, soc_feature_virtual_port_routing) &&
    391         (l3cfg->l3c_encap_id > 0 &&
    392          l3cfg->l3c_encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit))) {
    393         int virtual_interface_id;
    394         uint32 hg_vntag_modify = 1;
    395         int count;
    396         if (_bcm_vp_used_get(unit, l3cfg->l3c_encap_id,
    397                              _bcmVpTypeNiv)) { /* NIV */
    398             bcm_niv_port_t niv_port;
    399             bcm_niv_egress_t niv_egress;
    400             BCM_GPORT_NIV_PORT_ID_SET(niv_port.niv_port_id,
    401                                       l3cfg->l3c_encap_id);
    402             BCM_IF_ERROR_RETURN(bcm_esw_niv_port_get(unit, &niv_port));
    403             if (niv_port.flags & BCM_NIV_PORT_MATCH_NONE) {
    404                 BCM_IF_ERROR_RETURN(bcm_esw_niv_egress_get(unit,
    405                                     niv_port.niv_port_id, 1,
    406                                     &niv_egress, &count));
    407                 if (count == 0) {
    408                     return BCM_E_CONFIG;
    409                 }
    410                 if (niv_egress.flags & BCM_NIV_EGRESS_MULTICAST) {
    411                     return BCM_E_PARAM;
    412                 }
    413                 virtual_interface_id = niv_egress.virtual_interface_id;
    414             } else {
    415                 if (niv_port.flags & BCM_NIV_PORT_MULTICAST) {
    416                     return BCM_E_PARAM;
    417                 }
    418                 virtual_interface_id = niv_port.virtual_interface_id;
    419             }
    420             soc_mem_field32_set(unit, mem, bufp, fld->dst_vif,
    421                                 virtual_interface_id);
    422             
    423             sal_memset(&vntag_etag_profile_entry, 0, sizeof(vntag_etag_profile_entry));
    424             vntag_actions = 1;
    425             soc_EGR_VNTAG_ETAG_PROFILEm_field_set(unit, &vntag_etag_profile_entry,
    426                                                   VNTAG_ACTIONSf, &vntag_actions);
    427             if (l3cfg->l3c_flags2 & BCM_L3_FLAGS2_NIV_ENCAP_LOCAL) {
    428                 soc_EGR_VNTAG_ETAG_PROFILEm_field_set(unit, &vntag_etag_profile_entry,
    429                                                       HG_VNTAG_MODIFY_ENABLEf, &hg_vntag_modify);
    430             }
    431             entries[0] = &vntag_etag_profile_entry;
    432             BCM_IF_ERROR_RETURN(soc_profile_mem_add(unit, _bcm_th_vntag_etag_profile[unit],
    433                                                     entries, 1, &profile_idx));
    434             *vntag_etag_profile_index = profile_idx;
    435             soc_mem_field32_set(unit, mem, bufp, fld->vntag_etag_profile_id,
    436                                 profile_idx);
    437         } else if (_bcm_vp_used_get(unit, l3cfg->l3c_encap_id,
    438                                     _bcmVpTypeExtender)) { /* PE */
    439             bcm_extender_port_t ep;
    440             int etag_dot1p_mapping_ptr = 0;
    441             bcm_extender_egress_t extender_egress;
    442             uint16 extended_port_vid;
    443             int qos_map_id;
    444 
    445             BCM_GPORT_EXTENDER_PORT_ID_SET(ep.extender_port_id,
    446                                            l3cfg->l3c_encap_id);
    447             BCM_IF_ERROR_RETURN(bcm_esw_extender_port_get(unit, &ep));
    448             if (ep.flags & BCM_EXTENDER_PORT_MATCH_NONE) {
    449                 bcm_extender_egress_t_init(&extender_egress);
    450                 BCM_IF_ERROR_RETURN(bcm_esw_extender_egress_get_all(unit,
    451                             ep.extender_port_id, 1, &extender_egress, &count));
    452                 if (count == 0) {
    453                     return BCM_E_CONFIG;
    454                 }
    455                 if (extender_egress.flags & BCM_EXTENDER_EGRESS_MULTICAST) {
    456                     return BCM_E_PARAM;
    457                 }
    458                 qos_map_id        = extender_egress.qos_map_id;
    459                 extended_port_vid = extender_egress.extended_port_vid;
    460             } else {
    461                 if (ep.flags & BCM_EXTENDER_PORT_MULTICAST) {
    462                     return BCM_E_PARAM;
    463                 }
    464                 qos_map_id        = ep.qos_map_id;
    465                 extended_port_vid = ep.extended_port_vid;
    466             }
    467 
    468             sal_memset(&vntag_etag_profile_entry, 0, sizeof(vntag_etag_profile_entry));
    469             vntag_actions = 2;
    470             soc_EGR_VNTAG_ETAG_PROFILEm_field_set(unit, &vntag_etag_profile_entry,
    471                                                   VNTAG_ACTIONSf, &vntag_actions);
    472             if (l3cfg->l3c_flags2 & BCM_L3_FLAGS2_NIV_ENCAP_LOCAL) {
    473                 soc_EGR_VNTAG_ETAG_PROFILEm_field_set(unit, &vntag_etag_profile_entry,
    474                                                       HG_VNTAG_MODIFY_ENABLEf, &hg_vntag_modify);
    475             }
    476             bcm_td2_qos_egr_etag_id2profile(unit, qos_map_id,
    477                                             &etag_dot1p_mapping_ptr);
    478             soc_EGR_VNTAG_ETAG_PROFILEm_field_set(unit, &vntag_etag_profile_entry,
    479                                                   ETAG_DOT1P_MAPPING_PTRf,
    480                                                   (uint32 *)&etag_dot1p_mapping_ptr);
    481 
    482             entries[0] = &vntag_etag_profile_entry;
    483             BCM_IF_ERROR_RETURN(soc_profile_mem_add(unit, _bcm_th_vntag_etag_profile[unit],
    484                                                     entries, 1, &profile_idx));
    485             *vntag_etag_profile_index = profile_idx;
    486             soc_mem_field32_set(unit, mem, bufp, fld->vntag_etag_profile_id,
    487                                 profile_idx);
    488             virtual_interface_id = extended_port_vid;
    489             soc_mem_field32_set(unit, mem, bufp, fld->dst_vif, virtual_interface_id);
    490         } else {
    491             return BCM_E_PARAM;
    492         }
    493     } else {
    494         soc_mem_field32_set(unit, mem, bufp, fld->vntag_etag_profile_id,
    495                             L3_EXT_VIEW_INVALID_VNTAG_ETAG_PROFILE);
    496     }
    497     soc_mem_mac_address_set(unit, mem, bufp, fld->macda_low,
    498                             l3cfg->l3c_mac_addr,
    499                             SOC_MEM_MAC_LOWER_ONLY);
    500     mac_field = ((l3cfg->l3c_mac_addr[0] << 16) |
    501                  (l3cfg->l3c_mac_addr[1] << 8)  |
    502                  (l3cfg->l3c_mac_addr[2] << 0));
    503     sal_memset(&macda_oui_profile_entry, 0, sizeof(macda_oui_profile_entry));
    504     soc_EGR_MACDA_OUI_PROFILEm_field_set(unit, &macda_oui_profile_entry,
    505                                          MACDA_OUIf, &mac_field);
    506     entries[0] = &macda_oui_profile_entry;
    507     rv = soc_profile_mem_add(unit, _bcm_th_macda_oui_profile[unit],
    508                              entries, 1, &profile_idx);
    509     if (BCM_FAILURE(rv)) {
    510         /* delete previously added entry or decrement ref count
    511          * from EGR_VNTAG_ETAG_PROFILE table
    512          */
    513         soc_mem_lock(unit, EGR_VNTAG_ETAG_PROFILEm);
    514         /* profile 0 is reserved for NON NIV/PE entries */
    515         if (*vntag_etag_profile_index != 0) {
    516             rv1 = soc_profile_mem_delete(unit, _bcm_th_vntag_etag_profile[unit],
    517                                          *vntag_etag_profile_index);
    518         }
    519         if (BCM_FAILURE(rv1)) {
    520             soc_mem_unlock(unit, EGR_VNTAG_ETAG_PROFILEm);
    521             return rv1;
    522         }
    523         soc_mem_unlock(unit, EGR_VNTAG_ETAG_PROFILEm);
    524         return rv;
    525     }
    526   
    527     *macda_oui_profile_index = profile_idx;
    528     soc_mem_field32_set(unit, mem, bufp, fld->oui_profile_id,
    529                         profile_idx);
    530 
    531 #ifdef BCM_TRIDENT3_SUPPORT
    532     if (SOC_IS_TRIDENT3X(unit)) {
    533         if (BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) {
    534             soc_mem_field32_set(unit, mem, bufp, MACDA_OUI_PROFILE_VALIDf, 1);
    535         }
    536     }
    537 #endif
    538     return rv;
    539 }
    540 
    541 /*
    542  * Function:
    543  *      th_glp_resolve
    544  * Purpose:
    545  *      TH helper routine  function to get modid, port, and trunk_id
    546  *      from a bcm_gport_t
    547  * Parameters  : (IN)  unit      - BCM device number
    548  *               (IN)  gport     - Global port identifier
    549  *               (OUT) modid     - Module ID
    550  *               (OUT) port      - Port number
    551  *               (OUT) is_trunk  - Trunk
    552 
    553  * Returns:
    554  *      BCM_X_XXX
    555  */
    556 
    557 void _bcm_th_glp_resolve_embedded_nh(int unit, uint32 gport,
    558                                      bcm_module_t *modid, bcm_port_t *port,
    559                                      int *is_trunk)
    560 {
    561 
    562     uint8 port_mask_len = 0, modid_mask_len = 0;
    563     uint32 temp = 0;    
    564                
    565     /* Determine length of port mask */
    566     temp = SOC_PORT_ADDR_MAX(unit);
    567     while (0 != temp) {
    568         port_mask_len++;
    569         temp >>= 1;
    570     }
    571     
    572     /* Determine length of modid mask */
    573     temp = SOC_MODID_MAX(unit);
    574     while (0 != temp) {
    575         modid_mask_len++;
    576         temp >>= 1;
    577     }
    578     *modid = (gport >> port_mask_len) & SOC_MODID_MAX(unit);   
    579                   
    580     if (gport & (1 << (port_mask_len + modid_mask_len))) {
    581         *is_trunk = 1;
    582     }
    583     *port = gport & SOC_PORT_ADDR_MAX(unit);
    584 }
    585 
    586 /*
    587  * Function:
    588  *      _bcm_th_l3_ext_ent_init
    589  * Purpose:
    590  *      TH helper routine used to init extended l3 host entry buffer
    591  * Parameters:
    592  *      unit      - (IN) SOC unit number. 
    593  *      mem       - (IN) L3 extended host memory.
    594  *      l3cfg     - (IN/OUT) l3 entry  lookup key & search result.
    595  *      l3x_entry - (IN) hw buffer.
    596  * Returns:
    597  *      void
    598  */
    599 STATIC int
    600 _bcm_th_l3_ext_ent_init(int unit, soc_mem_t mem_ext, 
    601                         _bcm_l3_cfg_t *l3cfg, void *l3x_entry)
    602 {
    603     int ipv6;                     /* Entry is IPv6 flag.         */
    604     uint32 *buf_p;                /* HW buffer address.          */ 
    605 
    606 
    607     /* Get entry type. */
    608     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
    609 
    610     /* Zero destination buffer. */
    611     buf_p = (uint32 *)l3x_entry;
    612     sal_memset(buf_p, 0, BCM_L3_MEM_ENT_SIZE(unit, mem_ext)); 
    613 
    614     if (ipv6) { /* ipv6 entry */
    615         if (BCM_XGS3_L3_MEM(unit, v6_4) == mem_ext) { 
    616             soc_mem_ip6_addr_set(unit, mem_ext, buf_p, IPV6UC_EXT__IP_ADDR_LWR_64f,
    617                                  l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY);
    618             soc_mem_ip6_addr_set(unit, mem_ext, buf_p, IPV6UC_EXT__IP_ADDR_UPR_64f,
    619                                 l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY);
    620             soc_mem_field32_set(unit, mem_ext, buf_p, IPV6UC_EXT__VRF_IDf,
    621                                 l3cfg->l3c_vrf);
    622             /* ipv6 extended host entry */
    623 #ifdef BCM_TRIDENT3_SUPPORT
    624             if (SOC_IS_TRIDENT3X(unit)) {
    625                 soc_mem_field32_set(unit, mem_ext, buf_p, KEY_TYPEf,
    626                                     TD3_L3_HASH_KEY_TYPE_V6UC_EXT);
    627                 soc_mem_field32_set(unit, mem_ext, buf_p, DATA_TYPEf,
    628                                     TD3_L3_HASH_DATA_TYPE_V6UC_EXT);
    629                 soc_mem_field32_set(unit, mem_ext, buf_p, BASE_VALID_0f, 3);
    630                 soc_mem_field32_set(unit, mem_ext, buf_p, BASE_VALID_1f, 4);
    631                 soc_mem_field32_set(unit, mem_ext, buf_p, BASE_VALID_2f, 7);
    632                 soc_mem_field32_set(unit, mem_ext, buf_p, BASE_VALID_3f, 7);
    633             } else
    634 #endif
    635             {
    636                 soc_mem_field32_set(unit, mem_ext, buf_p, KEY_TYPE_0f, 3);
    637                 soc_mem_field32_set(unit, mem_ext, buf_p, KEY_TYPE_1f, 3);
    638                 soc_mem_field32_set(unit, mem_ext, buf_p, KEY_TYPE_2f, 3);
    639                 soc_mem_field32_set(unit, mem_ext, buf_p, KEY_TYPE_3f, 3);
    640 
    641                 soc_mem_field32_set(unit, mem_ext, buf_p, VALID_0f, 1);
    642                 soc_mem_field32_set(unit, mem_ext, buf_p, VALID_1f, 1);
    643                 soc_mem_field32_set(unit, mem_ext, buf_p, VALID_2f, 1);
    644                 soc_mem_field32_set(unit, mem_ext, buf_p, VALID_3f, 1);
    645             }
    646         } else {
    647             return BCM_E_NOT_FOUND;
    648         }
    649     } else { /* ipv4 entry */
    650         if (BCM_XGS3_L3_MEM(unit, v4_2) == mem_ext) { 
    651             soc_mem_field32_set(unit, mem_ext, buf_p, IPV4UC_EXT__IP_ADDRf,
    652                                 l3cfg->l3c_ip_addr);
    653             soc_mem_field32_set(unit, mem_ext, buf_p, IPV4UC_EXT__VRF_IDf,
    654                                 l3cfg->l3c_vrf);
    655             /* ipv4 extended host entry */
    656 #ifdef BCM_TRIDENT3_SUPPORT
    657             if (SOC_IS_TRIDENT3X(unit)) {
    658                 soc_mem_field32_set(unit, mem_ext, buf_p, KEY_TYPEf,
    659                                     TD3_L3_HASH_KEY_TYPE_V4UC_EXT);
    660                 soc_mem_field32_set(unit, mem_ext, buf_p, DATA_TYPEf,
    661                                     TD3_L3_HASH_DATA_TYPE_V4UC_EXT);
    662                 soc_mem_field32_set(unit, mem_ext, buf_p, BASE_VALID_0f, 1);
    663                 soc_mem_field32_set(unit, mem_ext, buf_p, BASE_VALID_1f, 7);
    664             } else
    665 #endif
    666             {
    667                 soc_mem_field32_set(unit, mem_ext, buf_p, KEY_TYPE_0f, 1);
    668                 soc_mem_field32_set(unit, mem_ext, buf_p, KEY_TYPE_1f, 1);
    669                 soc_mem_field32_set(unit, mem_ext, buf_p, VALID_1f, 1);
    670                 soc_mem_field32_set(unit, mem_ext, buf_p, VALID_0f, 1);
    671             }
    672         } else {
    673             return BCM_E_NOT_FOUND;
    674         }
    675     }
    676     return BCM_E_NONE;
    677     
    678 }
    679 
    680 /*
    681  * Function:
    682  *      _bcm_th_l3_ent_init
    683  * Purpose:
    684  *      TH helper routine used to init l3 host entry buffer
    685  * Parameters:
    686  *      unit      - (IN) SOC unit number. 
    687  *      mem       - (IN) L3 host memory.
    688  *      l3cfg     - (IN/OUT) l3 entry  lookup key & search result.
    689  *      l3x_entry - (IN) hw buffer.
    690  * Returns:
    691  *      void
    692  */
    693 STATIC int
    694 _bcm_th_l3_ent_init(int unit, soc_mem_t mem, 
    695                     _bcm_l3_cfg_t *l3cfg, void *l3x_entry)
    696 {
    697     int ipv6;                     /* Entry is IPv6 flag.         */
    698     uint32 *buf_p;                /* HW buffer address.          */ 
    699 
    700 
    701     /* Get entry type. */
    702     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
    703 
    704     /* Zero destination buffer. */
    705     buf_p = (uint32 *)l3x_entry;
    706     sal_memset(buf_p, 0, BCM_L3_MEM_ENT_SIZE(unit, mem)); 
    707 
    708     if (ipv6) { /* ipv6 entry */
    709         if (BCM_XGS3_L3_MEM(unit, v6) == mem) {
    710             soc_mem_field32_set(unit, mem, buf_p, VRF_IDf,
    711                                 l3cfg->l3c_vrf);
    712 #ifdef BCM_TRIDENT3_SUPPORT
    713             if (SOC_IS_TRIDENT3X(unit)) {
    714                 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6UC__IP_ADDR_LWR_64f,
    715                                      l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY);
    716                 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6UC__IP_ADDR_UPR_64f,
    717                                      l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY);
    718                 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf, 2);
    719                 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_0f, 3);
    720                 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_1f, 4);
    721             } else
    722 #endif
    723             {
    724                 soc_mem_ip6_addr_set(unit, mem, buf_p, IP_ADDR_LWR_64f,
    725                                      l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY);
    726                 soc_mem_ip6_addr_set(unit, mem, buf_p, IP_ADDR_UPR_64f,
    727                                      l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY);
    728                 soc_mem_field32_set(unit, mem, buf_p, VALID_0f, 1);
    729                 soc_mem_field32_set(unit, mem, buf_p, VALID_1f, 1);
    730                 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_0f, 2);
    731                 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_1f, 2);
    732             }
    733         } else {
    734             return BCM_E_NOT_FOUND;
    735         }
    736     } else { /* ipv4 entry */
    737         if (BCM_XGS3_L3_MEM(unit, v4) == mem) {
    738             soc_mem_field32_set(unit, mem, buf_p, IP_ADDRf,
    739                                 l3cfg->l3c_ip_addr);
    740             soc_mem_field32_set(unit, mem, buf_p, VRF_IDf,
    741                                 l3cfg->l3c_vrf);
    742             /* ipv4 unicast */
    743             soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf, 0); 
    744 #ifdef BCM_TRIDENT3_SUPPORT
    745             if (SOC_IS_TRIDENT3X(unit)) {
    746                 soc_mem_field32_set(unit, mem, buf_p, BASE_VALIDf, 1);
    747             } else
    748 #endif
    749             {
    750                 soc_mem_field32_set(unit, mem, buf_p, VALIDf, 1);
    751             }
    752         } else {
    753             return BCM_E_NOT_FOUND;
    754         }
    755     }
    756     return BCM_E_NONE;
    757     
    758 }
    759 
    760 /*
    761  * Function:
    762  *      _bcm_th_get_extended_profile_index
    763  * Purpose:
    764  *      TH helper routine used to get profile index for EGR_MACDA_OUI_PROFILE
    765  *      and EGR_VNTAG_ETAG_PROFILE
    766  * Parameters:
    767  *      unit                      - (IN) SOC unit number. 
    768  *      mem                       - (IN) L3 Extended table memory.
    769  *      l3cfg                     - (IN) L3 entry info.
    770  *      macda_oui_profile_index   - (out) EGR_MACDA_OUI profile index.
    771  *      vntag_etag_profile_index  - (out) EGR_VNTAG_ETAG profile index.
    772  * Returns:
    773  *      BCM_X_XXX
    774  */
    775 bcm_error_t _bcm_th_get_extended_profile_index(int unit, soc_mem_t mem_ext,
    776                                                _bcm_l3_cfg_t *l3cfg,
    777                                                int *macda_oui_profile_index,
    778                                                int *vntag_etag_profile_index,
    779                                                int *ref_count) {
    780                                         
    781     int ipv6;                          /* IPv6 entry indicator.*/
    782     int rv = BCM_E_NONE;               /* Operation return status. */
    783     uint32 *buf_key, *buf_entry;       /* Key and entry buffer ptrs*/
    784     l3_entry_ipv4_unicast_entry_t l3v4_key, l3v4_entry;            /* IPv4 */
    785     l3_entry_ipv4_multicast_entry_t l3v4_ext_key, l3v4_ext_entry; /* IPv4-Embedded */
    786     l3_entry_ipv6_unicast_entry_t l3v6_key, l3v6_entry;           /* IPv6 */
    787     l3_entry_ipv6_multicast_entry_t l3v6_ext_key, l3v6_ext_entry; /* IPv6-Embedded */
    788     soc_field_t macda_oui_id, vntag_etag_id;
    789     soc_mem_t mem;
    790    
    791 
    792     /* Get entry type. */
    793     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
    794     
    795     if (ipv6) {
    796 #ifdef BCM_TRIDENT3_SUPPORT
    797         if (SOC_IS_TRIDENT3X(unit)) {
    798             macda_oui_id  = IPV6UC_EXT__MACDA_OUI_PROFILE_INDEXf;
    799         } else
    800 #endif
    801         {
    802             macda_oui_id  = IPV6UC_EXT__MAC_DA_OUI_PROFILE_IDf;
    803         }
    804         vntag_etag_id = IPV6UC_EXT__VNTAG_ETAG_PROFILE_IDf;
    805         mem = BCM_XGS3_L3_MEM(unit, v6);
    806     } else {
    807 #ifdef BCM_TRIDENT3_SUPPORT
    808         if (SOC_IS_TRIDENT3X(unit)) {
    809             macda_oui_id  = IPV4UC_EXT__MACDA_OUI_PROFILE_INDEXf;
    810         } else
    811 #endif
    812         {
    813             macda_oui_id  = IPV4UC_EXT__MAC_DA_OUI_PROFILE_IDf;
    814         }
    815         vntag_etag_id = IPV4UC_EXT__VNTAG_ETAG_PROFILE_IDf;
    816         mem = BCM_XGS3_L3_MEM(unit, v4);
    817     }
    818 
    819     /* Assign entry-key buf based on table being used */
    820     BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_key,
    821                               l3v4_key,
    822                               l3v4_ext_key,
    823                               l3v6_key,
    824                               l3v6_ext_key);
    825 
    826     /* Assign entry buf based on table being used */
    827     BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_entry,
    828                               l3v4_entry,
    829                               l3v4_ext_entry,
    830                               l3v6_entry,
    831                               l3v6_ext_entry);
    832 
    833     /* Prepare lookup key. */
    834     BCM_IF_ERROR_RETURN
    835     (_bcm_th_l3_ext_ent_init(unit, mem_ext, l3cfg, buf_key));
    836 
    837     /* Perform lookup hw. */
    838     rv = soc_mem_generic_lookup(unit, mem_ext, MEM_BLOCK_ANY,
    839                                 _BCM_TD2_L3_MEM_BANKS_ALL,
    840                                 buf_key, buf_entry, &l3cfg->l3c_hw_index);
    841     if (BCM_SUCCESS(rv)) {
    842         *macda_oui_profile_index = soc_mem_field32_get(unit, mem_ext, buf_entry,
    843                                                        macda_oui_id);
    844         *vntag_etag_profile_index = soc_mem_field32_get(unit, mem_ext, buf_entry,
    845                                                         vntag_etag_id);
    846         rv = soc_profile_mem_ref_count_get(unit, 
    847                                            _bcm_th_macda_oui_profile[unit],
    848                                            *macda_oui_profile_index,
    849                                            ref_count);
    850         return rv;
    851     } else if (BCM_E_NOT_FOUND == rv) {
    852         /* Check if entry was added in regular L3_ENTRY table view */
    853 
    854         /* Assign entry-key buf based on table being used */
    855         BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem, buf_key,
    856                                   l3v4_key,
    857                                   l3v4_ext_key,
    858                                   l3v6_key,
    859                                   l3v6_ext_key);
    860 
    861         /* Assign entry buf based on table being used */
    862         BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry,
    863                                   l3v4_entry,
    864                                   l3v4_ext_entry,
    865                                   l3v6_entry,
    866                                   l3v6_ext_entry);
    867         
    868         /* Prepare lookup key. */
    869         BCM_IF_ERROR_RETURN(_bcm_th_l3_ent_init(unit, mem, l3cfg, buf_key));
    870 
    871         /* Perform lookup */
    872         rv = soc_mem_generic_lookup(unit, mem, MEM_BLOCK_ANY,
    873                                     _BCM_TD2_L3_MEM_BANKS_ALL,
    874                                     buf_key, buf_entry, &l3cfg->l3c_hw_index);
    875         return rv;
    876     }
    877 
    878     return rv;
    879    
    880 }
    881 
    882 /*
    883  * Function:
    884  *      _bcm_th_l3_ecmp_across_layers_move
    885  * Purpose:
    886  *      Move ecmp entries (which have no flags - BCM_L3_ECMP_UNDERLAY/OVERLAY)
    887  *      across two layers
    888  * Parameters:
    889  *      unit      - (IN) SOC unit number.
    890  *      threshold - (IN) Move threshold.
    891  *      direction - (IN) Move direction (0: L2 -> L1, 1: L1 -> L2).
    892  * Returns:
    893  *      BCM_E_XXX.
    894  */
    895 int
    896 _bcm_th_l3_ecmp_across_layers_move(int unit, int threshold, int direction)
    897 {
    898     int rv = BCM_E_NONE;
    899     int idx_min = 0;
    900     int idx_max = 0;
    901     int i = 0;
    902     int idx_increment = 0;
    903     int max_paths = 0;
    904     int base_ptr = 0;
    905     int boundary = 0;
    906     int old_ecmp_tbl_idx_min = 0;
    907     int old_ecmp_tbl_idx_max = 0;
    908     int move_width = 0;
    909     _bcm_l3_tbl_op_t data;
    910     _bcm_l3_tbl_t *ecmp_group_tbl_ptr = NULL;
    911     _bcm_l3_tbl_t *ecmp_tbl_ptr = NULL;
    912     ecmp_count_entry_t *ecmp_group_entry = NULL;
    913     uint8 *ecmp_group_buf = NULL;
    914     soc_defragment_member_op_t member_op;
    915     soc_defragment_group_op_t group_op;
    916 
    917     ecmp_group_tbl_ptr   = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
    918     ecmp_tbl_ptr         = BCM_XGS3_L3_TBL_PTR(unit, ecmp);
    919     old_ecmp_tbl_idx_max = ecmp_tbl_ptr->idx_max;
    920     old_ecmp_tbl_idx_min = ecmp_tbl_ptr->idx_min;
    921     if (direction) {
    922         /* direction: L1 -> L2, try to get free index in L2 */
    923         ecmp_tbl_ptr->idx_max = soc_mem_index_count(unit, L3_ECMPm) - 1;
    924         ecmp_tbl_ptr->idx_min = soc_mem_index_count(unit, L3_ECMPm) / 2;
    925     } else {
    926         /* direction: L2 -> L1, try to get free index in L1 */
    927         ecmp_tbl_ptr->idx_max = soc_mem_index_count(unit, L3_ECMPm) / 2 - 1;
    928         ecmp_tbl_ptr->idx_min = soc_mem_index_min(unit, L3_ECMPm);
    929     }
    930 
    931     sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t));
    932     data.tbl_ptr     = ecmp_tbl_ptr;
    933     data.oper_flags  = _BCM_L3_SHR_TABLE_TRAVERSE_CONTROL;
    934     data.entry_index = -1;
    935 
    936     member_op.member_copy = _bcm_tr2_l3_ecmp_member_copy;
    937     member_op.member_clear = _bcm_tr2_l3_ecmp_member_clear;
    938     group_op.group_base_ptr_update = _bcm_tr2_l3_ecmp_group_base_ptr_update;
    939 
    940     boundary = soc_mem_index_count(unit, L3_ECMPm) / 2;
    941 
    942     /*
    943      * Max_Ecmp_Group  : TH 2K   TH2 4K
    944      * Max_Ecmp_Member : TH 16K  TH2 32K
    945      *
    946      * Combination_1 for ecmp_group_flags with 0 :
    947      *                   Group Index  [0 ~ Max_Ecmp_Group / 2 - 1]
    948      *                   Member Index [0 ~ Max_Ecmp_Member - 1]
    949      *
    950      * Combination_2 for ecmp_group_flags with 0 :
    951      *                   Group Index  [Max_Ecmp_Group / 2 ~ Max_Ecmp_Group - 1]
    952      *                   Member Index [Max_Ecmp_Member /2 ~ Max_Ecmp_Member - 1]
    953      *
    954      * So only can move ecmp members of the groups [0 ~ Max_Ecmp_Group / 2 - 1]
    955      * across layers
    956      */
    957     idx_min = soc_mem_index_min(unit, L3_ECMP_COUNTm);
    958     idx_max = soc_mem_index_count(unit, L3_ECMP_COUNTm) / 2 - 1;
    959 
    960     ecmp_group_buf =
    961         soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, L3_ECMP_COUNTm),
    962                       "L3_ECMP_COUNT buffer");
    963     if (NULL == ecmp_group_buf) {
    964         goto clean_up;
    965     }
    966 
    967     rv = soc_mem_read_range(unit, L3_ECMP_COUNTm, MEM_BLOCK_ANY,
    968                             idx_min, idx_max, ecmp_group_buf);
    969     if (SOC_FAILURE(rv)) {
    970         goto clean_up;
    971     }
    972 
    973     idx_increment = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
    974                         _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
    975 
    976     for (i = idx_min; i <= idx_max; i += idx_increment) {
    977         if (soc_feature(unit, soc_feature_vp_lag)) {
    978             /* Skip VP LAG entries */
    979             int is_vp_lag, is_used, has_member;
    980             rv = bcm_td2_vp_lag_status_get(
    981                      unit, i, &is_vp_lag, &is_used, &has_member);
    982             if (BCM_FAILURE(rv)) {
    983                 goto clean_up;
    984             }
    985             if (is_vp_lag) {
    986                 continue;
    987             }
    988         }
    989 
    990         if (!BCM_XGS3_L3_ENT_REF_CNT(ecmp_group_tbl_ptr, i)) {
    991             /* Skip unused entries */
    992             continue;
    993         }
    994 
    995         if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, i, BCM_L3_ECMP_OVERLAY) ||
    996             BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, i, BCM_L3_ECMP_UNDERLAY)) {
    997             /* Skip entries which have BCM_L3_ECMP_OVERLAY/OVERLAY flags */
    998             continue;
    999         }
   1000 
   1001         ecmp_group_entry = soc_mem_table_idx_to_pointer(unit, L3_ECMP_COUNTm,
   1002                                                         ecmp_count_entry_t *,
   1003                                                         ecmp_group_buf, i);
   1004         base_ptr =
   1005             soc_L3_ECMP_COUNTm_field32_get(unit, ecmp_group_entry, BASE_PTRf);
   1006         rv = bcm_xgs3_l3_egress_ecmp_max_paths_get(
   1007                  unit, i + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit), NULL, &max_paths);
   1008         if (BCM_FAILURE(rv)) {
   1009             goto clean_up;
   1010         }
   1011 
   1012         if (((1 == direction) && (base_ptr < boundary)) ||
   1013             ((0 == direction) && (base_ptr >= boundary))) {
   1014 
   1015             data.width = max_paths;
   1016             rv = _bcm_xgs3_tbl_free_idx_get(unit, &data);
   1017             if (BCM_SUCCESS(rv)) {
   1018                 rv = soc_defragment_block_move(unit, base_ptr,
   1019                                                data.entry_index, max_paths,
   1020                                                &member_op, i, &group_op);
   1021                 if (BCM_FAILURE(rv)) {
   1022                     goto clean_up;
   1023                 }
   1024 
   1025                 move_width += max_paths;
   1026                 if (move_width >= threshold) {
   1027                     break;
   1028                 }
   1029             }
   1030         }
   1031     }
   1032 
   1033     rv = BCM_E_NONE;
   1034 
   1035 clean_up:
   1036 
   1037     if (NULL != ecmp_group_buf) {
   1038         soc_cm_sfree(unit, ecmp_group_buf);
   1039     }
   1040 
   1041     ecmp_tbl_ptr->idx_max = old_ecmp_tbl_idx_max;
   1042     ecmp_tbl_ptr->idx_min = old_ecmp_tbl_idx_min;
   1043 
   1044     return rv;
   1045 }
   1046 
   1047 /*
   1048  * Function:
   1049  *      bcm_th_l3_extended_required_scache_size_get
   1050  * Purpose:
   1051  *      Get required NIV module scache size for Level 2 Warm Boot in Tomahawk
   1052  *      L3_ENTRY extended view
   1053  * Parameters:
   1054  *      unit - StrataSwitch unit number.
   1055  *      size - (OUT) Required scache size.
   1056  */
   1057 void
   1058 bcm_th_l3_extended_required_scache_size_get(int unit, int *size)
   1059 {
   1060 
   1061     if (BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) {
   1062         /* Sync the ref_count of EGR_MACDA_OUI_PROFILEm */
   1063         *size += SOC_MEM_SIZE(unit, EGR_MACDA_OUI_PROFILEm) * sizeof(uint32);
   1064     
   1065         /* Sync the ref_count of EGR_VNTAG_ETAG_PROFILEm */
   1066         *size += SOC_MEM_SIZE(unit, EGR_VNTAG_ETAG_PROFILEm) * sizeof(uint32);
   1067     }
   1068 }
   1069 
   1070 /*
   1071  * Function:
   1072  *      soc_profile_th_mem_ref_count_get
   1073  * Purpose:
   1074  *      Get the reference count of the cached entry at the specified index.
   1075  *
   1076  * Parameters:
   1077  *      unit        - (IN) Unit
   1078  *      profile     - (IN) Pointer to profile memory structure
   1079  *      index0      - (IN) Base index to the entries in HW for table 0
   1080  *      ref_count   - (OUT) Reference count
   1081  * Returns:
   1082  *      SOC_E_XXX
   1083  */
   1084 static soc_error_t
   1085 soc_profile_th_mem_ref_count_get(int unit,
   1086                                  soc_profile_mem_t *profile,
   1087                                  int index0,
   1088                                  uint32 *ref_count)
   1089 {
   1090     soc_profile_mem_table_t *table;
   1091     int base0;
   1092 
   1093     if (profile == NULL || ref_count == NULL) {
   1094         return SOC_E_PARAM;
   1095     }
   1096 
   1097     if (profile->tables == NULL || profile->table_count == 0) {
   1098         return SOC_E_INIT;
   1099     }
   1100 
   1101     table = &profile->tables[0];
   1102     if (index0 < table->index_min || index0 > table->index_max) {
   1103         return SOC_E_PARAM;
   1104     }
   1105 
   1106     base0 = index0 - table->index_min;
   1107 
   1108     *ref_count = table->entries[base0].ref_count;
   1109 
   1110     return SOC_E_NONE;
   1111 }
   1112 
   1113 /*
   1114  * Function:
   1115  *      bcm_th_l3_extended_view_sync
   1116  * Purpose:
   1117  *      Record persistent info into the scache for the TH NIV software module 
   1118  *      for L3_ENTRY extended view.
   1119  * Parameters:
   1120  *      unit - StrataSwitch unit #
   1121  *      scache_ptr - (IN/OUT) Scache pointer
   1122  * Returns:
   1123  *      BCM_E_xxx
   1124  */
   1125 bcm_error_t
   1126 bcm_th_l3_extended_view_sync(int unit, uint8 **scache_ptr)
   1127 {
   1128     int rv = BCM_E_NONE;
   1129     int i;
   1130     uint32 ref_count;
   1131 
   1132     if (!BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) {
   1133         return rv;
   1134     }
   1135     
   1136     if ((scache_ptr == NULL) || (*scache_ptr == NULL)) {
   1137         return BCM_E_PARAM;
   1138     }
   1139 
   1140     /* Record EGR_MACDA_OUI_PROFILEm ref_count in scache */
   1141     for (i = 0; i < SOC_MEM_SIZE(unit, EGR_MACDA_OUI_PROFILEm); i++) {
   1142         /* Generic profile library has a routine which takes ref_count as
   1143          * int. However, MACDA_OUI_PROFILE table can have ref_count exceeding
   1144          * int max value. Below routine takes ref_count as uint32 for TH
   1145          */
   1146         rv = soc_profile_th_mem_ref_count_get(unit,
   1147                                               _bcm_th_macda_oui_profile[unit],
   1148                                               i,
   1149                                               &ref_count);
   1150         if (!(rv == SOC_E_NONE)) {
   1151             return rv;
   1152         }
   1153         
   1154         sal_memcpy((*scache_ptr), &ref_count, sizeof(uint32));
   1155         (*scache_ptr) += sizeof(ref_count);
   1156     }
   1157 
   1158     /* Record EGR_VNTAG_ETAG_PROFILEm ref_count in scache */
   1159     for (i = 0; i < SOC_MEM_SIZE(unit, EGR_VNTAG_ETAG_PROFILEm); i++) {
   1160         rv = soc_profile_th_mem_ref_count_get(unit,
   1161                                               _bcm_th_vntag_etag_profile[unit],
   1162                                               i,
   1163                                               &ref_count);
   1164         if (!(rv == SOC_E_NONE)) {
   1165             return rv;
   1166         }
   1167         
   1168         sal_memcpy((*scache_ptr), &ref_count, sizeof(uint32));
   1169         (*scache_ptr) += sizeof(ref_count);
   1170     }
   1171 
   1172     return rv;
   1173 }
   1174 
   1175 /*
   1176  * Function:
   1177  *      bcm_th_l3_extended_view_reinit
   1178  * Purpose:
   1179  *      Warm boot recovery for the TH NIV software module for L3_ENTRY 
   1180  *      extended view
   1181  * Parameters:
   1182  *      unit - Device Number
   1183  *      defaul_ver - Warm boot default version
   1184  * Returns:
   1185  *      BCM_E_XXX
   1186  */
   1187 bcm_error_t
   1188 bcm_th_l3_extended_view_reinit(int unit, uint8 **scache_ptr)
   1189 {
   1190     int rv = BCM_E_NONE;
   1191     soc_profile_mem_t *profile_mem;
   1192     int i, j, size;
   1193     uint32 ref_count;
   1194 
   1195     if (!BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) {
   1196         return rv;
   1197     }
   1198 
   1199     if ((scache_ptr == NULL) || (*scache_ptr == NULL)) {
   1200         return BCM_E_PARAM;
   1201     }
   1202 
   1203     /* Update EGR_MACDA_OUI_PROFILE memory profile reference counter */
   1204     profile_mem = _bcm_th_macda_oui_profile[unit];
   1205     size = SOC_MEM_SIZE(unit, EGR_MACDA_OUI_PROFILEm);
   1206     for (i = 0; i < size; i++) {
   1207         sal_memcpy(&ref_count, (*scache_ptr), sizeof(uint32));
   1208         (*scache_ptr) += sizeof(ref_count);
   1209         for (j = 0; j < ref_count; j++) {
   1210             SOC_IF_ERROR_RETURN(
   1211             soc_profile_mem_reference(unit, profile_mem, i, 1));
   1212         }
   1213     }
   1214 
   1215     /* Update EGR_VNTAG_ETAG_PROFILE memory profile reference counter */
   1216     profile_mem = _bcm_th_vntag_etag_profile[unit];
   1217     size = SOC_MEM_SIZE(unit, EGR_VNTAG_ETAG_PROFILEm);
   1218     for (i = 0; i < size; i++) {
   1219         sal_memcpy(&ref_count, (*scache_ptr), sizeof(uint32));
   1220         (*scache_ptr) += sizeof(ref_count);
   1221         for (j = 0; j < ref_count; j++) {
   1222             SOC_IF_ERROR_RETURN(
   1223             soc_profile_mem_reference(unit, profile_mem, i, 1));
   1224         }
   1225     }
   1226     
   1227     return rv;
   1228 }
   1229 
   1230 #endif
   1231