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

mpls.c (236611B)


      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:    mpls.c
      8  * Purpose: Manages Tomahawk, TD2+ MPLS functions
      9  */
     10 #include <shared/bsl.h>
     11 
     12 #include <soc/defs.h>
     13 #include <sal/core/libc.h>
     14 #include <shared/bsl.h>
     15 
     16 #ifdef INCLUDE_L3
     17 #ifdef BCM_MPLS_SUPPORT
     18 #if (defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_TRIDENT2PLUS_SUPPORT))
     19 
     20 #include <soc/drv.h>
     21 #include <soc/hash.h>
     22 #include <soc/mem.h>
     23 #include <soc/util.h>
     24 #include <soc/debug.h>
     25 #include <soc/triumph.h>
     26 #include <soc/format.h>
     27 
     28 #include <bcm/error.h>
     29 #include <bcm/mpls.h>
     30 
     31 #include <bcm_int/esw/mbcm.h>
     32 #include <bcm_int/esw/l3.h>
     33 #include <bcm_int/esw/firebolt.h>
     34 #include <bcm_int/esw/tomahawk.h>
     35 #include <bcm_int/esw/triumph3.h>
     36 #include <bcm_int/esw/trident2plus.h>
     37 #include <bcm_int/esw/triumph.h>
     38 #include <bcm_int/esw/triumph2.h>
     39 #include <bcm_int/esw/trx.h>
     40 #include <bcm_int/esw/xgs3.h>
     41 #include <bcm_int/esw/xgs5.h>
     42 #include <bcm_int/esw/mpls.h>
     43 #include <bcm_int/esw/stack.h>
     44 #include <bcm_int/common/multicast.h>
     45 #include <bcm_int/esw/virtual.h>
     46 #include <bcm_int/esw/port.h>
     47 #include <bcm_int/esw/ecn.h>
     48 #include <bcm_int/esw_dispatch.h>
     49 #include <bcm_int/api_xlate_port.h>
     50 #include <bcm_int/esw/failover.h>
     51 #ifdef BCM_TOMAHAWK2_SUPPORT
     52 #include <bcm_int/esw/tomahawk2.h>
     53 #endif
     54 #ifdef BCM_TOMAHAWK3_SUPPORT
     55 #include <bcm_int/esw/tomahawk3.h>
     56 #endif
     57 #ifdef BCM_TRIDENT3_SUPPORT
     58 #include <soc/esw/cancun.h>
     59 #include <soc/esw/cancun_enums.h>
     60 #endif /* BCM_TRIDENT3_SUPPORT */
     61 
     62 #define MPLS_INFO(_unit_)   (&_bcm_tr_mpls_bk_info[_unit_])
     63 #define L3_INFO(_unit_)   (&_bcm_l3_bk_info[_unit_])
     64 
     65 #define bcmi_mpls_bookkeeping_t  _bcm_tr_mpls_bookkeeping_t
     66 
     67 bcmi_egr_ip_tnl_mpls_tunnel_entry_t **egr_mpls_tnl_sw_state[BCM_MAX_NUM_UNITS];
     68 bcmi_egr_ip_tnl_free_indexes_t fi_db[BCM_MAX_NUM_UNITS];
     69 
     70 STATIC int
     71 _bcmi_xgs5_mpls_entry_set_key(int unit, bcm_mpls_tunnel_switch_t *info,
     72                               mpls_entry_entry_t *ment);
     73 
     74 /*
     75 TD3 MPLS_ENTRY_X FORMAT:
     76 ----------------------------------------------------------------------------------------------------------
     77 | MPLS_LABEL(0:19)                  | MPLS_PUSH_ACTION(20:21)          | MPLS_EXP_SELECT(22:23)           |
     78 ----------------------------------------------------------------------------------------------------------|
     79 | MPLS_EXP_MAPPING_PTR(24:27)       | NEW_CFI(24:24)                   | NEW_PRI(25:27)                   |
     80 ----------------------------------------------------------------------------------------------------------|
     81 | MPLS_EXP(30:28)                   | LABEL_SELECT(31:31)              | MPLS_TTL(32:39)                  |
     82 ----------------------------------------------------------------------------------------------------------|
     83 | SPECIAL_LABEL_PUSH_TYPE(40:41)    | EXP_MAPPING_TABLE_SELECT(42:43)  | PKT_ECN_TO_EXP_MAPPING_PTR(44:45)|
     84 ----------------------------------------------------------------------------------------------------------|
     85 | PKT_ECN_TO_EXP_PRIORITY(46:46)    | EGR_FLEX_CTR_ACTION_SET(47:65)   | FLEX_CTR_BASE_COUNTER_IDX(47:59) |
     86 ----------------------------------------------------------------------------------------------------------|
     87 | FLEX_CTR_POOL_NUMBER(60:61)       | RSVD_FLEX_CTR_POOL_NUMBER(62:63) | FLEX_CTR_OFFSET_MODE(61:65)      |
     88 ----------------------------------------------------------------------------------------------------------|
     89 | ECN_MAPPING_ENABLE(66:66)         | ECN_MAPPING_TABLE_SELECT(67:68)  | RESERVED(69:70)                  |
     90 ----------------------------------------------------------------------------------------------------------
     91 */
     92 #ifdef BCM_TRIDENT3_SUPPORT
     93 static soc_field_t _tnl_label_entry_f[] =
     94 { MPLS_ENTRY_0f, MPLS_ENTRY_1f, MPLS_ENTRY_2f, MPLS_ENTRY_3f,
     95   MPLS_ENTRY_4f, MPLS_ENTRY_5f, MPLS_ENTRY_6f, MPLS_ENTRY_7f };
     96 #endif
     97 
     98 static soc_field_t _tnl_label_f[] =
     99 { MPLS_LABEL_0f, MPLS_LABEL_1f, MPLS_LABEL_2f, MPLS_LABEL_3f,
    100   MPLS_LABEL_4f, MPLS_LABEL_5f, MPLS_LABEL_6f, MPLS_LABEL_7f };
    101 static soc_field_t _tnl_push_action_f[] =
    102 { MPLS_PUSH_ACTION_0f, MPLS_PUSH_ACTION_1f,
    103   MPLS_PUSH_ACTION_2f, MPLS_PUSH_ACTION_3f,
    104   MPLS_PUSH_ACTION_4f, MPLS_PUSH_ACTION_5f,
    105   MPLS_PUSH_ACTION_6f, MPLS_PUSH_ACTION_7f };
    106 static soc_field_t _tnl_exp_select_f[] =
    107 { MPLS_EXP_SELECT_0f, MPLS_EXP_SELECT_1f,
    108   MPLS_EXP_SELECT_2f, MPLS_EXP_SELECT_3f,
    109   MPLS_EXP_SELECT_4f, MPLS_EXP_SELECT_5f,
    110   MPLS_EXP_SELECT_6f, MPLS_EXP_SELECT_7f };
    111 static soc_field_t _tnl_exp_ptr_f[] =
    112 { MPLS_EXP_MAPPING_PTR_0f, MPLS_EXP_MAPPING_PTR_1f,
    113   MPLS_EXP_MAPPING_PTR_2f, MPLS_EXP_MAPPING_PTR_3f,
    114   MPLS_EXP_MAPPING_PTR_4f, MPLS_EXP_MAPPING_PTR_5f,
    115   MPLS_EXP_MAPPING_PTR_6f, MPLS_EXP_MAPPING_PTR_7f };
    116 static soc_field_t _tnl_exp_f[] =
    117 { MPLS_EXP_0f, MPLS_EXP_1f, MPLS_EXP_2f, MPLS_EXP_3f,
    118   MPLS_EXP_4f, MPLS_EXP_5f, MPLS_EXP_6f, MPLS_EXP_7f };
    119 static soc_field_t _tnl_ttl_f[] =
    120 { MPLS_TTL_0f, MPLS_TTL_1f, MPLS_TTL_2f, MPLS_TTL_3f,
    121   MPLS_TTL_4f, MPLS_TTL_5f, MPLS_TTL_6f, MPLS_TTL_7f };
    122 static soc_field_t _tnl_pri_f[] =
    123 { NEW_PRI_0f, NEW_PRI_1f, NEW_PRI_2f, NEW_PRI_3f,
    124   NEW_PRI_4f, NEW_PRI_5f, NEW_PRI_6f, NEW_PRI_7f };
    125 static soc_field_t _tnl_cfi_f[] =
    126 { NEW_CFI_0f, NEW_CFI_1f, NEW_CFI_2f, NEW_CFI_3f,
    127   NEW_CFI_4f, NEW_CFI_5f, NEW_CFI_6f, NEW_CFI_7f };
    128 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
    129 static soc_field_t _tnl_ecn_ptr_f[] = 
    130 { IP_ECN_TO_EXP_MAPPING_PTR_0f, IP_ECN_TO_EXP_MAPPING_PTR_1f, 
    131   IP_ECN_TO_EXP_MAPPING_PTR_2f, IP_ECN_TO_EXP_MAPPING_PTR_3f,
    132   IP_ECN_TO_EXP_MAPPING_PTR_4f, IP_ECN_TO_EXP_MAPPING_PTR_5f, 
    133   IP_ECN_TO_EXP_MAPPING_PTR_6f, IP_ECN_TO_EXP_MAPPING_PTR_7f};
    134 static soc_field_t _tnl_ecn_ptr_pri_f[] = 
    135 { IP_ECN_TO_EXP_PRIORITY_0f, IP_ECN_TO_EXP_PRIORITY_1f, 
    136   IP_ECN_TO_EXP_PRIORITY_2f, IP_ECN_TO_EXP_PRIORITY_3f,
    137   IP_ECN_TO_EXP_PRIORITY_4f, IP_ECN_TO_EXP_PRIORITY_5f, 
    138   IP_ECN_TO_EXP_PRIORITY_6f, IP_ECN_TO_EXP_PRIORITY_7f};
    139 static soc_field_t _tnl_int_cn_ptr_f[] = 
    140 { INT_CN_TO_EXP_MAPPING_PTR_0f, INT_CN_TO_EXP_MAPPING_PTR_1f, 
    141   INT_CN_TO_EXP_MAPPING_PTR_2f, INT_CN_TO_EXP_MAPPING_PTR_3f,
    142   INT_CN_TO_EXP_MAPPING_PTR_4f, INT_CN_TO_EXP_MAPPING_PTR_5f, 
    143   INT_CN_TO_EXP_MAPPING_PTR_6f, INT_CN_TO_EXP_MAPPING_PTR_7f};
    144 static soc_field_t _tnl_int_cn_ptr_pri_f[] = 
    145 { INT_CN_TO_EXP_PRIORITY_0f, INT_CN_TO_EXP_PRIORITY_1f, 
    146   INT_CN_TO_EXP_PRIORITY_2f, INT_CN_TO_EXP_PRIORITY_3f,
    147   INT_CN_TO_EXP_PRIORITY_4f, INT_CN_TO_EXP_PRIORITY_5f, 
    148   INT_CN_TO_EXP_PRIORITY_6f, INT_CN_TO_EXP_PRIORITY_7f};
    149 #endif
    150 /************************  FUNCTIONS BOUNDARY **********************/
    151 
    152 STATIC soc_mem_t
    153 bcmi_egr_ip_tnl_mem_name_get(int unit)
    154 {
    155    soc_mem_t mem;
    156 
    157 #if defined(BCM_TRIDENT3_SUPPORT)
    158    if (soc_feature(unit, soc_feature_td3_style_mpls)) {
    159        mem = EGR_IP_TUNNEL_MPLS_DOUBLE_WIDEm;
    160    } else
    161 #endif
    162    {
    163        mem = EGR_IP_TUNNEL_MPLSm;
    164    }
    165    return mem;
    166 }
    167 
    168 STATIC int
    169 bcmi_egr_ip_tnl_mpls_table_write(int unit,int tnl_id,void *tnl_buf)
    170 {
    171   int rv = BCM_E_NONE;
    172 
    173 #if defined(BCM_TRIDENT3_SUPPORT)
    174   if (soc_feature(unit, soc_feature_td3_style_mpls)) {
    175       rv = WRITE_EGR_IP_TUNNEL_MPLS_DOUBLE_WIDEm(unit, MEM_BLOCK_ANY,
    176               tnl_id, tnl_buf);
    177   } else
    178 #endif
    179   {
    180       rv = WRITE_EGR_IP_TUNNEL_MPLSm(unit, MEM_BLOCK_ANY, tnl_id, tnl_buf);
    181   }
    182    return rv;
    183 }
    184 
    185 
    186 STATIC int
    187 bcmi_egr_ip_tnl_mpls_table_read(int unit,int tnl_id,void *tnl_buf)
    188 {
    189   int rv = BCM_E_NONE;
    190 
    191 #if defined(BCM_TRIDENT3_SUPPORT)
    192   if (soc_feature(unit, soc_feature_td3_style_mpls)) {
    193       rv = READ_EGR_IP_TUNNEL_MPLS_DOUBLE_WIDEm(unit,
    194               MEM_BLOCK_ANY,tnl_id, tnl_buf);
    195   } else
    196 #endif
    197   {
    198       rv = READ_EGR_IP_TUNNEL_MPLSm(unit, MEM_BLOCK_ANY,
    199               tnl_id,tnl_buf);
    200   }
    201   return rv;
    202 }
    203 
    204 STATIC void
    205 bcmi_egr_ip_tnl_mpls_table_memset(int unit,void *tnl_buf)
    206 {
    207 
    208 #if defined(BCM_TRIDENT3_SUPPORT)
    209     if (soc_feature(unit, soc_feature_td3_style_mpls)) {
    210         sal_memset(tnl_buf, 0,
    211                 sizeof(egr_ip_tunnel_mpls_double_wide_entry_t));
    212     } else
    213 #endif
    214     {
    215         sal_memset(tnl_buf, 0, sizeof(egr_ip_tunnel_mpls_entry_t));
    216     }
    217 }
    218 
    219 STATIC int
    220 bcmi_egr_ip_tnl_mpls_entry_type_check(int unit,void *tnl_buf)
    221 {
    222     int rv = BCM_E_NONE;
    223     soc_mem_t mem;
    224     mem = bcmi_egr_ip_tnl_mem_name_get(unit);
    225 
    226 #if defined(BCM_TRIDENT3_SUPPORT)
    227     if (soc_feature(unit, soc_feature_td3_style_mpls)) {
    228         if (soc_mem_field32_get(unit,
    229                     mem,
    230                     tnl_buf, DATA_TYPEf) != 0x14) {
    231             return BCM_E_INTERNAL;
    232         }
    233     } else
    234 #endif
    235     {
    236         if (soc_mem_field32_get(unit,
    237                     mem,
    238                     tnl_buf, ENTRY_TYPEf) != 3) {
    239             return BCM_E_INTERNAL;
    240         }
    241     }
    242     return rv;
    243 }
    244 
    245 int
    246 bcmi_egress_tnl_label_entry_set(int unit, void *tnl_buf,
    247         int offset, uint32 *data_buf)
    248 {
    249     int rv = BCM_E_NONE;
    250 
    251 #if defined(BCM_TRIDENT3_SUPPORT)
    252     if (soc_feature(unit, soc_feature_td3_style_mpls)) {
    253         soc_mem_field_set(unit, EGR_IP_TUNNEL_MPLS_DOUBLE_WIDEm,
    254                 (uint32 *)tnl_buf, _tnl_label_entry_f[offset], data_buf);
    255     }
    256 #endif
    257 
    258     return rv;
    259 }
    260 
    261 
    262 int
    263 bcmi_egress_tnl_label_entry_get(int unit, void *tnl_buf,
    264         int offset, uint32 *data_buf)
    265 {
    266     int rv = BCM_E_NONE;
    267 
    268 #if defined(BCM_TRIDENT3_SUPPORT)
    269     if (soc_feature(unit, soc_feature_td3_style_mpls)) {
    270         soc_mem_field_get(unit, EGR_IP_TUNNEL_MPLS_DOUBLE_WIDEm,
    271                 (uint32 *)tnl_buf, _tnl_label_entry_f[offset], data_buf);
    272     }
    273 #endif
    274 
    275     return rv;
    276 }
    277 
    278 STATIC int
    279 bcmi_validate_field_range(int unit,uint32 set_val,int range)
    280 {
    281 #ifdef BCM_TRIDENT3_SUPPORT
    282     return BCM_E_NONE;
    283 #else
    284     return BCM_E_NONE;
    285 #endif
    286 
    287 }
    288 
    289 STATIC void
    290 bcmi_egr_ip_tnl_copy_src_label_info_to_dest(int unit, void *src_entry ,
    291         void *dst_entry, int src_offset, int dst_offset, int no_of_elements)
    292 {
    293     int i = 0;
    294     int src_value;
    295 
    296     for (; i < no_of_elements; i++) {
    297         src_value = soc_mem_field32_get(unit, EGR_IP_TUNNEL_MPLSm, src_entry,
    298                 _tnl_push_action_f[src_offset+i]);
    299         soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, dst_entry,
    300                 _tnl_push_action_f[dst_offset+i], src_value);
    301         src_value = soc_mem_field32_get(unit, EGR_IP_TUNNEL_MPLSm, src_entry,
    302                 _tnl_label_f[src_offset+i]);
    303         soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, dst_entry,
    304                 _tnl_label_f[dst_offset+i], src_value);
    305         src_value = soc_mem_field32_get(unit, EGR_IP_TUNNEL_MPLSm, src_entry,
    306                 _tnl_exp_select_f[src_offset+i]);
    307         soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, dst_entry,
    308                 _tnl_exp_select_f[dst_offset+i], src_value);
    309         src_value = soc_mem_field32_get(unit, EGR_IP_TUNNEL_MPLSm, src_entry,
    310                 _tnl_exp_f[src_offset+i]);
    311         soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, dst_entry,
    312                 _tnl_exp_f[dst_offset+i], src_value);
    313         src_value = soc_mem_field32_get(unit, EGR_IP_TUNNEL_MPLSm, src_entry,
    314                 _tnl_pri_f[src_offset+i]);
    315         soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, dst_entry,
    316                 _tnl_pri_f[dst_offset+i], src_value);
    317         src_value = soc_mem_field32_get(unit, EGR_IP_TUNNEL_MPLSm, src_entry,
    318                 _tnl_cfi_f[src_offset+i]);
    319         soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, dst_entry,
    320                 _tnl_cfi_f[dst_offset+i], src_value);
    321         src_value = soc_mem_field32_get(unit, EGR_IP_TUNNEL_MPLSm, src_entry,
    322                 _tnl_exp_ptr_f[src_offset+i]);
    323         soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, dst_entry,
    324                 _tnl_exp_ptr_f[dst_offset+i], src_value);
    325         src_value = soc_mem_field32_get(unit, EGR_IP_TUNNEL_MPLSm, src_entry,
    326                 _tnl_ttl_f[src_offset+i]);
    327         soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, dst_entry,
    328                 _tnl_ttl_f[dst_offset+i], src_value);
    329     }
    330 }
    331 
    332 STATIC int
    333 bcmi_td3_destination_format_set(int unit, mpls_entry_entry_t *mpls_entry,
    334                                                int dest_type, int value)
    335 {
    336     if (mpls_entry == NULL) {
    337         return BCM_E_PARAM;
    338     }
    339 
    340     switch (dest_type) {
    341         case SOC_MEM_FIF_DEST_NEXTHOP:
    342             soc_mem_field32_dest_set(unit, MPLS_ENTRYm, mpls_entry,
    343                     DESTINATIONf,
    344                     SOC_MEM_FIF_DEST_NEXTHOP, value);
    345             break;
    346         case SOC_MEM_FIF_DEST_ECMP:
    347             soc_mem_field32_dest_set(unit, MPLS_ENTRYm, mpls_entry,
    348                     DESTINATIONf,
    349                     SOC_MEM_FIF_DEST_ECMP, value);
    350             break;
    351         default:
    352             break;
    353     }
    354 
    355     return BCM_E_NONE;
    356 }
    357 
    358 STATIC int
    359 _bcmi_xgs5_mpls_entry_get_key(int unit, mpls_entry_entry_t *ment,
    360                            bcm_mpls_tunnel_switch_t *info)
    361 {
    362     bcm_port_t port_in = 0, port_out = 0;
    363     bcm_module_t mod_in = 0, mod_out = 0;
    364     bcm_trunk_t trunk_id;
    365     soc_mem_t mem = MPLS_ENTRYm;
    366 
    367     if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
    368         mem = MPLS_ENTRY_SINGLEm;
    369     } else {
    370         mod_in = soc_mem_field32_get(unit, mem, ment, MODULE_IDf);
    371     }
    372     port_in = soc_mem_field32_get(unit, mem, ment, PORT_NUMf);
    373     if (soc_mem_field32_get(unit, mem, ment, Tf)) {
    374         trunk_id = soc_mem_field32_get(unit, mem, ment, TGIDf);
    375         BCM_GPORT_TRUNK_SET(info->port, trunk_id);
    376     } else if ((port_in == 0) && (mod_in == 0)) {
    377         /* Global label, mod/port not part of lookup key */
    378         info->port = BCM_GPORT_INVALID;
    379     } else {
    380         BCM_IF_ERROR_RETURN
    381             (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
    382                                     mod_in, port_in, &mod_out, &port_out));
    383         BCM_GPORT_MODPORT_SET(info->port, mod_out, port_out);
    384     } 
    385     info->label = soc_mem_field32_get(unit, mem, ment, MPLS_LABELf);
    386 
    387     return BCM_E_NONE;
    388 }
    389 
    390 /* Convert data part of HW entry to application format. */
    391 STATIC int
    392 _bcmi_xgs5_mpls_entry_get_data(int unit, mpls_entry_entry_t *ment,
    393                             bcm_mpls_tunnel_switch_t *info)
    394 {
    395     int rv, nh_index, vrf;
    396     int action_if_bos, action_if_not_bos;
    397     bcm_if_t egress_if=0;
    398     int mode = 0;
    399     soc_mem_t mem = MPLS_ENTRYm;
    400 #ifdef BCM_MONTEREY_SUPPORT
    401     uint32 roe_type = 0;
    402     uint32 bit_num = 0;
    403 #endif
    404 
    405     if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
    406         mem = MPLS_ENTRY_SINGLEm;
    407     }
    408 
    409     BCM_IF_ERROR_RETURN(bcm_xgs3_l3_ingress_mode_get(unit, &mode));
    410     action_if_bos = soc_mem_field32_get(unit, mem, ment, MPLS_ACTION_IF_BOSf);
    411     action_if_not_bos = soc_mem_field32_get(unit, mem, ment,
    412                                             MPLS_ACTION_IF_NOT_BOSf); 
    413 
    414     if (action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_L3_IIF ||
    415         action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_POP) {
    416         if (!mode) {
    417             _bcm_l3_ingress_intf_t iif;
    418 #ifdef BCM_TOMAHAWK_SUPPORT
    419             int tunnel_term_ecn_map_id;
    420 #endif
    421             vrf = soc_mem_field32_get(unit, mem, ment, L3_IIFf);
    422             /*
    423              * If the ingress mode is not set, then L3_IIF is added
    424              * above the intreface of _BCM_TR_MPLS_L3_IIF_BASE.
    425              * If this is 0 then 0 vpn index was set.
    426              */
    427             if (vrf != 0) {
    428                 iif.intf_id =  vrf;
    429                 vrf -= _BCM_TR_MPLS_L3_IIF_BASE;
    430                 _BCM_MPLS_VPN_SET(info->vpn, _BCM_MPLS_VPN_TYPE_L3, vrf);
    431                 rv = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif);
    432                 BCM_IF_ERROR_RETURN(rv);
    433 #ifdef BCM_TOMAHAWK_SUPPORT
    434                 if (soc_feature(unit, soc_feature_mpls_ecn)) {
    435                     tunnel_term_ecn_map_id = iif.tunnel_term_ecn_map_id;
    436                     if (bcmi_xgs5_ecn_map_used_get(unit, tunnel_term_ecn_map_id,
    437                                 _bcmEcnmapTypeTunnelTerm)) {
    438                         info->tunnel_term_ecn_map_id = tunnel_term_ecn_map_id |
    439                             _BCM_XGS5_ECN_MAP_TYPE_TUNNEL_TERM;
    440                         info->flags |= BCM_MPLS_SWITCH_TUNNEL_TERM_ECN_MAP;
    441                     }
    442                 }
    443 #endif
    444             }
    445         } else {
    446             info->ingress_if = soc_mem_field32_get(unit, mem, ment, L3_IIFf);
    447         } 
    448     }
    449 
    450     if (action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_SWAP_NHI ||
    451             action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_SWAP_NHI) {
    452         nh_index = soc_mem_field32_get(unit, mem, ment,
    453                                                NEXT_HOP_INDEXf);
    454         rv = bcm_tr_mpls_get_vp_nh (unit, nh_index,&egress_if);
    455         if (rv == BCM_E_NONE) {
    456             rv = bcm_tr_mpls_l3_nh_info_get(unit, info, nh_index);
    457         } else
    458 #ifdef BCM_TOMAHAWK3_SUPPORT
    459         if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
    460             rv = bcm_th3_mpls_l3_nh_info_get(unit, info, nh_index);
    461         } else
    462 #endif
    463         {
    464             info->egress_if = nh_index + BCM_XGS3_EGRESS_IDX_MIN(unit);
    465             info->egress_label.label = BCM_MPLS_LABEL_INVALID;
    466             rv = BCM_E_NONE;
    467         }
    468         BCM_IF_ERROR_RETURN(rv);
    469     }
    470 
    471     if (action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_L3_NHI ||
    472         action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_ROE_NHI ||
    473         action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_PHP_NHI) {
    474         info->action = BCM_MPLS_SWITCH_ACTION_PHP;
    475         nh_index = soc_mem_field32_get(unit, mem, ment,
    476                                                NEXT_HOP_INDEXf);
    477         info->egress_if = nh_index + BCM_XGS3_EGRESS_IDX_MIN(unit);
    478     }
    479 
    480     if (action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_L3_ECMP ||
    481         action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_PHP_ECMP ||
    482         action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_SWAP_ECMP ||
    483         action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_SWAP_ECMP) {
    484         info->action = BCM_MPLS_SWITCH_ACTION_SWAP;
    485         nh_index = soc_mem_field32_get(unit, mem, ment,
    486                 ECMP_PTRf);
    487         info->egress_if = nh_index + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
    488     }
    489 
    490 
    491     switch(action_if_bos) {
    492         case _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_L3_IIF:
    493             info->action_if_bos = BCM_MPLS_SWITCH_ACTION_POP;
    494             break;
    495         case _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_SWAP_NHI:
    496         case _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_SWAP_ECMP:
    497             info->action_if_bos = BCM_MPLS_SWITCH_ACTION_SWAP;
    498             break;
    499         case _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_L3_NHI:
    500         case _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_ROE_NHI:
    501         case _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_L3_ECMP:
    502             info->action_if_bos = BCM_MPLS_SWITCH_ACTION_PHP;
    503             break;
    504         case _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_INVALID:
    505             info->action_if_bos = BCM_MPLS_SWITCH_ACTION_INVALID;
    506             break;
    507         default:
    508             return BCM_E_INTERNAL;
    509             break;
    510     }
    511 
    512    switch(action_if_not_bos) {
    513         case _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_POP:
    514             info->action_if_not_bos = BCM_MPLS_SWITCH_ACTION_POP;
    515             break;
    516         case _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_SWAP_NHI:
    517         case _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_SWAP_ECMP:
    518             info->action_if_not_bos = BCM_MPLS_SWITCH_ACTION_SWAP;
    519             break;
    520         case _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_PHP_NHI:
    521         case _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_PHP_ECMP:
    522             info->action_if_not_bos = BCM_MPLS_SWITCH_ACTION_PHP;
    523             break;
    524         case _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_INVALID:
    525             info->action_if_not_bos = BCM_MPLS_SWITCH_ACTION_INVALID;
    526             break;
    527         default:
    528             return BCM_E_INTERNAL;
    529             break;
    530     }
    531 
    532     if (info->action_if_bos == info->action_if_not_bos) {
    533         info->action = info->action_if_bos;
    534         if (info->action == BCM_MPLS_SWITCH_ACTION_INVALID) {
    535             /* Both actions are invalid in the HW entry 
    536              * Error out.
    537              */
    538             return BCM_E_INTERNAL;
    539         }
    540     } else {
    541         info->action = BCM_MPLS_SWITCH_ACTION_INVALID;
    542     }
    543 
    544     if (SOC_MEM_FIELD_VALID(unit, mem, PW_TERM_NUM_VALIDf) &&
    545         soc_mem_field32_get(unit, mem, ment, PW_TERM_NUM_VALIDf)) {
    546         info->flags |= BCM_MPLS_SWITCH_COUNTED;
    547     }
    548 
    549 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
    550      else if (SOC_MEM_FIELD_VALID(unit, MPLS_ENTRYm, CLASS_IDf)) {
    551         info->class_id = soc_mem_field32_get(unit, mem, ment, CLASS_IDf);
    552 #if defined(BCM_MONTEREY_SUPPORT)
    553         if (soc_feature(unit,soc_feature_mont_roe_classid_sw_war)) {
    554             if ((bit_num = soc_mem_field_length(unit, mem, CLASS_IDf)) > 0) {
    555                 bit_num -= 1;
    556                 info->class_id = info->class_id & (( 1 << bit_num ) - 1);
    557             }
    558         }
    559 #endif
    560     }
    561 #endif
    562 
    563 #ifdef BCM_MONTEREY_SUPPORT
    564      if (SOC_MEM_FIELD_VALID(unit, MPLS_ENTRYm, ROE_TYPEf)) {
    565          roe_type = soc_MPLS_ENTRYm_field32_get(unit, ment, ROE_TYPEf);
    566          if (roe_type == _BCM_MPLS_XGS5_MPLS_ROE_TUNNEL) {
    567              info->flags2 |= BCM_MPLS_SWITCH2_ENABLE_ROE;
    568          } else if (roe_type == _BCM_MPLS_XGS5_MPLS_ROE_CUSTOM_TUNNEL) {
    569              info->flags2 |= BCM_MPLS_SWITCH2_ENABLE_ROE_CUSTOM;
    570          } else {
    571              /* Do nothing */
    572          }
    573      }
    574 #endif
    575 
    576     if (!soc_mem_field32_get(unit, mem, ment, DECAP_USE_TTLf)) {
    577         info->flags |= BCM_MPLS_SWITCH_INNER_TTL;
    578     }
    579     if (soc_mem_field32_get(unit, mem, ment, DECAP_USE_EXP_FOR_INNERf)) {
    580         if ((info->action_if_bos == BCM_MPLS_SWITCH_ACTION_PHP) ||
    581             (info->action_if_bos == BCM_MPLS_SWITCH_ACTION_POP) ||
    582             (info->action_if_not_bos == BCM_MPLS_SWITCH_ACTION_PHP) ||
    583             (info->action_if_not_bos == BCM_MPLS_SWITCH_ACTION_POP)) {
    584             info->flags |= BCM_MPLS_SWITCH_INNER_EXP;
    585         }
    586     }
    587     if (soc_mem_field32_get(unit, mem, ment, 
    588                                     DECAP_USE_EXP_FOR_PRIf) == 0x1) {
    589 
    590         /* Use specified EXP-map to determine internal prio/color */
    591         info->flags |= BCM_MPLS_SWITCH_INT_PRI_MAP;
    592         info->exp_map = 
    593             soc_mem_field32_get(unit, mem, ment, EXP_MAPPING_PTRf);
    594         info->exp_map |= _BCM_TR_MPLS_EXP_MAP_TABLE_TYPE_INGRESS;
    595     } else if (soc_mem_field32_get(unit, mem, ment,
    596                                            DECAP_USE_EXP_FOR_PRIf) == 0x2) {
    597 
    598         /* Use the specified internal priority value */
    599         info->flags |= BCM_MPLS_SWITCH_INT_PRI_SET;
    600         info->int_pri =
    601             soc_mem_field32_get(unit, mem, ment, NEW_PRIf);
    602 
    603         /* Use specified EXP-map to determine internal color */
    604         info->flags |= BCM_MPLS_SWITCH_COLOR_MAP;
    605         info->exp_map = 
    606             soc_mem_field32_get(unit, mem, ment, EXP_MAPPING_PTRf);
    607         info->exp_map |= _BCM_TR_MPLS_EXP_MAP_TABLE_TYPE_INGRESS;
    608     }
    609     if (SOC_MEM_FIELD_VALID(unit,mem,
    610                             DO_NOT_CHANGE_PAYLOAD_DSCPf)) {
    611         if (soc_mem_field32_get(unit, mem, ment, 
    612                                         DO_NOT_CHANGE_PAYLOAD_DSCPf) == 0) {
    613             if ((info->action_if_bos == BCM_MPLS_SWITCH_ACTION_PHP) ||
    614                 (info->action_if_bos == BCM_MPLS_SWITCH_ACTION_POP) ||
    615                 (info->action_if_not_bos == BCM_MPLS_SWITCH_ACTION_PHP) ||
    616                 (info->action_if_not_bos == BCM_MPLS_SWITCH_ACTION_POP)) {
    617                      info->flags |=
    618                          (BCM_MPLS_SWITCH_OUTER_EXP | BCM_MPLS_SWITCH_OUTER_TTL);
    619             }
    620         }
    621     }
    622 #if defined(BCM_TOMAHAWK2_SUPPORT)
    623     if (soc_feature(unit, soc_feature_mpls_ecn)) {
    624         int ecn_map_id;
    625         int ecn_map_hw_idx;
    626         int rv;
    627         ecn_map_hw_idx = soc_mem_field32_get(unit, mem, ment,
    628                                                      EXP_TO_IP_ECN_MAPPING_PTRf);
    629         rv = bcmi_ecn_map_hw_idx2id(unit, ecn_map_hw_idx, 
    630                                     _BCM_XGS5_MPLS_ECN_MAP_TYPE_EXP2ECN, 
    631                                     &ecn_map_id); 
    632         if (BCM_SUCCESS(rv)) {
    633             info->flags |= BCM_MPLS_SWITCH_INGRESS_ECN_MAP;
    634             info->ecn_map_id = ecn_map_id;
    635         }
    636     }
    637 #endif /* BCM_TOMAHAWK2_SUPPORT */
    638 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_TOMAHAWK2_SUPPORT)
    639     if (soc_feature(unit, soc_feature_td2p_mpls_linear_protection) || 
    640         SOC_IS_TOMAHAWK2(unit)) {
    641 
    642         if (soc_mem_field32_get(unit, mem, ment,
    643                                         MPLS__DROP_DATA_ENABLEf)) {
    644             info->flags |= BCM_MPLS_SWITCH_DROP;
    645         }
    646         info->failover_id =
    647             soc_mem_field32_get(unit, mem, ment,
    648                                         MPLS__RX_PROT_GROUPf);
    649         if (info->failover_id != 0) {
    650             _BCM_ENCAP_TYPE_IN_FAILOVER_ID(info->failover_id,
    651                                            _BCM_FAILOVER_INGRESS);
    652         }
    653      }
    654 #endif /*BCM_TRIDENT2PLUS_SUPPORT || BCM_TOMAHAWK2_SUPPORT */
    655     return BCM_E_NONE;
    656 }
    657 
    658 /*
    659  * Function:
    660  *        bcm_td3_mpls_l3_nh_info_get
    661  * Purpose:
    662  *        Get Tunnel_switch info for a specific EGR_NH Index
    663  * Parameters:
    664  *        unit - unit
    665  *        info - Tunnel switch info
    666  *        nh_index - next hop index
    667  * Returns:
    668  *        BCM_E_XXX
    669 */
    670 STATIC int
    671 bcm_td3_mpls_l3_nh_info_get(int unit, bcm_mpls_tunnel_switch_t *info, int nh_index)
    672 {
    673     int vc_swap_idx = 0;
    674     int vc_data_type = 0;
    675     int pri_cfi_sel = 0;
    676     int mapping_ptr = 0;
    677     uint32 mpls_format[2];
    678     egr_l3_next_hop_entry_t egr_nh;
    679     egr_mpls_vc_and_swap_label_table_entry_t vc_entry;
    680 
    681     SOC_IF_ERROR_RETURN(soc_mem_read(unit,
    682         EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY, nh_index, &egr_nh));
    683     vc_swap_idx = soc_EGR_L3_NEXT_HOPm_field32_get(
    684         unit, &egr_nh, MPLS__VC_AND_SWAP_INDEXf);
    685     SOC_IF_ERROR_RETURN(soc_mem_read(unit,
    686         EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm,
    687         MEM_BLOCK_ANY, vc_swap_idx, &vc_entry));
    688     vc_data_type = soc_mem_field32_get(unit,
    689         EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm,
    690         &vc_entry, DATA_TYPEf);
    691 
    692     if (vc_data_type == _BCM_VC_SWAP_TBL_FLEX_DATA_TYPE) {
    693         sal_memset(mpls_format, 0, sizeof(mpls_format));
    694         soc_mem_field_get(unit, EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm,
    695             (uint32*)&vc_entry,
    696             MPLS_PHP__MPLS_ENTRY_0_ACTION_SETf,
    697             (uint32*)mpls_format);
    698         pri_cfi_sel = soc_format_field32_get(unit,
    699             MPLS_ENTRY_ACTION_SETfmt,
    700             (uint32*)mpls_format, PRI_CFI_SELf);
    701         mapping_ptr = soc_format_field32_get(unit,
    702             MPLS_ENTRY_ACTION_SETfmt,
    703             (uint32*)mpls_format, DOT1P_MAPPING_PTRf);
    704 
    705         if (pri_cfi_sel == 1) {
    706             info->flags2 |= BCM_MPLS_SWITCH2_VLAN_PRI_PHB_REMARK;
    707             BCM_IF_ERROR_RETURN(
    708                 _bcm_tr2_qos_idx2id(unit, mapping_ptr,
    709                     _BCM_QOS_MAP_TYPE_EGR_MPLS_MAPS, &info->qos_map_id));
    710         } else if (pri_cfi_sel == 0 && mapping_ptr > 0) {
    711             info->flags2 |= BCM_MPLS_SWITCH2_VLAN_PRI_SET;
    712             info->pkt_cfi = mapping_ptr & 1;
    713             info->pkt_pri = (mapping_ptr >> 1) & 0x7;
    714         }
    715     }
    716 
    717     return BCM_E_NONE;
    718 }
    719 
    720 STATIC int
    721 bcmi_td3_mpls_entry_get_data(int unit, mpls_entry_entry_t *ment,
    722                             bcm_mpls_tunnel_switch_t *info)
    723 {
    724     int rv = BCM_E_NONE, nh_index, vrf;
    725     int action_if_bos, action_if_not_bos;
    726     bcm_if_t egress_if=0;
    727     int mode = 0;
    728     uint32 dest_type;
    729     uint32 value = 0;
    730     soc_mem_t mem = MPLS_ENTRYm;
    731 
    732     BCM_IF_ERROR_RETURN(bcm_xgs3_l3_ingress_mode_get(unit, &mode));
    733     action_if_bos = soc_mem_field32_get(unit, mem, ment, MPLS_ACTION_IF_BOSf);
    734     action_if_not_bos = soc_mem_field32_get(unit, mem, ment,
    735                                             MPLS_ACTION_IF_NOT_BOSf);
    736 
    737     if (action_if_bos == _BCM_MPLS_TD3_MPLS_ACTION_POP_SVP_ENTROPY) {
    738        
    739     }
    740 
    741     /*POP OR L3_IIF*/
    742     if (action_if_bos == _BCM_MPLS_TD3_MPLS_ACTION_L3_IIF ||
    743             action_if_not_bos == _BCM_MPLS_TD3_MPLS_ACTION_POP) {
    744         if (!mode) {
    745             _bcm_l3_ingress_intf_t iif;
    746 #ifdef BCM_TOMAHAWK_SUPPORT
    747             int tunnel_term_ecn_map_id;
    748 #endif
    749             vrf = soc_mem_field32_get(unit, mem, ment, L3_IIFf);
    750             iif.intf_id =  vrf;
    751             vrf -= _BCM_TR_MPLS_L3_IIF_BASE;
    752             _BCM_MPLS_VPN_SET(info->vpn, _BCM_MPLS_VPN_TYPE_L3, vrf);
    753             rv = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif);
    754             BCM_IF_ERROR_RETURN(rv);
    755 #ifdef BCM_TOMAHAWK_SUPPORT
    756             if (soc_feature(unit, soc_feature_mpls_ecn)) {
    757                 tunnel_term_ecn_map_id = iif.tunnel_term_ecn_map_id;
    758                 if (bcmi_xgs5_ecn_map_used_get(unit, tunnel_term_ecn_map_id,
    759                             _bcmEcnmapTypeTunnelTerm)) {
    760                     info->tunnel_term_ecn_map_id = tunnel_term_ecn_map_id |
    761                         _BCM_XGS5_ECN_MAP_TYPE_TUNNEL_TERM;
    762                     info->flags |= BCM_MPLS_SWITCH_TUNNEL_TERM_ECN_MAP;
    763                 }
    764             }
    765 #endif
    766         } else {
    767             info->ingress_if = soc_mem_field32_get(unit, mem, ment, L3_IIFf);
    768         }
    769     }
    770 
    771     if (action_if_bos == _BCM_MPLS_TD3_MPLS_ACTION_SWAP ||
    772             action_if_not_bos == _BCM_MPLS_TD3_MPLS_ACTION_SWAP) {
    773         value = soc_mem_field32_dest_get(unit, MPLS_ENTRYm, ment,
    774                 DESTINATIONf, &dest_type);
    775 
    776         if (dest_type == SOC_MEM_FIF_DEST_NEXTHOP) {
    777             nh_index = value;
    778 
    779             rv = bcm_tr_mpls_get_vp_nh (unit, nh_index,&egress_if);
    780             if (rv == BCM_E_NONE) {
    781                 rv = bcm_tr_mpls_l3_nh_info_get(unit, info, nh_index);
    782             } else {
    783                 info->egress_if = nh_index + BCM_XGS3_EGRESS_IDX_MIN(unit);
    784                 info->egress_label.label = BCM_MPLS_LABEL_INVALID;
    785                 rv = BCM_E_NONE;
    786             }
    787         }
    788         BCM_IF_ERROR_RETURN(rv);
    789     }
    790 
    791     if (action_if_bos == _BCM_MPLS_TD3_MPLS_ACTION_PHP ||
    792             action_if_not_bos == _BCM_MPLS_TD3_MPLS_ACTION_PHP) {
    793         info->action = BCM_MPLS_SWITCH_ACTION_PHP;
    794         value = soc_mem_field32_dest_get(unit, MPLS_ENTRYm, ment,
    795                 DESTINATIONf, &dest_type);
    796 
    797         if (dest_type == SOC_MEM_FIF_DEST_NEXTHOP) {
    798             nh_index = value;
    799             info->egress_if = nh_index + BCM_XGS3_EGRESS_IDX_MIN(unit);
    800             BCM_IF_ERROR_RETURN(
    801                 bcm_td3_mpls_l3_nh_info_get(unit, info, nh_index));
    802         }
    803     }
    804 
    805     if (action_if_bos == _BCM_MPLS_TD3_MPLS_ACTION_PHP ||
    806             action_if_not_bos == _BCM_MPLS_TD3_MPLS_ACTION_PHP ||
    807             action_if_bos == _BCM_MPLS_TD3_MPLS_ACTION_SWAP ||
    808             action_if_not_bos == _BCM_MPLS_TD3_MPLS_ACTION_SWAP) {
    809         info->action = BCM_MPLS_SWITCH_ACTION_SWAP;
    810         value = soc_mem_field32_dest_get(unit, MPLS_ENTRYm, ment,
    811                 DESTINATIONf, &dest_type);
    812 
    813         if (dest_type == SOC_MEM_FIF_DEST_ECMP) {
    814             nh_index = value;
    815             info->egress_if = nh_index + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
    816         }
    817     }
    818 
    819     switch(action_if_bos) {
    820         case _BCM_MPLS_TD3_MPLS_ACTION_L3_IIF:
    821             info->action_if_bos = BCM_MPLS_SWITCH_ACTION_POP;
    822             break;
    823         case _BCM_MPLS_TD3_MPLS_ACTION_SWAP:
    824             info->action_if_bos = BCM_MPLS_SWITCH_ACTION_SWAP;
    825             break;
    826         case _BCM_MPLS_TD3_MPLS_ACTION_PHP:
    827             info->action_if_bos = BCM_MPLS_SWITCH_ACTION_PHP;
    828             break;
    829         case _BCM_MPLS_TD3_MPLS_ACTION_INVALID:
    830             info->action_if_bos = BCM_MPLS_SWITCH_ACTION_INVALID;
    831             break;
    832         default:
    833             return BCM_E_INTERNAL;
    834             break;
    835     }
    836 
    837     switch(action_if_not_bos) {
    838         case _BCM_MPLS_TD3_MPLS_ACTION_POP:
    839             info->action_if_not_bos = BCM_MPLS_SWITCH_ACTION_POP;
    840             break;
    841         case _BCM_MPLS_TD3_MPLS_ACTION_SWAP:
    842             info->action_if_not_bos = BCM_MPLS_SWITCH_ACTION_SWAP;
    843             break;
    844         case _BCM_MPLS_TD3_MPLS_ACTION_PHP:
    845             info->action_if_not_bos = BCM_MPLS_SWITCH_ACTION_PHP;
    846             break;
    847         case _BCM_MPLS_TD3_MPLS_ACTION_INVALID:
    848             info->action_if_not_bos = BCM_MPLS_SWITCH_ACTION_INVALID;
    849             break;
    850         default:
    851             return BCM_E_INTERNAL;
    852             break;
    853     }
    854 
    855     if (info->action_if_bos == info->action_if_not_bos) {
    856         info->action = info->action_if_bos;
    857         if (info->action == BCM_MPLS_SWITCH_ACTION_INVALID) {
    858             /* Both actions are invalid in the HW entry
    859              * Error out.
    860              */
    861             return BCM_E_INTERNAL;
    862         }
    863     } else {
    864         info->action = BCM_MPLS_SWITCH_ACTION_INVALID;
    865     }
    866 
    867     if (soc_mem_field32_get(unit, mem, ment, PW_TERM_NUM_VALIDf)) {
    868         info->flags |= BCM_MPLS_SWITCH_COUNTED;
    869     }
    870 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
    871      else if (SOC_MEM_FIELD_VALID(unit, MPLS_ENTRYm, CLASS_IDf)) {
    872         info->class_id = soc_mem_field32_get(unit, mem, ment, CLASS_IDf);
    873     }
    874 #endif
    875 
    876     if (!soc_mem_field32_get(unit, mem, ment, DECAP_USE_TTLf)) {
    877         info->flags |= BCM_MPLS_SWITCH_INNER_TTL;
    878     }
    879     if (soc_mem_field32_get(unit, mem, ment, DECAP_USE_EXP_FOR_INNERf)) {
    880         if ((info->action_if_bos == BCM_MPLS_SWITCH_ACTION_PHP) ||
    881             (info->action_if_bos == BCM_MPLS_SWITCH_ACTION_POP) ||
    882             (info->action_if_not_bos == BCM_MPLS_SWITCH_ACTION_PHP) ||
    883             (info->action_if_not_bos == BCM_MPLS_SWITCH_ACTION_POP)) {
    884             info->flags |= BCM_MPLS_SWITCH_INNER_EXP;
    885         }
    886     }
    887     if (soc_mem_field32_get(unit, mem, ment,
    888                                     DECAP_USE_EXP_FOR_PRIf) == 0x1) {
    889 
    890         /* Use specified EXP-map to determine internal prio/color */
    891         info->flags |= BCM_MPLS_SWITCH_INT_PRI_MAP;
    892         info->exp_map =
    893             soc_mem_field32_get(unit, mem, ment, EXP_MAPPING_PTRf);
    894         info->exp_map |= _BCM_TR_MPLS_EXP_MAP_TABLE_TYPE_INGRESS;
    895     } else if (soc_mem_field32_get(unit, mem, ment,
    896                                            DECAP_USE_EXP_FOR_PRIf) == 0x2) {
    897 
    898         /* Use the specified internal priority value */
    899         info->flags |= BCM_MPLS_SWITCH_INT_PRI_SET;
    900         info->int_pri =
    901             soc_mem_field32_get(unit, mem, ment, NEW_PRIf);
    902 
    903         /* Use specified EXP-map to determine internal color */
    904         info->flags |= BCM_MPLS_SWITCH_COLOR_MAP;
    905         info->exp_map =
    906             soc_mem_field32_get(unit, mem, ment, EXP_MAPPING_PTRf);
    907         info->exp_map |= _BCM_TR_MPLS_EXP_MAP_TABLE_TYPE_INGRESS;
    908     }
    909     if (SOC_MEM_FIELD_VALID(unit,MPLS_ENTRYm,
    910                             DO_NOT_CHANGE_PAYLOAD_DSCPf)) {
    911         if (soc_mem_field32_get(unit, mem, ment,
    912                                         DO_NOT_CHANGE_PAYLOAD_DSCPf) == 0) {
    913             if ((info->action_if_bos == BCM_MPLS_SWITCH_ACTION_PHP) ||
    914                 (info->action_if_bos == BCM_MPLS_SWITCH_ACTION_POP) ||
    915                 (info->action_if_not_bos == BCM_MPLS_SWITCH_ACTION_PHP) ||
    916                 (info->action_if_not_bos == BCM_MPLS_SWITCH_ACTION_POP)) {
    917                      info->flags |=
    918                          (BCM_MPLS_SWITCH_OUTER_EXP | BCM_MPLS_SWITCH_OUTER_TTL);
    919             }
    920         }
    921     }
    922 
    923 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
    924     if (soc_feature(unit, soc_feature_mpls_ecn)) {
    925         int ecn_map_id;
    926         int ecn_map_hw_idx = 0;
    927         int rv;
    928 
    929         if(soc_feature(unit, soc_feature_td3_style_mpls)) {
    930             ecn_map_hw_idx = soc_MPLS_ENTRYm_field32_get(unit, ment,
    931                     EXP_TO_ECN_MAPPING_PTRf);
    932         }
    933 
    934         rv = bcmi_ecn_map_hw_idx2id(unit, ecn_map_hw_idx,
    935                                     _BCM_XGS5_MPLS_ECN_MAP_TYPE_EXP2ECN,
    936                                     &ecn_map_id);
    937         if (BCM_SUCCESS(rv)) {
    938             info->flags |= BCM_MPLS_SWITCH_INGRESS_ECN_MAP;
    939             info->ecn_map_id = ecn_map_id;
    940         }
    941     }
    942 #endif
    943     return rv;
    944 }
    945 
    946 /* Convert key part of application format to HW entry. */
    947 STATIC int
    948 _bcmi_xgs5_mpls_entry_set_key(int unit, bcm_mpls_tunnel_switch_t *info,
    949                            mpls_entry_entry_t *ment)
    950 {
    951     bcm_module_t mod_out;
    952     bcm_port_t port_out;
    953     bcm_trunk_t trunk_id;
    954     int rv, gport_id;
    955     soc_mem_t mem = MPLS_ENTRYm;
    956     soc_field_t validf = VALIDf;
    957 
    958     if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
    959         mem = MPLS_ENTRY_SINGLEm;
    960         validf = BASE_VALIDf;
    961     }
    962 
    963     sal_memset(ment, 0, sizeof(mpls_entry_entry_t));
    964 
    965     if (info->port == BCM_GPORT_INVALID) {
    966         /* Global label, mod/port not part of lookup key */
    967         if (SOC_MEM_FIELD_VALID(unit, mem, MODULE_IDf)) {
    968             soc_mem_field32_set(unit, mem, ment, MODULE_IDf, 0);
    969         }
    970         soc_mem_field32_set(unit, mem, ment, PORT_NUMf, 0);
    971         if (BCM_XGS3_L3_MPLS_LBL_VALID(info->label)) {
    972             soc_mem_field32_set(unit, mem, ment, MPLS_LABELf, info->label);
    973         } else {
    974             return BCM_E_PARAM;
    975         }
    976 
    977         if (soc_feature(unit, soc_feature_td3_style_mpls)) {
    978             soc_mem_field32_set(unit, mem, ment, BASE_VALID_0f, 3);
    979             soc_mem_field32_set(unit, mem, ment, BASE_VALID_1f, 7);
    980         } else if (SOC_MEM_FIELD_VALID(unit, mem, BASE_VALIDf)) {
    981             soc_mem_field32_set(unit, mem, ment, BASE_VALIDf, 1);
    982         } else {
    983             soc_mem_field32_set(unit, mem, ment, validf, 1);
    984         }
    985         return BCM_E_NONE;
    986     }
    987 
    988     rv = _bcm_esw_gport_resolve(unit, info->port, &mod_out, 
    989                                 &port_out, &trunk_id, &gport_id);
    990     BCM_IF_ERROR_RETURN(rv);
    991 
    992     if (BCM_GPORT_IS_TRUNK(info->port)) {
    993         soc_mem_field32_set(unit, mem, ment, Tf, 1);
    994         soc_mem_field32_set(unit, mem, ment, TGIDf, trunk_id);
    995     } else {
    996         if (SOC_MEM_FIELD_VALID(unit, mem, MODULE_IDf)) {
    997             soc_mem_field32_set(unit, mem, ment, MODULE_IDf, mod_out);
    998         }
    999         soc_mem_field32_set(unit, mem, ment, PORT_NUMf, port_out);
   1000     }
   1001     if (BCM_XGS3_L3_MPLS_LBL_VALID(info->label)) {
   1002         soc_mem_field32_set(unit, mem, ment, MPLS_LABELf, info->label);
   1003     } else {
   1004         return BCM_E_PARAM;
   1005     }
   1006 
   1007     if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   1008         soc_mem_field32_set(unit, mem, ment, BASE_VALID_0f, 3);
   1009         soc_mem_field32_set(unit, mem, ment, BASE_VALID_1f, 7);
   1010     } else if (SOC_MEM_FIELD_VALID(unit, mem, BASE_VALIDf)){
   1011         soc_mem_field32_set(unit, mem, ment, BASE_VALIDf, 1);
   1012     } else {
   1013         soc_mem_field32_set(unit, mem, ment, validf, 1);
   1014     }
   1015 
   1016     return BCM_E_NONE;
   1017 }
   1018 
   1019 #if defined(BCM_TRIDENT3_SUPPORT)
   1020 STATIC int
   1021 bcmi_td3_php_ecmp_nhop_vcswap_add(int unit,bcm_mpls_tunnel_switch_t *php_info,
   1022         int nh_index, int mpath_flag)
   1023 {
   1024     int i = 0, ecmp_member_count = 0;
   1025     int alloc_size, index;
   1026     bcm_l3_egress_ecmp_t ecmp_info;
   1027     bcm_l3_ecmp_member_t *ecmp_member_array = NULL;
   1028     int rv = BCM_E_NONE;
   1029 
   1030     if (mpath_flag & BCM_L3_MULTIPATH) {
   1031 
   1032         alloc_size = sizeof(bcm_l3_ecmp_member_t) * BCM_XGS3_L3_ECMP_MAX(unit);
   1033         ecmp_member_array = sal_alloc(alloc_size, "ecmp member array");
   1034         if (NULL == ecmp_member_array) {
   1035             return BCM_E_MEMORY;
   1036         }
   1037         sal_memset(ecmp_member_array, 0, alloc_size);
   1038 
   1039         ecmp_info.ecmp_intf = nh_index + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   1040         rv = bcm_xgs3_l3_ecmp_get(unit, &ecmp_info, BCM_XGS3_L3_ECMP_MAX(unit),
   1041                 ecmp_member_array, &ecmp_member_count);
   1042         if (BCM_FAILURE(rv)) {
   1043             goto clean_up;
   1044         }
   1045 
   1046         while (i < ecmp_member_count) {
   1047             if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit,
   1048                         ecmp_member_array[i].egress_if)) {
   1049                 index = (ecmp_member_array[i].egress_if -
   1050                         BCM_XGS3_EGRESS_IDX_MIN(unit));
   1051             } else {
   1052                 index = (ecmp_member_array[i].egress_if -
   1053                         BCM_XGS3_DVP_EGRESS_IDX_MIN(unit));
   1054             }
   1055 
   1056             rv = bcmi_td3_mpls_php_vcswap_info_add(unit, php_info, &index);
   1057             if (BCM_FAILURE(rv)) {
   1058                 goto clean_up;
   1059             }
   1060             i++;
   1061         }
   1062     }
   1063 
   1064 clean_up:
   1065     if (ecmp_member_array) {
   1066         sal_free(ecmp_member_array);
   1067         ecmp_member_array = NULL;
   1068     }
   1069 
   1070     return rv;
   1071 }
   1072 
   1073 STATIC int
   1074 bcmi_td3_php_ecmp_nhop_vcswap_delete(int unit, int nh_index, int dest_type, int mpath_flag)
   1075 {
   1076     int i = 0, ecmp_member_count = 0;
   1077     int alloc_size, index;
   1078     bcm_l3_egress_ecmp_t ecmp_info;
   1079     bcm_l3_ecmp_member_t *ecmp_member_array = NULL;
   1080     int rv = BCM_E_NONE;
   1081 
   1082     if (mpath_flag & BCM_L3_MULTIPATH) {
   1083 
   1084         alloc_size = sizeof(bcm_l3_ecmp_member_t) * BCM_XGS3_L3_ECMP_MAX(unit);
   1085         ecmp_member_array = sal_alloc(alloc_size, "ecmp member array");
   1086         if (NULL == ecmp_member_array) {
   1087             return BCM_E_MEMORY;
   1088         }
   1089         sal_memset(ecmp_member_array, 0, alloc_size);
   1090 
   1091         ecmp_info.ecmp_intf = nh_index + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   1092         rv = bcm_xgs3_l3_ecmp_get(unit, &ecmp_info, BCM_XGS3_L3_ECMP_MAX(unit),
   1093                 ecmp_member_array, &ecmp_member_count);
   1094         if (BCM_FAILURE(rv)) {
   1095             goto clean_up;
   1096         }
   1097 
   1098         while (i < ecmp_member_count) {
   1099             if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit,
   1100                         ecmp_member_array[i].egress_if)) {
   1101                 index = (ecmp_member_array[i].egress_if -
   1102                         BCM_XGS3_EGRESS_IDX_MIN(unit));
   1103             } else {
   1104                 index = (ecmp_member_array[i].egress_if -
   1105                         BCM_XGS3_DVP_EGRESS_IDX_MIN(unit));
   1106             }
   1107 
   1108             rv = bcmi_td3_mpls_php_vcswap_info_delete(unit, index, dest_type);
   1109             if (BCM_FAILURE(rv)) {
   1110                 goto clean_up;
   1111             }
   1112             i++;
   1113         }
   1114     }
   1115 
   1116 clean_up:
   1117     if (ecmp_member_array) {
   1118         sal_free(ecmp_member_array);
   1119         ecmp_member_array = NULL;
   1120     }
   1121 
   1122     return rv;
   1123 }
   1124 #endif
   1125 
   1126 STATIC int
   1127 bcmi_xgs5_mpls_entry_label_actions_set(int unit, int action_if_bos,
   1128         int action_if_not_bos, bcm_mpls_tunnel_switch_t *info,
   1129         mpls_entry_entry_t *ment, int *nh_index, int *nh_index_alloc_failed)
   1130 {
   1131     int rv = BCM_E_NONE;
   1132     int mode,vrf=0;
   1133     uint32 mpath_flag=0;
   1134     soc_mem_t mem = MPLS_ENTRYm;
   1135 #if defined(BCM_TRIDENT3_SUPPORT)
   1136     uint32 cancun_ver;
   1137 #endif
   1138 
   1139     if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
   1140         mem = MPLS_ENTRY_SINGLEm;
   1141     }
   1142 
   1143     if ((ment == NULL) || (info == NULL)) {
   1144         return BCM_E_INTERNAL;
   1145     }
   1146 
   1147 #if defined(BCM_TRIDENT3_SUPPORT)
   1148     if (SOC_IS_TRIDENT3X(unit)) {
   1149         SOC_IF_ERROR_RETURN(soc_cancun_version_get(unit, &cancun_ver));
   1150     }
   1151 #endif
   1152 
   1153     /*POP ACTION*/
   1154     if (BCM_MPLS_SWITCH_ACTION_POP == action_if_bos ||
   1155             BCM_MPLS_SWITCH_ACTION_POP == action_if_not_bos) {
   1156 
   1157         /* uniform qos model if either of these two flags set.
   1158          * Only apply to L3 MPLS and BOS
   1159          */
   1160         if (info->flags & (BCM_MPLS_SWITCH_OUTER_EXP |
   1161                     BCM_MPLS_SWITCH_OUTER_TTL) ) {
   1162             if (SOC_MEM_FIELD_VALID(unit,mem,
   1163                         DO_NOT_CHANGE_PAYLOAD_DSCPf)) {
   1164                 soc_mem_field32_set(unit, mem, ment,
   1165                         DO_NOT_CHANGE_PAYLOAD_DSCPf, 0);
   1166             }
   1167         }
   1168 
   1169         mode = -1;
   1170         if (_BCM_MPLS_VPN_IS_L3(info->vpn)) {
   1171             _BCM_MPLS_VPN_GET(vrf, _BCM_MPLS_VPN_TYPE_L3, info->vpn);
   1172             if (!_BCM_MPLS_VRF_USED_GET(unit, vrf)) {
   1173                 return BCM_E_PARAM;
   1174             }
   1175 
   1176             /* Check L3 Ingress Interface mode. */
   1177             mode = 0;
   1178             rv = bcm_xgs3_l3_ingress_mode_get(unit, &mode);
   1179             BCM_IF_ERROR_RETURN(rv);
   1180         }
   1181         if (!mode) {
   1182             _bcm_l3_ingress_intf_t iif;
   1183             sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t));
   1184             iif.intf_id =  _BCM_TR_MPLS_L3_IIF_BASE + vrf;
   1185             rv = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif);
   1186             BCM_IF_ERROR_RETURN(rv);
   1187 
   1188             iif.vrf = vrf;
   1189 #ifdef BCM_TOMAHAWK_SUPPORT
   1190             if (soc_feature(unit, soc_feature_ecn_wred) && 
   1191                 (info->flags & BCM_MPLS_SWITCH_TUNNEL_TERM_ECN_MAP)) {
   1192                 int ecn_map_index;
   1193                 int ecn_map_type;
   1194                 int ecn_map_num;
   1195                 ecn_map_type = info->tunnel_term_ecn_map_id & 
   1196                                 _BCM_XGS5_ECN_MAP_TYPE_MASK;
   1197                 ecn_map_index = info->tunnel_term_ecn_map_id & 
   1198                                 _BCM_XGS5_ECN_MAP_NUM_MASK;
   1199                 ecn_map_num = 
   1200                     soc_mem_index_count(unit, ING_TUNNEL_ECN_DECAPm) / 
   1201                     _BCM_ECN_MAX_ENTRIES_PER_TUNNEL_TERM_MAP;
   1202                 if (ecn_map_type != _BCM_XGS5_ECN_MAP_TYPE_TUNNEL_TERM) {
   1203                     return BCM_E_PARAM;
   1204                 }
   1205                 if (ecn_map_index >= ecn_map_num) {
   1206                     return BCM_E_PARAM;
   1207                 }
   1208                 if (!bcmi_xgs5_ecn_map_used_get(unit, ecn_map_index,
   1209                                                 _bcmEcnmapTypeTunnelTerm)) {
   1210                     return BCM_E_PARAM;
   1211                 }
   1212                 iif.tunnel_term_ecn_map_id = ecn_map_index;
   1213                 iif.flags |= BCM_L3_INGRESS_TUNNEL_TERM_ECN_MAP;
   1214             }
   1215 #endif
   1216 
   1217             rv = _bcm_tr_l3_ingress_interface_set(unit, &iif, NULL, NULL);
   1218             BCM_IF_ERROR_RETURN(rv);
   1219 
   1220             soc_mem_field32_set(unit, mem, ment, L3_IIFf,
   1221                     _BCM_TR_MPLS_L3_IIF_BASE + vrf);
   1222         } else {
   1223             soc_mem_field32_set(unit, mem, ment, L3_IIFf, info->ingress_if);
   1224         }
   1225 
   1226         if (BCM_MPLS_SWITCH_ACTION_POP == action_if_not_bos) {
   1227             if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   1228                 soc_mem_field32_set(unit, mem, ment,
   1229                         MPLS_ACTION_IF_NOT_BOSf, 
   1230                         _BCM_MPLS_TD3_MPLS_ACTION_POP);
   1231             } else {
   1232                 soc_mem_field32_set(unit, mem, ment,
   1233                         MPLS_ACTION_IF_NOT_BOSf,
   1234                         _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_POP);
   1235             }
   1236         }
   1237 
   1238         if (BCM_MPLS_SWITCH_ACTION_POP == action_if_bos) {
   1239             if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   1240                 soc_mem_field32_set(unit, mem, ment,
   1241                         MPLS_ACTION_IF_BOSf,
   1242                         _BCM_MPLS_TD3_MPLS_ACTION_L3_IIF);
   1243             } else {
   1244                 soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_BOSf,
   1245                         _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_L3_IIF);
   1246             }
   1247         }
   1248     }/*BCM_MPLS_SWITCH_ACTION_POP*/ 
   1249 
   1250     /*PHP ACTION*/
   1251     if (BCM_MPLS_SWITCH_ACTION_PHP == action_if_bos ||
   1252             BCM_MPLS_SWITCH_ACTION_PHP == action_if_not_bos) {
   1253 
   1254         if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, info->egress_if)) {
   1255             if (BCM_MPLS_SWITCH_ACTION_PHP == action_if_bos) {
   1256 
   1257                 if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   1258                     soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_BOSf,
   1259                             _BCM_MPLS_TD3_MPLS_ACTION_PHP);
   1260                 } else {
   1261                     soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_BOSf,
   1262                             _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_L3_ECMP);
   1263                 }
   1264 
   1265             }
   1266 
   1267             if (BCM_MPLS_SWITCH_ACTION_PHP == action_if_not_bos) {
   1268                 if (soc_feature(unit, soc_feature_mpls_lsr_ecmp)) {
   1269 
   1270                     if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   1271                         soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_NOT_BOSf,
   1272                                 _BCM_MPLS_TD3_MPLS_ACTION_PHP);
   1273                     } else {
   1274                         soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_NOT_BOSf,
   1275                                 _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_PHP_ECMP);
   1276                     }
   1277                 }
   1278             }
   1279         } else if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, info->egress_if)) {
   1280             if (BCM_MPLS_SWITCH_ACTION_PHP == action_if_bos) {
   1281 
   1282                 if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   1283                     soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_BOSf,
   1284                             _BCM_MPLS_TD3_MPLS_ACTION_PHP);
   1285                 } else {
   1286 #ifdef BCM_MONTEREY_SUPPORT
   1287                     if ((info->flags2 & BCM_MPLS_SWITCH2_ENABLE_ROE) ||
   1288                         (info->flags2 & BCM_MPLS_SWITCH2_ENABLE_ROE_CUSTOM)){
   1289                         soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_BOSf,
   1290                                 _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_ROE_NHI);
   1291                     } else
   1292 #endif
   1293                     {
   1294                         soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_BOSf,
   1295                                 _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_L3_NHI);
   1296                     }
   1297                 }
   1298             }
   1299 
   1300             if (BCM_MPLS_SWITCH_ACTION_PHP == action_if_not_bos) {
   1301 
   1302                 if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   1303                     soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_NOT_BOSf,
   1304                             _BCM_MPLS_TD3_MPLS_ACTION_PHP);
   1305                 } else {
   1306                     soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_NOT_BOSf,
   1307                             _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_PHP_NHI);
   1308                 }
   1309             }
   1310         } else {
   1311             return BCM_E_PARAM;
   1312         }
   1313 
   1314         /* uniform qos model if either of these two flags set.
   1315          * Only apply to L3 MPLS and BOS
   1316          */
   1317         if (info->flags & (BCM_MPLS_SWITCH_OUTER_EXP |
   1318                     BCM_MPLS_SWITCH_OUTER_TTL) ) {
   1319             if (SOC_MEM_FIELD_VALID(unit,mem,
   1320                         DO_NOT_CHANGE_PAYLOAD_DSCPf)) {
   1321                 soc_mem_field32_set(unit, mem, ment,
   1322                         DO_NOT_CHANGE_PAYLOAD_DSCPf, 0);
   1323             }
   1324         }
   1325 
   1326         /*
   1327          * Get egress next-hop index from egress object and
   1328          * increment egress object reference count.
   1329          */
   1330 
   1331         BCM_IF_ERROR_RETURN(bcm_xgs3_get_nh_from_egress_object(unit,
   1332                     info->egress_if, &mpath_flag, 1, nh_index));
   1333 
   1334         /* Fix: Entry_Type = 1, for PHP Packets with more than 1 Label */
   1335         /* Read the egress next_hop entry pointed by Egress-Object */
   1336         if (!((info->flags2 & BCM_MPLS_SWITCH2_ENABLE_ROE) ||
   1337               (info->flags2 & BCM_MPLS_SWITCH2_ENABLE_ROE_CUSTOM))) {
   1338             rv = bcm_tr_mpls_egress_entry_modify(unit, *nh_index, mpath_flag, 1);
   1339             if (rv < 0 ) {
   1340                 return rv;
   1341             }
   1342         }
   1343 
   1344         if (mpath_flag == BCM_L3_MULTIPATH) {
   1345             if (soc_feature(unit, soc_feature_generic_dest)) {
   1346                 bcmi_td3_destination_format_set(unit, ment,
   1347                         SOC_MEM_FIF_DEST_ECMP, *nh_index);
   1348             } else {
   1349                 soc_mem_field32_set(unit, mem, ment, ECMP_PTRf,
   1350                         *nh_index);
   1351             }
   1352 
   1353             /* Swap to ECMP Type  PHP_ECMP or L3_ECMP flag is set up earlier */
   1354         } else {
   1355             if (soc_feature(unit, soc_feature_generic_dest)) {
   1356                 bcmi_td3_destination_format_set(unit, ment,
   1357                         SOC_MEM_FIF_DEST_NEXTHOP, *nh_index);
   1358             } else {
   1359                 soc_mem_field32_set(unit, mem, ment, NEXT_HOP_INDEXf,
   1360                         *nh_index);
   1361             }
   1362         }
   1363 
   1364 #if defined(BCM_TRIDENT3_SUPPORT) 
   1365         /*PHP is similar to swap-to-self*/
   1366         if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   1367             if (((SOC_IS_TRIDENT3(unit) && (cancun_ver < SOC_CANCUN_VERSION_DEF_6_0_0))  ||
   1368                  (SOC_IS_MAVERICK2(unit) && (cancun_ver < SOC_CANCUN_VERSION_DEF_4_0_0)) ||
   1369                  (SOC_IS_HELIX5(unit) && (cancun_ver < SOC_CANCUN_VERSION_DEF_4_0_0))) ||
   1370                 (BCM_MPLS_SWITCH_ACTION_PHP != action_if_not_bos)) {
   1371                 soc_mem_field32_set(unit, mem, ment,
   1372                         DECAP_NEXT_FWD_LABELf, 1);
   1373 
   1374                 soc_mem_field32_set(unit, mem, ment,
   1375                         NEXT_FWD_LABEL_INHERITf, 1);
   1376 
   1377                 soc_mem_field32_set(unit, mem, ment,
   1378                         INHERITANCE_TYPEf, 1);
   1379             }
   1380 
   1381             if (BCM_MPLS_SWITCH_ACTION_PHP == action_if_bos ||
   1382                     BCM_MPLS_SWITCH_ACTION_PHP == action_if_not_bos) {
   1383                 if (info->action == BCM_MPLS_SWITCH_ACTION_INVALID) {
   1384                     info->action = BCM_MPLS_SWITCH_ACTION_PHP;
   1385                 }
   1386             }
   1387 
   1388             if (mpath_flag == BCM_L3_MULTIPATH) {
   1389                 rv = bcmi_td3_php_ecmp_nhop_vcswap_add(unit, info, *nh_index, mpath_flag);
   1390             } else {
   1391                 rv = bcmi_td3_mpls_php_vcswap_info_add(unit, info, nh_index);
   1392             }
   1393 
   1394             if (rv < 0) {
   1395                 return rv;
   1396             }
   1397         }
   1398 #endif
   1399     } /*BCM_MPLS_SWITCH_ACTION_PHP*/ 
   1400 
   1401     /*SWAP ACTION*/
   1402     if (BCM_MPLS_SWITCH_ACTION_SWAP == action_if_bos ||
   1403             BCM_MPLS_SWITCH_ACTION_SWAP == action_if_not_bos) {
   1404 
   1405         if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, info->egress_if)) {
   1406             if ((!soc_feature(unit, soc_feature_mpls_lsr_ecmp)) ||
   1407                     (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, info->egress_if))) {
   1408                 return BCM_E_PARAM;
   1409             }
   1410         }
   1411         if (BCM_XGS3_L3_MPLS_LBL_VALID(info->egress_label.label) ||
   1412                 _BCM_MPLS_EGRESS_LABEL_PRESERVE(unit, info->egress_label.flags)) {
   1413             rv = bcm_tr_mpls_l3_nh_info_add(unit, info, nh_index);
   1414             if (rv < 0) {
   1415                 *nh_index_alloc_failed = 1;
   1416                 return rv;
   1417             }
   1418             if (soc_feature(unit, soc_feature_generic_dest)) {
   1419                 bcmi_td3_destination_format_set(unit, ment,
   1420                         SOC_MEM_FIF_DEST_NEXTHOP, *nh_index);
   1421             } else {
   1422                 soc_mem_field32_set(unit, mem, ment, NEXT_HOP_INDEXf,
   1423                         *nh_index);
   1424             }
   1425 
   1426             if (BCM_MPLS_SWITCH_ACTION_SWAP == action_if_bos) {
   1427 
   1428                 if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   1429                     soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_BOSf,
   1430                             _BCM_MPLS_TD3_MPLS_ACTION_SWAP);
   1431                 } else {
   1432                     soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_BOSf,
   1433                             _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_SWAP_NHI);
   1434                 }
   1435             }
   1436 
   1437             if (BCM_MPLS_SWITCH_ACTION_SWAP == action_if_not_bos) {
   1438 
   1439                 if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   1440                     soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_NOT_BOSf,
   1441                             _BCM_MPLS_TD3_MPLS_ACTION_SWAP);
   1442                 } else {
   1443                     soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_NOT_BOSf,
   1444                             _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_SWAP_NHI);
   1445                 }
   1446             }
   1447 
   1448 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
   1449             if (_BCM_MPLS_EGRESS_LABEL_PRESERVE(unit, info->egress_label.flags)) {
   1450                 /*Decap and add swap label to achieve swap-to-self.*/
   1451                 if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   1452                     soc_mem_field32_set(unit, mem, ment,
   1453                             CURR_FWD_LABEL_INHERITf, 1);
   1454 
   1455                     soc_mem_field32_set(unit, mem, ment,
   1456                             INHERITANCE_TYPEf, 1);
   1457                 }
   1458             }
   1459 #endif
   1460         } else {
   1461             /*
   1462              * Get egress next-hop index from egress object and
   1463              * increment egress object reference count.
   1464              */
   1465             BCM_IF_ERROR_RETURN(bcm_xgs3_get_nh_from_egress_object(unit, info->egress_if,
   1466                         &mpath_flag, 1, nh_index));
   1467 
   1468             if (soc_feature(unit, soc_feature_mpls_lsr_ecmp) && (mpath_flag == BCM_L3_MULTIPATH)) {
   1469                 if (soc_feature(unit, soc_feature_generic_dest)) {
   1470                     bcmi_td3_destination_format_set(unit, ment,
   1471                             SOC_MEM_FIF_DEST_ECMP, *nh_index);
   1472                 } else {
   1473                     soc_mem_field32_set(unit, mem, ment, ECMP_PTRf,
   1474                             *nh_index);
   1475                 }
   1476 
   1477                 /* Swap to ECMP Type */
   1478                 if (BCM_MPLS_SWITCH_ACTION_SWAP == action_if_not_bos) {
   1479 
   1480                     if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   1481                         soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_NOT_BOSf,
   1482                                 _BCM_MPLS_TD3_MPLS_ACTION_SWAP);
   1483                     } else {
   1484                         soc_mem_field32_set(unit, mem, ment, MPLS__MPLS_ACTION_IF_NOT_BOSf,
   1485                                 _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_SWAP_ECMP);
   1486                     }
   1487                 }
   1488 
   1489                 if (BCM_MPLS_SWITCH_ACTION_SWAP == action_if_bos) {
   1490 
   1491                     if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   1492                         soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_BOSf,
   1493                                 _BCM_MPLS_TD3_MPLS_ACTION_SWAP);
   1494                     } else {
   1495                         soc_mem_field32_set(unit, mem, ment, MPLS__MPLS_ACTION_IF_BOSf,
   1496                                 _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_SWAP_ECMP);
   1497                     }
   1498                 }
   1499             } else {
   1500                 if (soc_feature(unit, soc_feature_generic_dest)) {
   1501                     bcmi_td3_destination_format_set(unit, ment,
   1502                             SOC_MEM_FIF_DEST_NEXTHOP, *nh_index);
   1503                 } else {
   1504                     soc_mem_field32_set(unit, mem, ment, NEXT_HOP_INDEXf,
   1505                             *nh_index);
   1506                 }
   1507                 if (BCM_MPLS_SWITCH_ACTION_SWAP == action_if_not_bos) {
   1508 
   1509                     if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   1510                         soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_NOT_BOSf,
   1511                                 _BCM_MPLS_TD3_MPLS_ACTION_SWAP);
   1512                     } else {
   1513                         soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_NOT_BOSf,
   1514                                 _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_SWAP_NHI);
   1515                     }
   1516                 }
   1517 
   1518                 if (BCM_MPLS_SWITCH_ACTION_SWAP == action_if_bos) {
   1519 
   1520                     if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   1521                         soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_BOSf,
   1522                                 _BCM_MPLS_TD3_MPLS_ACTION_SWAP);
   1523                     } else {
   1524                         soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_BOSf,
   1525                                 _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_SWAP_NHI);
   1526                     }
   1527                 }
   1528             }
   1529         }
   1530     }/* BCM_MPLS_SWITCH_ACTION_SWAP */
   1531 
   1532     /*INVALID ACTION*/
   1533     if (BCM_MPLS_SWITCH_ACTION_INVALID == action_if_bos) {
   1534 
   1535         if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   1536             soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_BOSf,
   1537                     _BCM_MPLS_TD3_MPLS_ACTION_INVALID);
   1538         } else {
   1539             soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_BOSf,
   1540                     _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_INVALID);
   1541         }
   1542     } else if (BCM_MPLS_SWITCH_ACTION_INVALID == action_if_not_bos) {
   1543 
   1544         if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   1545             soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_NOT_BOSf,
   1546                     _BCM_MPLS_TD3_MPLS_ACTION_INVALID);
   1547         } else {
   1548             soc_mem_field32_set(unit, mem, ment, MPLS_ACTION_IF_NOT_BOSf,
   1549                     _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_INVALID);
   1550         }
   1551     }
   1552 
   1553     return rv;
   1554 }
   1555 
   1556 /*
   1557  * Function:
   1558  *      bcm_mpls_tunnel_switch_add
   1559  * Purpose:
   1560  *      Add an MPLS label entry.
   1561  * Parameters:
   1562  *      unit - Device Number
   1563  *      info - Label (switch) information
   1564  * Returns:
   1565  *      BCM_E_XXX
   1566  */
   1567 int
   1568 bcmi_xgs5_mpls_tunnel_switch_add(int unit, bcm_mpls_tunnel_switch_t *info)
   1569 {
   1570     mpls_entry_entry_t ment, ment_lkup, ment_old;
   1571     int mode=0, nh_index = -1, rv, num_pw_term, old_pw_cnt = -1, pw_cnt = -1;
   1572     int idx_l3_tunnel_mem, idx_mpls_mem;
   1573     int old_nh_index = -1, old_ecmp_index = -1;
   1574     int action, action_if_bos, action_if_not_bos;
   1575     int old_action_if_bos = -1, old_action_if_not_bos = -1;
   1576     int  tunnel_switch_update=0;
   1577     int  ref_count=0;
   1578     bcm_if_t  egress_if=0;
   1579     uint32 retval = 0, dest_type =  SOC_MEM_FIF_DEST_INVALID;
   1580     int nh_index_alloc_failed = 0;
   1581     soc_mem_t mem = MPLS_ENTRYm;
   1582 
   1583     if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
   1584         mem = MPLS_ENTRY_SINGLEm;
   1585     }
   1586 
   1587     rv = bcm_xgs3_l3_egress_mode_get(unit, &mode);
   1588     BCM_IF_ERROR_RETURN(rv);
   1589     if (!mode) {
   1590         LOG_INFO(BSL_LS_BCM_L3,
   1591                  (BSL_META_U(unit,
   1592                              "L3 egress mode must be set first\n")));
   1593         return BCM_E_DISABLED;
   1594     }
   1595 
   1596     /* Check for Port_independent Label mapping */
   1597     if (!BCM_XGS3_L3_MPLS_LBL_VALID(info->label)) {
   1598         return BCM_E_PARAM;
   1599     }
   1600 
   1601     /*INT_CN TO EXP MAP is Deprecated in TD3*/
   1602     if (soc_feature(unit, soc_feature_td3_style_mpls) &&
   1603             (info->flags & BCM_MPLS_EGRESS_LABEL_INT_CN_TO_EXP_MAP)) {
   1604         return BCM_E_UNAVAIL;
   1605     }
   1606 
   1607     rv = bcm_tr_mpls_port_independent_range (unit, info->label, info->port);
   1608     if (rv < 0) {
   1609         return rv;
   1610     }
   1611 
   1612 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   1613     if (soc_feature(unit, soc_feature_mpls_frr_lookup)) {
   1614         if (info->flags & BCM_MPLS_SWITCH_FRR) {
   1615             rv = _bcm_tr3_mpls_tunnel_switch_frr_set(unit, info);
   1616             return rv;
   1617          }
   1618     }
   1619 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_APACHE_SUPPORT */
   1620 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   1621     if((soc_feature(unit, soc_feature_fp_based_oam) ||
   1622          soc_feature(unit, soc_feature_td3_style_fp)) &&
   1623                 SOC_MEM_FIELD_VALID(unit, MPLS_ENTRYm, CLASS_IDf)) {
   1624         /*Ensure that class_id doesnt overcross CLASS_IDf*/
   1625         int bit_num = 0;
   1626         if((info->flags & BCM_MPLS_SWITCH_COUNTED) && (info->class_id)) {
   1627             return BCM_E_PARAM;
   1628         }
   1629         if(info->class_id) {
   1630             if ((bit_num = soc_mem_field_length(unit, mem, CLASS_IDf)) > 0) {
   1631 #if defined(BCM_MONTEREY_SUPPORT)
   1632                 if (soc_feature(unit,soc_feature_mont_roe_classid_sw_war)) {
   1633                     bit_num -= 1;
   1634                 }
   1635 #endif
   1636             }
   1637             if(info->class_id > (( 1 << bit_num ) - 1)) {
   1638                 return BCM_E_PARAM;
   1639             }
   1640         }
   1641     }
   1642 #endif
   1643 
   1644     action = info->action;
   1645     if (info->action_if_bos != info->action_if_not_bos) {
   1646         action = BCM_MPLS_SWITCH_ACTION_INVALID;
   1647         action_if_bos = info->action_if_bos;
   1648         action_if_not_bos = info->action_if_not_bos;
   1649     } else {
   1650         /* 
   1651          * Same action specified in if_bos and if_not_bos.
   1652          * If this action is of valid type, it will override
   1653          * the action specified in info->action
   1654          */
   1655         if (info->action_if_bos != BCM_MPLS_SWITCH_ACTION_INVALID) {
   1656             action = info->action_if_bos;
   1657         }
   1658         action_if_bos = action_if_not_bos = action;
   1659     }
   1660 
   1661     if (!(BCM_MPLS_SWITCH_ACTION_SWAP == action_if_bos ||
   1662           BCM_MPLS_SWITCH_ACTION_SWAP == action_if_not_bos ||
   1663           BCM_MPLS_SWITCH_ACTION_POP == action_if_bos ||
   1664           BCM_MPLS_SWITCH_ACTION_POP == action_if_not_bos ||
   1665           BCM_MPLS_SWITCH_ACTION_PHP == action_if_bos ||
   1666           BCM_MPLS_SWITCH_ACTION_PHP == action_if_not_bos)) {
   1667         return BCM_E_PARAM;
   1668     }
   1669     if ((info->egress_label.flags & BCM_MPLS_EGRESS_LABEL_PRESERVE) &&
   1670         (BCM_MPLS_SWITCH_ACTION_SWAP != action_if_bos ||
   1671          BCM_MPLS_SWITCH_ACTION_SWAP != action_if_not_bos)) {
   1672         return BCM_E_PARAM;
   1673     }
   1674 
   1675 #ifdef BCM_MONTEREY_SUPPORT
   1676     if (!soc_feature(unit,soc_feature_roe)) {
   1677         if (info->flags2 & BCM_MPLS_SWITCH2_ENABLE_ROE) {
   1678             return BCM_E_UNAVAIL;
   1679         }
   1680     }
   1681     if (!soc_feature(unit,soc_feature_roe_custom)) {
   1682         if (info->flags2 & BCM_MPLS_SWITCH2_ENABLE_ROE_CUSTOM) {
   1683             return BCM_E_UNAVAIL;
   1684         }
   1685     }
   1686     if ((info->flags2 & BCM_MPLS_SWITCH2_ENABLE_ROE) && 
   1687         (info->flags2 & BCM_MPLS_SWITCH2_ENABLE_ROE_CUSTOM)) {
   1688         return BCM_E_PARAM;
   1689     }
   1690 #endif
   1691 
   1692     BCM_IF_ERROR_RETURN(_bcmi_xgs5_mpls_entry_set_key(unit, info, &ment));
   1693 
   1694     /* See if entry already exists */
   1695     rv = soc_mem_search(unit, mem, MEM_BLOCK_ANY, &idx_mpls_mem,
   1696                         &ment, &ment, 0);
   1697 
   1698     if ((SOC_E_NONE == rv) &&
   1699         soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
   1700         /* For TH3, if there exists an entry in MPLS_ENTRY_SINGLE table then
   1701          * cache it, as at later stage the cached copy can be used to revert
   1702          * the MPLS_ENTRY_SINGLE entry to its original format if the insertion
   1703          * fails in L3_TUNNEL_SINGLEm
   1704          */
   1705         sal_memcpy(&ment_old, &ment, sizeof(mpls_entry_entry_t));
   1706     }
   1707 
   1708     /* default not to use DSCP from ING_MPLS_EXP_MAPPING table */
   1709     if (SOC_MEM_FIELD_VALID(unit,mem,DO_NOT_CHANGE_PAYLOAD_DSCPf)) {
   1710         if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   1711             soc_mem_field32_set(unit, mem, &ment,
   1712                                           DO_NOT_CHANGE_PAYLOAD_DSCPf, 0);
   1713         } else {
   1714             soc_mem_field32_set(unit, mem, &ment,
   1715                                           DO_NOT_CHANGE_PAYLOAD_DSCPf, 1);
   1716         }
   1717     }
   1718 
   1719     if (rv == SOC_E_NONE) {
   1720         /* Entry exists, save old info */
   1721         tunnel_switch_update = 1;
   1722         old_action_if_bos = soc_mem_field32_get(unit, mem, &ment,
   1723                                                         MPLS_ACTION_IF_BOSf);
   1724         old_action_if_not_bos = soc_mem_field32_get(unit, mem, &ment,
   1725                 MPLS_ACTION_IF_NOT_BOSf);
   1726 
   1727         if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   1728             /*TD3 old mpls actions*/
   1729             if ((old_action_if_bos == _BCM_MPLS_TD3_MPLS_ACTION_SWAP) ||
   1730                     (old_action_if_not_bos == _BCM_MPLS_TD3_MPLS_ACTION_SWAP) ||
   1731                     (old_action_if_bos == _BCM_MPLS_TD3_MPLS_ACTION_PHP) ||
   1732                     (old_action_if_not_bos == _BCM_MPLS_TD3_MPLS_ACTION_PHP)) {
   1733 
   1734                 retval = soc_mem_field32_dest_get(unit, MPLS_ENTRYm, &ment,
   1735                         DESTINATIONf, &dest_type);
   1736                 if (dest_type == SOC_MEM_FIF_DEST_ECMP) {
   1737                     old_ecmp_index = retval;
   1738                 }
   1739 
   1740                 if (dest_type == SOC_MEM_FIF_DEST_NEXTHOP) {
   1741                     old_nh_index = retval;
   1742                 }
   1743             }
   1744 
   1745             if (((old_action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_SWAP_ECMP) ||
   1746                         (old_action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_SWAP_ECMP)) &&
   1747                     soc_feature(unit, soc_feature_mpls_lsr_ecmp)) {
   1748 
   1749                 retval = soc_mem_field32_dest_get(unit, mem, &ment,
   1750                         DESTINATIONf, &dest_type);
   1751 
   1752                 if (dest_type == SOC_MEM_FIF_DEST_ECMP) {
   1753                     old_ecmp_index = retval;
   1754                 }
   1755             }
   1756 
   1757         } else {
   1758 
   1759             if ((old_action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_SWAP_NHI) ||
   1760                     (old_action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_SWAP_NHI) ||
   1761                     (old_action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_L3_NHI) ||
   1762                     (old_action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_PHP_NHI) ||
   1763                     (old_action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_ROE_NHI)) {
   1764                 old_nh_index = soc_mem_field32_get(unit, mem, &ment, NEXT_HOP_INDEXf);
   1765             }
   1766             if ((old_action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_L3_ECMP) ||
   1767                     (old_action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_PHP_ECMP)) {
   1768                 old_ecmp_index = soc_mem_field32_get(unit, mem, &ment, ECMP_PTRf);
   1769             }
   1770             if (((old_action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_SWAP_ECMP) ||
   1771                         (old_action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_SWAP_ECMP)) &&
   1772                     soc_feature(unit, soc_feature_mpls_lsr_ecmp)) {
   1773                 old_ecmp_index = soc_mem_field32_get(unit, mem, &ment, ECMP_PTRf);
   1774             }
   1775         }
   1776         if (SOC_MEM_FIELD_VALID(unit, mem, PW_TERM_NUM_VALIDf)) {
   1777             if (soc_mem_field32_get(unit, mem, &ment, PW_TERM_NUM_VALIDf)) {
   1778                 old_pw_cnt = soc_mem_field32_get(unit, mem, &ment, PW_TERM_NUMf);
   1779             }
   1780         }
   1781     } else if (rv != SOC_E_NOT_FOUND) {
   1782         return rv;
   1783     }
   1784 
   1785     rv = bcmi_xgs5_mpls_entry_label_actions_set(unit, action_if_bos,
   1786             action_if_not_bos, info, &ment, &nh_index, &nh_index_alloc_failed);
   1787 
   1788     if (rv < 0) {
   1789         goto cleanup;
   1790     }
   1791 
   1792     soc_mem_field32_set(unit, mem, &ment, V4_ENABLEf, 1);
   1793     soc_mem_field32_set(unit, mem, &ment, V6_ENABLEf, 1);
   1794 
   1795     if (info->flags & BCM_MPLS_SWITCH_INNER_TTL) {
   1796         if (BCM_MPLS_SWITCH_ACTION_SWAP == action_if_bos &&
   1797             BCM_MPLS_SWITCH_ACTION_SWAP == action_if_not_bos) {
   1798             rv = BCM_E_PARAM;
   1799             goto cleanup;
   1800         }
   1801         soc_mem_field32_set(unit, mem, &ment, DECAP_USE_TTLf, 0);
   1802     } else {
   1803         soc_mem_field32_set(unit, mem, &ment, DECAP_USE_TTLf, 1);
   1804     }
   1805 
   1806     if (info->flags & BCM_MPLS_SWITCH_INNER_EXP) {
   1807         if (BCM_MPLS_SWITCH_ACTION_SWAP == action_if_bos &&
   1808             BCM_MPLS_SWITCH_ACTION_SWAP == action_if_not_bos) {
   1809             rv = BCM_E_PARAM;
   1810             goto cleanup;
   1811         }
   1812         soc_mem_field32_set(unit, mem, &ment, DECAP_USE_EXP_FOR_INNERf, 0);
   1813     } else {
   1814         /* For SWAP, Do-not PUSH EXP */
   1815         if (BCM_MPLS_SWITCH_ACTION_SWAP == action_if_bos &&
   1816             BCM_MPLS_SWITCH_ACTION_SWAP == action_if_not_bos) {
   1817             soc_mem_field32_set(unit, mem, &ment, DECAP_USE_EXP_FOR_INNERf, 0);
   1818         } else {
   1819             soc_mem_field32_set(unit, mem, &ment, DECAP_USE_EXP_FOR_INNERf, 1);
   1820         }
   1821     }
   1822 
   1823 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   1824     if (soc_feature(unit, soc_feature_td2p_mpls_linear_protection)){
   1825         int local_failover_id = 0;
   1826         int prot_type         = 0;
   1827         if (info->flags & BCM_MPLS_SWITCH_DROP) {
   1828             soc_mem_field32_set(unit, mem, &ment,
   1829                     MPLS__DROP_DATA_ENABLEf, 1);
   1830         } else {
   1831             soc_mem_field32_set(unit, mem, &ment,
   1832                     MPLS__DROP_DATA_ENABLEf, 0);
   1833         }
   1834 
   1835         if (info->failover_id != 0) {
   1836             local_failover_id = info->failover_id;
   1837             _BCM_GET_FAILOVER_TYPE(local_failover_id, prot_type);
   1838             _BCM_GET_FAILOVER_ID(local_failover_id);
   1839             if ((prot_type & _BCM_FAILOVER_INGRESS) &&
   1840                 (BCM_SUCCESS(_bcm_td2p_failover_ingress_id_validate(
   1841                 unit, local_failover_id)))) {
   1842                 soc_mem_field32_set(unit, mem, &ment,
   1843                                             MPLS__RX_PROT_GROUPf,
   1844                                             local_failover_id);
   1845             }
   1846         } else {
   1847             soc_mem_field32_set(unit, mem, &ment,
   1848                                         MPLS__RX_PROT_GROUPf, 0);
   1849         }
   1850     }
   1851 #endif
   1852 
   1853 #if defined(BCM_TOMAHAWK2_SUPPORT)
   1854     if (SOC_IS_TOMAHAWK2(unit)){
   1855         int local_failover_id = 0;
   1856         int prot_type         = 0;
   1857         if (info->flags & BCM_MPLS_SWITCH_DROP) {
   1858             soc_mem_field32_set(unit, mem, &ment,
   1859                     MPLS__DROP_DATA_ENABLEf, 1);
   1860         } else {
   1861             soc_mem_field32_set(unit, mem, &ment,
   1862                     MPLS__DROP_DATA_ENABLEf, 0);
   1863         }
   1864 
   1865         if (info->failover_id != 0) {
   1866             local_failover_id = info->failover_id;
   1867             _BCM_GET_FAILOVER_TYPE(local_failover_id, prot_type);
   1868             _BCM_GET_FAILOVER_ID(local_failover_id);
   1869             if ((prot_type & _BCM_FAILOVER_INGRESS) &&
   1870                 (BCM_SUCCESS(_bcm_th2_failover_ingress_id_validate(
   1871                 unit, local_failover_id)))) {
   1872                 soc_mem_field32_set(unit, mem, &ment,
   1873                                             MPLS__RX_PROT_GROUPf,
   1874                                             local_failover_id);
   1875             }
   1876         } else {
   1877             soc_mem_field32_set(unit, mem, &ment,
   1878                                         MPLS__RX_PROT_GROUPf, 0);
   1879         }
   1880     }
   1881 #endif
   1882 
   1883 
   1884     
   1885     (void) bcm_tr_mpls_entry_internal_qos_set(unit, NULL, info, &ment);
   1886 
   1887     if ((info->flags & BCM_MPLS_SWITCH_COUNTED)) {
   1888         if (SOC_MEM_IS_VALID(unit, ING_PW_TERM_COUNTERSm)) {
   1889             if (old_pw_cnt == -1) {
   1890                 num_pw_term = soc_mem_index_count(unit, ING_PW_TERM_COUNTERSm);
   1891                 for (pw_cnt = 0; pw_cnt < num_pw_term; pw_cnt++) {
   1892                     if (!_BCM_MPLS_PW_TERM_USED_GET(unit, pw_cnt)) {
   1893                         break;
   1894                     }
   1895                 }
   1896                 if (pw_cnt == num_pw_term) {
   1897                     rv = BCM_E_RESOURCE;
   1898                     goto cleanup;
   1899                 }
   1900                 _BCM_MPLS_PW_TERM_USED_SET(unit, pw_cnt);
   1901                 soc_mem_field32_set(unit, mem, &ment, PW_TERM_NUMf, pw_cnt);
   1902                 soc_mem_field32_set(unit, mem, &ment, PW_TERM_NUM_VALIDf, 1);
   1903             }
   1904         } else if (SOC_MEM_IS_VALID(unit, ING_PW_TERM_SEQ_NUMm)) {
   1905             if (old_pw_cnt == -1) {
   1906                 num_pw_term = soc_mem_index_count(unit, ING_PW_TERM_SEQ_NUMm);
   1907                 for (pw_cnt = 0; pw_cnt < num_pw_term; pw_cnt++) {
   1908                     if (!_BCM_MPLS_PW_TERM_USED_GET(unit, pw_cnt)) {
   1909                         break;
   1910                     }
   1911                 }
   1912                 if (pw_cnt == num_pw_term) {
   1913                     rv = BCM_E_RESOURCE;
   1914                     goto cleanup;
   1915                 }
   1916                 _BCM_MPLS_PW_TERM_USED_SET(unit, pw_cnt);
   1917                 soc_mem_field32_set(unit, mem, &ment, PW_TERM_NUMf, pw_cnt);
   1918                 soc_mem_field32_set(unit, mem, &ment, PW_TERM_NUM_VALIDf, 1);
   1919             }
   1920         }        
   1921     }
   1922 
   1923 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   1924     else if ((soc_feature(unit, soc_feature_fp_based_oam) ||
   1925                 soc_feature(unit, soc_feature_td3_style_fp)) &&
   1926                 SOC_MEM_FIELD_VALID(unit, MPLS_ENTRYm, CLASS_IDf)) {
   1927         soc_mem_field32_set(unit, mem, &ment, CLASS_IDf, info->class_id);
   1928     }
   1929 #endif
   1930 
   1931 #ifdef BCM_MONTEREY_SUPPORT
   1932     /* Enable ROE or ROE Custom frame handling */
   1933     if (SOC_MEM_FIELD_VALID(unit,MPLS_ENTRYm,ROE_TYPEf)) {
   1934         if (info->flags2 & BCM_MPLS_SWITCH2_ENABLE_ROE) {
   1935             soc_mem_field32_set(unit, mem, &ment,
   1936                     ROE_TYPEf, _BCM_MPLS_XGS5_MPLS_ROE_TUNNEL);
   1937         } else if (info->flags2 & BCM_MPLS_SWITCH2_ENABLE_ROE_CUSTOM) {
   1938             soc_mem_field32_set(unit, mem, &ment,
   1939                     ROE_TYPEf, _BCM_MPLS_XGS5_MPLS_ROE_CUSTOM_TUNNEL);
   1940         } else {
   1941             soc_mem_field32_set(unit, mem, &ment, ROE_TYPEf, 0);
   1942         }
   1943     }
   1944 #endif
   1945 
   1946 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 
   1947     if (soc_feature(unit, soc_feature_mpls_ecn)) {
   1948         if (info->flags & BCM_MPLS_SWITCH_INGRESS_ECN_MAP) { 
   1949             int ecn_map_index;
   1950             int ecn_map_type;
   1951             int ecn_map_num;
   1952             int ecn_map_hw_idx;
   1953             soc_mem_t mem_map;
   1954 
   1955             ecn_map_type = info->ecn_map_id & _BCM_XGS5_MPLS_ECN_MAP_TYPE_MASK;
   1956             ecn_map_index = info->ecn_map_id & _BCM_XGS5_MPLS_ECN_MAP_NUM_MASK;
   1957 
   1958 #if defined(BCM_TRIDENT3_SUPPORT)
   1959             if(soc_feature(unit, soc_feature_td3_style_mpls)) {
   1960                 mem_map = ING_EXP_TO_ECN_MAPPING_1m;
   1961             } else
   1962 #endif
   1963             {
   1964                 mem_map = ING_EXP_TO_IP_ECN_MAPPINGm;
   1965             }
   1966 
   1967             ecn_map_num = 
   1968                 soc_mem_index_count(unit, mem_map) /
   1969                 _BCM_ECN_MAX_ENTRIES_PER_MAP;
   1970             if (ecn_map_type != _BCM_XGS5_MPLS_ECN_MAP_TYPE_EXP2ECN) {
   1971                 rv = BCM_E_PARAM;
   1972                 goto cleanup;
   1973             }
   1974             if (ecn_map_index >= ecn_map_num) {
   1975                 rv = BCM_E_PARAM;
   1976                 goto cleanup;
   1977             }
   1978             if (!bcmi_xgs5_ecn_map_used_get(unit, ecn_map_index, 
   1979                                             _bcmEcnmapTypeExp2Ecn)) {
   1980                 rv = BCM_E_PARAM;
   1981                 goto cleanup; 
   1982             }
   1983             if (bcmi_ecn_map_id2hw_idx(unit, info->ecn_map_id, &ecn_map_hw_idx)) {
   1984                 rv = BCM_E_PARAM;
   1985                 goto cleanup; 
   1986             }
   1987 #if defined(BCM_TRIDENT3_SUPPORT)
   1988             if(soc_feature(unit, soc_feature_td3_style_mpls)) {
   1989                 soc_MPLS_ENTRYm_field32_set(unit, &ment,
   1990                         EXP_TO_ECN_MAPPING_PTRf,
   1991                                         ecn_map_hw_idx);
   1992             } else
   1993 #endif
   1994             {
   1995                 soc_mem_field32_set(unit, mem, &ment, 
   1996                                      EXP_TO_IP_ECN_MAPPING_PTRf,
   1997                                      ecn_map_hw_idx);
   1998             }
   1999         }
   2000     }
   2001 #endif
   2002 
   2003 #if defined(BCM_TRIDENT3_SUPPORT)
   2004     if (BCM_MPLS_SWITCH_ACTION_SWAP == action_if_bos ||
   2005             BCM_MPLS_SWITCH_ACTION_SWAP == action_if_not_bos) {
   2006         if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   2007             /*It is needed for SWAPTOSELF scenarios*/
   2008             soc_mem_field32_set(unit, mem, &ment,
   2009                     CURR_FWD_LABEL_INHERITf, 1);
   2010 
   2011             soc_mem_field32_set(unit, mem, &ment,
   2012                     INHERITANCE_TYPEf, 1);
   2013         }
   2014     }
   2015 #endif
   2016 
   2017     if (!tunnel_switch_update) {
   2018         rv = soc_mem_insert(unit, mem, MEM_BLOCK_ALL, &ment);
   2019         if (BCM_SUCCESS(rv) &&
   2020             soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
   2021             rv = soc_mem_insert(unit, L3_TUNNEL_SINGLEm, MEM_BLOCK_ALL, &ment);
   2022             if (rv < 0) {
   2023                 /* Revert the insertion into MPLS_ENTRY_SINGLEm */
   2024                 (void)soc_mem_delete(unit, mem, MEM_BLOCK_ALL, &ment);
   2025             }
   2026         }
   2027     } else {
   2028         rv = soc_mem_write(unit, mem,
   2029                            MEM_BLOCK_ALL, idx_mpls_mem,
   2030                            &ment);
   2031         if (BCM_SUCCESS(rv) &&
   2032             soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
   2033             rv = _bcmi_xgs5_mpls_entry_set_key(unit, info, &ment_lkup);
   2034             if (BCM_SUCCESS(rv)) {
   2035                 rv = soc_mem_search(unit, L3_TUNNEL_SINGLEm, MEM_BLOCK_ANY,
   2036                                  &idx_l3_tunnel_mem, &ment_lkup, &ment_lkup, 0);
   2037                 if (BCM_SUCCESS(rv)) {
   2038                     rv = soc_mem_write(unit, L3_TUNNEL_SINGLEm,
   2039                                    MEM_BLOCK_ALL, idx_l3_tunnel_mem,
   2040                                    &ment);
   2041                 }
   2042             }
   2043 
   2044             if (rv < 0) {
   2045                 /* Revert the write into MPLS_ENTRY_SINGLEm */
   2046                 (void)soc_mem_write(
   2047                         unit, mem, MEM_BLOCK_ALL, idx_mpls_mem, &ment_old);
   2048             }
   2049         }
   2050     }
   2051 
   2052     if (rv < 0) {
   2053         goto cleanup;
   2054     }
   2055 
   2056     if (tunnel_switch_update) {
   2057         /* Clean up old next-hop and counter info if entry was replaced */
   2058         if ((old_pw_cnt != -1) && !(info->flags & BCM_MPLS_SWITCH_COUNTED)) {
   2059             _BCM_MPLS_PW_TERM_USED_CLR(unit, old_pw_cnt);
   2060         }
   2061 
   2062         if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   2063 
   2064             if ((old_action_if_bos == _BCM_MPLS_TD3_MPLS_ACTION_SWAP) ||
   2065                     (old_action_if_not_bos == _BCM_MPLS_TD3_MPLS_ACTION_SWAP)) {
   2066                 /* Check if tunnel_switch.egress_label mode is being used */
   2067                 if (dest_type == SOC_MEM_FIF_DEST_NEXTHOP) {
   2068 
   2069                     rv = bcm_tr_mpls_get_vp_nh (unit, (bcm_if_t) old_nh_index, &egress_if);
   2070                     if (rv == BCM_E_NONE) {
   2071                         rv = bcm_tr_mpls_l3_nh_info_delete(unit, old_nh_index);
   2072                     } else {
   2073                         /* Decrement next-hop Reference count */
   2074                         rv = bcm_xgs3_get_ref_count_from_nhi(unit, 0, &ref_count, old_nh_index);
   2075                     }
   2076                 }
   2077             }
   2078 
   2079             if ((old_action_if_bos == _BCM_MPLS_TD3_MPLS_ACTION_PHP) ||
   2080                     (old_action_if_not_bos == _BCM_MPLS_TD3_MPLS_ACTION_PHP)) {
   2081 
   2082                 if (dest_type == SOC_MEM_FIF_DEST_NEXTHOP) {
   2083                     rv = bcm_xgs3_nh_del(unit, 0, old_nh_index);
   2084                 }
   2085 
   2086                 if (dest_type == SOC_MEM_FIF_DEST_ECMP) {
   2087                     rv = bcm_xgs3_ecmp_group_del(unit, old_ecmp_index, 0);
   2088                 }
   2089             }
   2090 
   2091             if (soc_feature(unit, soc_feature_mpls_lsr_ecmp) &&
   2092                     ((old_action_if_bos == _BCM_MPLS_TD3_MPLS_ACTION_SWAP) ||
   2093                      (old_action_if_not_bos == _BCM_MPLS_TD3_MPLS_ACTION_SWAP))) {
   2094 
   2095                 if (dest_type == SOC_MEM_FIF_DEST_ECMP) {
   2096                     rv = bcm_xgs3_ecmp_group_del(unit, old_ecmp_index, 0);
   2097                 }
   2098             }
   2099 
   2100         } else {
   2101             if ((old_action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_SWAP_NHI) ||
   2102                     (old_action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_SWAP_NHI)) {
   2103                 /* Check if tunnel_switch.egress_label mode is being used */
   2104                 rv = bcm_tr_mpls_get_vp_nh (unit, (bcm_if_t) old_nh_index, &egress_if);
   2105                 if (rv == BCM_E_NONE) {
   2106                     rv = bcm_tr_mpls_l3_nh_info_delete(unit, old_nh_index);
   2107                 } else {
   2108                     /* Decrement next-hop Reference count */
   2109                     rv = bcm_xgs3_get_ref_count_from_nhi(unit, 0, &ref_count, old_nh_index);
   2110                 }
   2111             }
   2112             if ((old_action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_L3_NHI) ||
   2113                 (old_action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_ROE_NHI) ||
   2114                 (old_action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_PHP_NHI)) {
   2115                 rv = bcm_xgs3_nh_del(unit, 0, old_nh_index);
   2116             } 
   2117             if ((old_action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_L3_ECMP) ||
   2118                     (old_action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_PHP_ECMP)) {
   2119                 rv = bcm_xgs3_ecmp_group_del(unit, old_ecmp_index, 0);
   2120             }
   2121             if (soc_feature(unit, soc_feature_mpls_lsr_ecmp) &&
   2122                     ((old_action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_SWAP_ECMP) ||
   2123                      (old_action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_SWAP_ECMP))) {
   2124                 rv = bcm_xgs3_ecmp_group_del(unit, old_ecmp_index, 0);
   2125             }
   2126         }
   2127     }
   2128 
   2129     if (rv < 0) {
   2130         goto cleanup;
   2131     }
   2132 
   2133 #ifdef BCM_WARM_BOOT_SUPPORT
   2134     SOC_CONTROL_LOCK(unit);
   2135     SOC_CONTROL(unit)->scache_dirty = 1;
   2136     SOC_CONTROL_UNLOCK(unit);
   2137 #endif
   2138 
   2139     return rv;
   2140 
   2141   cleanup:
   2142     if (nh_index_alloc_failed) {
   2143         return rv;
   2144     }
   2145     if (pw_cnt != -1) {
   2146         _BCM_MPLS_PW_TERM_USED_CLR(unit, pw_cnt);
   2147     }
   2148     /* coverity[check_after_sink : FALSE] */
   2149     if (nh_index != -1) {
   2150         if ((action_if_bos == BCM_MPLS_SWITCH_ACTION_SWAP) ||
   2151             (action_if_not_bos == BCM_MPLS_SWITCH_ACTION_SWAP)) {
   2152             if (BCM_XGS3_L3_MPLS_LBL_VALID(info->egress_label.label) ||
   2153                 (info->action == BCM_MPLS_SWITCH_ACTION_PHP)) {
   2154                 (void) bcm_tr_mpls_l3_nh_info_delete(unit, nh_index);
   2155             }
   2156         } else if ((action_if_bos == BCM_MPLS_SWITCH_ACTION_PHP) ||
   2157                    (action_if_not_bos == BCM_MPLS_SWITCH_ACTION_PHP)) {
   2158             (void) bcm_xgs3_nh_del(unit, 0, nh_index);
   2159         }
   2160     }
   2161     return rv;
   2162 }
   2163 
   2164 STATIC int
   2165 _bcmi_xgs5_mpls_entry_delete(int unit, mpls_entry_entry_t *ment)
   2166 {   
   2167     ing_pw_term_counters_entry_t pw_cnt_entry;
   2168     int rv, ecmp_index = -1, nh_index = -1, pw_cnt = -1;
   2169     int action_if_bos, action_if_not_bos;
   2170     bcm_if_t  egress_if=0;
   2171     int  ref_count=0;
   2172     uint32  dest_type = SOC_MEM_FIF_DEST_INVALID;
   2173     uint32 value=0;
   2174     soc_mem_t mem = MPLS_ENTRYm;
   2175 
   2176     if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
   2177         mem = MPLS_ENTRY_SINGLEm;
   2178     }
   2179 
   2180     if (SOC_MEM_FIELD_VALID(unit, mem, PW_TERM_NUM_VALIDf)) {
   2181         if (soc_mem_field32_get(unit, mem, ment, PW_TERM_NUM_VALIDf)) {
   2182             pw_cnt = soc_mem_field32_get(unit, mem, ment, PW_TERM_NUMf);
   2183         }
   2184     }
   2185 
   2186     action_if_bos = soc_mem_field32_get(unit, mem, ment, MPLS_ACTION_IF_BOSf);
   2187     action_if_not_bos = soc_mem_field32_get(unit, mem, ment,
   2188                                                       MPLS_ACTION_IF_NOT_BOSf);
   2189 
   2190     if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   2191         if ((action_if_bos == _BCM_MPLS_TD3_MPLS_ACTION_SWAP) ||
   2192                 (action_if_not_bos == _BCM_MPLS_TD3_MPLS_ACTION_SWAP) ||
   2193                 (action_if_bos == _BCM_MPLS_TD3_MPLS_ACTION_PHP) ||
   2194                 (action_if_not_bos == _BCM_MPLS_TD3_MPLS_ACTION_PHP)) {
   2195 
   2196             value = soc_mem_field32_dest_get(unit, MPLS_ENTRYm, ment,
   2197                     DESTINATIONf, &dest_type);
   2198 
   2199             if (dest_type == SOC_MEM_FIF_DEST_NEXTHOP) {
   2200                 nh_index = value;
   2201             }
   2202             if (dest_type == SOC_MEM_FIF_DEST_ECMP) {
   2203                 ecmp_index = value;
   2204             }
   2205         }
   2206 #if 0
   2207         if ((action_if_bos == _BCM_MPLS_TD3_MPLS_ACTION_PHP) ||
   2208                 (action_if_not_bos == _BCM_MPLS_TD3_MPLS_ACTION_PHP)) {
   2209             ecmp_index = soc_mem_field32_get(unit, mem, ment, ECMP_PTRf);
   2210         }
   2211 #endif
   2212 
   2213         if (((action_if_bos == _BCM_MPLS_TD3_MPLS_ACTION_SWAP) ||
   2214                     (action_if_not_bos == _BCM_MPLS_TD3_MPLS_ACTION_SWAP)) &&
   2215                 soc_feature(unit, soc_feature_mpls_lsr_ecmp)) {
   2216 
   2217             value = soc_mem_field32_dest_get(unit, mem, ment,
   2218                     DESTINATIONf, &dest_type);
   2219 
   2220             if (dest_type == SOC_MEM_FIF_DEST_ECMP) {
   2221                 ecmp_index = value;
   2222             }
   2223         }
   2224     } else {
   2225         if ((action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_SWAP_NHI) ||
   2226                 (action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_SWAP_NHI) ||
   2227                 (action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_L3_NHI) ||
   2228                 (action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_ROE_NHI) ||
   2229                 (action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_PHP_NHI)) {
   2230             nh_index = soc_mem_field32_get(unit, mem, ment, NEXT_HOP_INDEXf);
   2231         }
   2232         if ((action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_L3_ECMP) ||
   2233                 (action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_PHP_ECMP)) {
   2234             ecmp_index = soc_mem_field32_get(unit, mem, ment, ECMP_PTRf);
   2235         }
   2236         if (((action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_SWAP_ECMP) ||
   2237                     (action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_SWAP_ECMP)) &&
   2238                 soc_feature(unit, soc_feature_mpls_lsr_ecmp)) {
   2239             ecmp_index = soc_mem_field32_get(unit, mem, ment, ECMP_PTRf);
   2240         }
   2241     }
   2242     /* Delete the entry from HW */
   2243     rv = soc_mem_delete(unit, mem, MEM_BLOCK_ALL, ment);
   2244     if ( (rv != BCM_E_NOT_FOUND) && (rv != BCM_E_NONE) ) {
   2245          return rv;
   2246     }
   2247 
   2248     if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
   2249         rv = soc_mem_delete(unit, L3_TUNNEL_SINGLEm, MEM_BLOCK_ALL, ment);
   2250         if ( (rv != BCM_E_NOT_FOUND) && (rv != BCM_E_NONE) ) {
   2251              return rv;
   2252         }
   2253     }
   2254 
   2255     if (pw_cnt != -1) {
   2256         if (SOC_MEM_IS_VALID(unit, ING_PW_TERM_SEQ_NUMm)) {
   2257             ing_pw_term_seq_num_entry_t pw_seq_num_entry;
   2258 
   2259             sal_memset(&pw_seq_num_entry, 0, sizeof(ing_pw_term_seq_num_entry_t));
   2260             (void) WRITE_ING_PW_TERM_SEQ_NUMm(unit, MEM_BLOCK_ALL, pw_cnt,
   2261                                                &pw_seq_num_entry);
   2262         } else {
   2263             sal_memset(&pw_cnt_entry, 0, sizeof(ing_pw_term_counters_entry_t));
   2264             (void) WRITE_ING_PW_TERM_COUNTERSm(unit, MEM_BLOCK_ALL, pw_cnt,
   2265                                                &pw_cnt_entry);
   2266         }
   2267 
   2268         _BCM_MPLS_PW_TERM_USED_CLR(unit, pw_cnt);
   2269     }
   2270 
   2271     if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   2272         if ((action_if_bos == _BCM_MPLS_TD3_MPLS_ACTION_SWAP) ||
   2273                 (action_if_not_bos == _BCM_MPLS_TD3_MPLS_ACTION_SWAP)) {
   2274             /* Check if tunnel_switch.egress_label mode is being used */
   2275             if (dest_type == SOC_MEM_FIF_DEST_NEXTHOP) {
   2276                 rv = bcm_tr_mpls_get_vp_nh (unit, (bcm_if_t) nh_index, &egress_if);
   2277                 if (rv == BCM_E_NONE) {
   2278                     rv = bcm_tr_mpls_l3_nh_info_delete(unit, nh_index);
   2279                 } else {
   2280                     /* Decrement next-hop Reference count */
   2281                     rv = bcm_xgs3_get_ref_count_from_nhi(unit, 0, &ref_count, nh_index);
   2282                 }
   2283             }
   2284         }
   2285 
   2286         if ((action_if_bos == _BCM_MPLS_TD3_MPLS_ACTION_PHP) ||
   2287                 (action_if_not_bos == _BCM_MPLS_TD3_MPLS_ACTION_PHP)) {
   2288 
   2289             if (dest_type == SOC_MEM_FIF_DEST_NEXTHOP) {
   2290 #if defined(BCM_TRIDENT3_SUPPORT)
   2291                 rv = bcmi_td3_mpls_php_vcswap_info_delete(unit,
   2292                         nh_index, dest_type);
   2293                 /* Decrement next-hop Reference count */
   2294                 rv = bcm_xgs3_get_ref_count_from_nhi(unit, 0,
   2295                         &ref_count, nh_index);
   2296 #endif
   2297                 rv = bcm_xgs3_nh_del(unit, 0, nh_index);
   2298             }
   2299 
   2300             if (dest_type == SOC_MEM_FIF_DEST_ECMP) {
   2301 #if defined(BCM_TRIDENT3_SUPPORT)
   2302                 rv = bcmi_td3_php_ecmp_nhop_vcswap_delete(unit,
   2303                         ecmp_index, dest_type,BCM_L3_MULTIPATH);
   2304                 /* Decrement next-hop Reference count */
   2305                 rv = bcm_xgs3_get_ref_count_from_nhi(unit, 0,
   2306                         &ref_count, ecmp_index);
   2307 #endif
   2308                 rv = bcm_xgs3_ecmp_group_del(unit, ecmp_index, 0);
   2309             }
   2310         }
   2311 
   2312         if (soc_feature(unit, soc_feature_mpls_lsr_ecmp) &&
   2313                 ((action_if_bos == _BCM_MPLS_TD3_MPLS_ACTION_SWAP) ||
   2314                  (action_if_not_bos == _BCM_MPLS_TD3_MPLS_ACTION_SWAP))) {
   2315 
   2316             if (dest_type == SOC_MEM_FIF_DEST_ECMP) {
   2317                 rv = bcm_xgs3_ecmp_group_del(unit, ecmp_index, 0);
   2318             }
   2319         }
   2320     } else {
   2321         if ((action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_SWAP_NHI) ||
   2322                 (action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_SWAP_NHI)) {
   2323             /* Check if tunnel_switch.egress_label mode is being used */
   2324             rv = bcm_tr_mpls_get_vp_nh (unit, (bcm_if_t) nh_index, &egress_if);
   2325             if (rv == BCM_E_NONE) {
   2326                 rv = bcm_tr_mpls_l3_nh_info_delete(unit, nh_index);
   2327             } else {
   2328                 /* Decrement next-hop Reference count */
   2329                 rv = bcm_xgs3_get_ref_count_from_nhi(unit, 0, &ref_count, nh_index);
   2330             }
   2331         }
   2332         if ((action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_L3_NHI) ||
   2333             (action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_ROE_NHI) ||
   2334                 (action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_PHP_NHI)) {
   2335             rv = bcm_xgs3_nh_del(unit, 0, nh_index);
   2336         }
   2337         if ((action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_L3_ECMP) ||
   2338                 (action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_PHP_ECMP)) {
   2339             rv = bcm_xgs3_ecmp_group_del(unit, ecmp_index, 0);
   2340         }
   2341         if (soc_feature(unit, soc_feature_mpls_lsr_ecmp) &&
   2342                 ((action_if_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_SWAP_ECMP) ||
   2343                  (action_if_not_bos == _BCM_MPLS_XGS5_MPLS_ACTION_IF_NOT_BOS_SWAP_ECMP))) {
   2344             rv = bcm_xgs3_ecmp_group_del(unit, ecmp_index, 0);
   2345         }
   2346     }
   2347 
   2348     return rv;
   2349 }
   2350 
   2351 /*
   2352  * Function:
   2353  *      bcm_mpls_tunnel_switch_delete
   2354  * Purpose:
   2355  *      Delete an MPLS label entry.
   2356  * Parameters:
   2357  *      unit - Device Number
   2358  *      info - Label (switch) information
   2359  * Returns:
   2360  *      BCM_E_XXX
   2361  */
   2362 int
   2363 bcmi_xgs5_mpls_tunnel_switch_delete(int unit, bcm_mpls_tunnel_switch_t *info)
   2364 {
   2365     int rv, index;
   2366     mpls_entry_entry_t ment;
   2367     soc_mem_t mem = MPLS_ENTRYm;
   2368 
   2369     if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
   2370         mem = MPLS_ENTRY_SINGLEm;
   2371     }
   2372 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   2373     if (soc_feature(unit, soc_feature_mpls_frr_lookup) && 
   2374         (info->flags & BCM_MPLS_SWITCH_FRR)) { 
   2375         rv = _bcm_tr3_mpls_tunnel_switch_frr_delete(unit, info);
   2376     } else
   2377 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_APACHE_SUPPORT */
   2378     {
   2379         rv = _bcmi_xgs5_mpls_entry_set_key(unit, info, &ment);
   2380         BCM_IF_ERROR_RETURN(rv);
   2381 
   2382         rv = soc_mem_search(unit, mem, MEM_BLOCK_ANY, &index,
   2383                 &ment, &ment, 0);
   2384         if (rv < 0) {
   2385             return rv;
   2386         }
   2387         rv = _bcmi_xgs5_mpls_entry_delete(unit, &ment);
   2388     }
   2389 
   2390 #ifdef BCM_WARM_BOOT_SUPPORT
   2391     SOC_CONTROL_LOCK(unit);
   2392     SOC_CONTROL(unit)->scache_dirty = 1;
   2393     SOC_CONTROL_UNLOCK(unit);
   2394 #endif
   2395 
   2396     return rv;
   2397 }
   2398 
   2399 /*
   2400  * Function:
   2401  *      bcm_mpls_tunnel_switch_delete_all
   2402  * Purpose:
   2403  *      Delete all MPLS label entries.
   2404  * Parameters:
   2405  *      unit   - Device Number
   2406  * Returns:
   2407  *      BCM_E_XXX
   2408  */
   2409 int
   2410 bcmi_xgs5_mpls_tunnel_switch_delete_all(int unit)
   2411 {
   2412     int rv = BCM_E_NONE, i;
   2413     mpls_entry_entry_t *ment = NULL;
   2414     int index_min, index_max;
   2415     uint8 *mpls_entry_buf = NULL;
   2416 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   2417     int num_entries;
   2418     soc_tunnel_term_t tnl_entry;
   2419 #endif
   2420     soc_mem_t mem = MPLS_ENTRYm;
   2421     soc_field_t validf = VALIDf;
   2422 
   2423     if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
   2424         mem = MPLS_ENTRY_SINGLEm;
   2425         validf = BASE_VALIDf;
   2426     }
   2427 
   2428     mpls_entry_buf = soc_cm_salloc(unit,
   2429             SOC_MEM_TABLE_BYTES(unit, mem), "MPLS_ENTRY buffer");
   2430     if (NULL == mpls_entry_buf) {
   2431         return BCM_E_MEMORY;
   2432     }
   2433 
   2434     index_min = soc_mem_index_min(unit, mem);
   2435     index_max = soc_mem_index_max(unit, mem);
   2436     rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY,
   2437             index_min, index_max, mpls_entry_buf);
   2438     if (SOC_FAILURE(rv)) {
   2439         if (mpls_entry_buf) {
   2440             soc_cm_sfree(unit, mpls_entry_buf);
   2441         }
   2442         return rv;
   2443     }
   2444 
   2445     for (i = index_min; i <= index_max; i++) {
   2446         ment = soc_mem_table_idx_to_pointer
   2447             (unit, mem, mpls_entry_entry_t *, mpls_entry_buf, i);
   2448 
   2449         /* Check for valid entry */
   2450         if (soc_feature(unit, soc_feature_td3_style_mpls)){
   2451             if (soc_mem_field32_get(unit, mem, ment, BASE_VALID_0f) != 3) {
   2452                 continue;
   2453             }
   2454             if (soc_mem_field32_get(unit, mem, ment, BASE_VALID_1f) != 7) {
   2455                 continue;
   2456             }
   2457         } else {
   2458             if (!soc_mem_field32_get(unit, mem, ment, validf)) {
   2459                 continue;
   2460             }
   2461         }
   2462         if (soc_mem_field32_get(unit, mem, ment, MPLS_ACTION_IF_BOSf) ==
   2463                 _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_L2_SVP) {
   2464             /* L2_SVP */
   2465             continue;
   2466         }
   2467 
   2468         rv = _bcmi_xgs5_mpls_entry_delete(unit, ment);
   2469         if (BCM_FAILURE(rv)) {
   2470             if (mpls_entry_buf) {
   2471                 soc_cm_sfree(unit, mpls_entry_buf);
   2472             }
   2473             return rv;
   2474         }
   2475     }
   2476 
   2477     if (mpls_entry_buf) {
   2478         soc_cm_sfree(unit, mpls_entry_buf);
   2479     }
   2480 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   2481     if (soc_feature(unit, soc_feature_mpls_frr_lookup)) {
   2482         num_entries = soc_mem_index_count(unit, L3_TUNNELm);
   2483         for (i = 0; i < num_entries; i++) {
   2484             sal_memset(&tnl_entry, 0, sizeof(tnl_entry));
   2485             rv = READ_L3_TUNNELm(unit, MEM_BLOCK_ANY, i,
   2486                 (uint32 *)&tnl_entry.entry_arr[0]);
   2487             if (rv < 0) {
   2488                 return rv;
   2489             }
   2490             if (!soc_L3_TUNNELm_field32_get(unit, &tnl_entry, VALIDf)) {
   2491                 continue;
   2492             }
   2493             if (0x2 != soc_L3_TUNNELm_field32_get(unit, &tnl_entry, MODEf)) {
   2494                 continue;
   2495             }
   2496 
   2497             rv = soc_tunnel_term_delete(unit, &tnl_entry);
   2498             if (rv < 0) {
   2499                 return rv;
   2500             }
   2501 
   2502             /*_soc_tunnel_term_slot_free() api moves last entry to
   2503              *deleted entry position using _soc_tunnel_term_entry_shift().
   2504              *Therefore adding this index change to support delete all*/
   2505             i--;
   2506         }
   2507     }
   2508 #endif
   2509 
   2510     return BCM_E_NONE;
   2511 }
   2512 
   2513 /*
   2514  * Function:
   2515  *      bcm_mpls_tunnel_switch_get
   2516  * Purpose:
   2517  *      Get an MPLS label entry.
   2518  * Parameters:
   2519  *      unit - Device Number
   2520  *      info - Label (switch) information
   2521  * Returns:
   2522  *      BCM_E_XXX
   2523  */
   2524 int
   2525 bcmi_xgs5_mpls_tunnel_switch_get(int unit, bcm_mpls_tunnel_switch_t *info)
   2526 {
   2527     int rv, index;
   2528     mpls_entry_entry_t ment;
   2529     soc_mem_t mem = MPLS_ENTRYm;
   2530 
   2531     if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
   2532         mem = MPLS_ENTRY_SINGLEm;
   2533     }
   2534 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   2535     if (soc_feature(unit, soc_feature_mpls_frr_lookup) && 
   2536         (info->flags & BCM_MPLS_SWITCH_FRR)) { 
   2537         rv = _bcm_tr3_mpls_tunnel_switch_frr_get(unit, info, &index);
   2538     } else
   2539 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_APACHE_SUPPORT */
   2540     {
   2541 
   2542         rv = _bcmi_xgs5_mpls_entry_set_key(unit, info, &ment);
   2543 
   2544         BCM_IF_ERROR_RETURN(rv);
   2545 
   2546         rv = soc_mem_search(unit, mem, MEM_BLOCK_ANY, &index,
   2547                 &ment, &ment, 0);
   2548 
   2549         if (rv < 0) {
   2550             return rv;
   2551         }
   2552 
   2553         if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   2554             rv =  bcmi_td3_mpls_entry_get_data(unit, &ment, info);
   2555         } else {
   2556             rv = _bcmi_xgs5_mpls_entry_get_data(unit, &ment, info);
   2557         }
   2558     }
   2559     return rv;
   2560 }
   2561 
   2562 /*
   2563  * Function:
   2564  *      bcm_mpls_tunnel_switch_traverse
   2565  * Purpose:
   2566  *      Traverse all valid MPLS label entries an call the
   2567  *      supplied callback routine.
   2568  * Parameters:
   2569  *      unit      - Device Number
   2570  *      cb        - User callback function, called once per MPLS entry.
   2571  *      user_data - cookie
   2572  * Returns:
   2573  *      BCM_E_XXX
   2574  */
   2575 int
   2576 bcmi_xgs5_mpls_tunnel_switch_traverse(int unit, 
   2577                                    bcm_mpls_tunnel_switch_traverse_cb cb,
   2578                                    void *user_data)
   2579 {
   2580     int rv, i;
   2581     mpls_entry_entry_t *ment = NULL;
   2582     bcm_mpls_tunnel_switch_t info;
   2583 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   2584     soc_tunnel_term_t *tnl_entry = NULL;
   2585     uint32 key_type=0;
   2586     uint8 *tnl_entry_buf = NULL;
   2587 #endif
   2588    int index_min, index_max;
   2589     uint8 *mpls_entry_buf = NULL;
   2590     soc_mem_t mem = MPLS_ENTRYm;
   2591     soc_field_t validf = VALIDf;
   2592 
   2593     if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
   2594         mem = MPLS_ENTRY_SINGLEm;
   2595         validf = BASE_VALIDf;
   2596     }
   2597 
   2598     mpls_entry_buf = soc_cm_salloc(unit,
   2599             SOC_MEM_TABLE_BYTES(unit, mem), "MPLS_ENTRY buffer");
   2600     if (NULL == mpls_entry_buf) {
   2601         rv = BCM_E_MEMORY;
   2602         goto cleanup;
   2603     }
   2604 
   2605     index_min = soc_mem_index_min(unit, mem);
   2606     index_max = soc_mem_index_max(unit, mem);
   2607     rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY,
   2608             index_min, index_max, mpls_entry_buf);
   2609     if (SOC_FAILURE(rv)) {
   2610         goto cleanup;
   2611     }
   2612 
   2613     for (i = index_min; i <= index_max; i++) {
   2614         ment = soc_mem_table_idx_to_pointer
   2615             (unit, mem, mpls_entry_entry_t *, mpls_entry_buf, i);
   2616 
   2617         /* Check for valid entry */
   2618         if (SOC_IS_TRIDENT3X(unit)) {
   2619             if (soc_mem_field32_get(unit, mem, ment, BASE_VALID_0f) != 3) {
   2620                 continue;
   2621             }
   2622             if (soc_mem_field32_get(unit, mem, ment, BASE_VALID_1f) != 7) {
   2623                 continue;
   2624             }
   2625         } else {
   2626             if (!soc_mem_field32_get(unit, mem, ment, validf)) {
   2627                 continue;
   2628             }
   2629         }
   2630         /* Check MPLS Key_type */
   2631         if (soc_feature(unit, soc_feature_mpls_enhanced)) {
   2632             if (0x0 != soc_mem_field32_get(unit, mem, ment, KEY_TYPEf)) {
   2633                 continue;
   2634             }
   2635         }
   2636         if (soc_mem_field32_get(unit, mem, ment, MPLS_ACTION_IF_BOSf) ==
   2637                 _BCM_MPLS_XGS5_MPLS_ACTION_IF_BOS_L2_SVP) {
   2638             continue;
   2639         }
   2640         sal_memset(&info, 0, sizeof(bcm_mpls_tunnel_switch_t));
   2641         rv = _bcmi_xgs5_mpls_entry_get_key(unit, ment, &info);
   2642         if (rv < 0) {
   2643             goto cleanup;
   2644         }
   2645 
   2646         if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   2647             rv =  bcmi_td3_mpls_entry_get_data(unit, ment, &info);
   2648         } else {
   2649             rv = _bcmi_xgs5_mpls_entry_get_data(unit, ment, &info);
   2650         }
   2651         if (rv < 0) {
   2652             goto cleanup;
   2653         }
   2654         rv = cb(unit, &info, user_data);
   2655 #ifdef BCM_CB_ABORT_ON_ERR
   2656         if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   2657             goto cleanup;
   2658         }
   2659 #endif
   2660     }
   2661 
   2662 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   2663     if (soc_feature(unit, soc_feature_mpls_frr_lookup)) {
   2664 
   2665         /* traverse L3_TUNNEL entries */
   2666         tnl_entry_buf = soc_cm_salloc(unit,
   2667                 SOC_MEM_TABLE_BYTES(unit, L3_TUNNELm), "L3_TUNNEL buffer");
   2668         if (NULL == tnl_entry_buf) {
   2669             rv = BCM_E_MEMORY;
   2670             goto cleanup;
   2671         }
   2672 
   2673         index_min = soc_mem_index_min(unit, L3_TUNNELm);
   2674         index_max = soc_mem_index_max(unit, L3_TUNNELm);
   2675         rv = soc_mem_read_range(unit, L3_TUNNELm, MEM_BLOCK_ANY,
   2676                 index_min, index_max, tnl_entry_buf);
   2677         if (SOC_FAILURE(rv)) {
   2678             goto cleanup;
   2679         }
   2680 
   2681         for (i = index_min; i <= index_max; i++) {
   2682             tnl_entry = soc_mem_table_idx_to_pointer
   2683                 (unit, L3_TUNNELm, soc_tunnel_term_t *, tnl_entry_buf, i);
   2684 
   2685             if (!soc_L3_TUNNELm_field32_get (unit, tnl_entry, VALIDf)) {
   2686                 continue;
   2687             }
   2688 
   2689             /* Check for MPLS entry key  */
   2690             key_type = soc_L3_TUNNELm_field32_get(unit, tnl_entry, MODEf);
   2691             if (key_type != 0x2) {
   2692                 continue;
   2693             }
   2694 
   2695             sal_memset(&info, 0, sizeof(bcm_mpls_tunnel_switch_t));
   2696             rv = _bcm_tr3_mpls_tunnel_switch_frr_entry_key_get (unit, tnl_entry, &info);
   2697             if (rv < 0) {
   2698                 goto cleanup;
   2699             }
   2700 
   2701             (void) _bcm_tr3_mpls_tunnel_switch_frr_parse(unit, tnl_entry, &info);
   2702 
   2703             rv = cb(unit, &info, user_data);
   2704 #ifdef BCM_CB_ABORT_ON_ERR
   2705             if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   2706                 goto cleanup;
   2707             }
   2708 #endif
   2709         }
   2710     }
   2711 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_APACHE_SUPPORT */
   2712 
   2713 cleanup:
   2714     if (mpls_entry_buf) {
   2715         soc_cm_sfree(unit, mpls_entry_buf);
   2716     }
   2717 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   2718     if (tnl_entry_buf) {
   2719         soc_cm_sfree(unit, tnl_entry_buf);
   2720     }
   2721 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_APACHE_SUPPORT */
   2722     return rv;
   2723 }
   2724 
   2725 /***************************************************
   2726  ***************************************************
   2727  ******                                       ******
   2728  ******  Segment Routing Feature Development. ******
   2729  */
   2730 
   2731 /*
   2732  * Function:
   2733  *      bcmi_egr_ip_tnl_mpls_free_indexes_init
   2734  * Purpose:
   2735  *      Initilize the free indexes.
   2736  * Parameters:
   2737  *      unit - Device Number
   2738  *      fi   - Pointer to free index structure.
   2739  * Returns:
   2740  *      None.
   2741  */
   2742 void
   2743 bcmi_egr_ip_tnl_mpls_free_indexes_init(int unit,
   2744                 bcmi_egr_ip_tnl_free_indexes_t *fi)
   2745 {
   2746 
   2747     int idx = 0,free_idx = 0;
   2748 
   2749     /* MAX_FREE_ENTRY = */
   2750     for (;idx < MAX_ENTRY_INDEXES; idx++) {
   2751         /* MAX FREE ENTRY COUNTING = 8 */
   2752             free_idx=0;
   2753         fi->free_index_count[idx]=0;
   2754         for (; free_idx<MAX_FREE_ENTRY_INDEXES; free_idx++) {
   2755             fi->free_entry_indexes[idx][free_idx] = -1;
   2756         }
   2757 
   2758     }
   2759 }
   2760 
   2761 /*
   2762  * Function:
   2763  *      bcmi_egr_ip_tnl_mpls_free_indexes_clear
   2764  * Purpose:
   2765  *      clear free indexes structure in tunnel.
   2766  *      When cleaning the full tunnel entry,
   2767  *      we also need to free any free entry
   2768  *      associated with this tunnel.
   2769  * Parameters:
   2770  *      unit   - Device Number
   2771  *      tnl_id - (IN)Tunnel index.
   2772  *      fi     - (IN)Pointer to free index structure.
   2773  * Returns:
   2774  *      None.
   2775  */
   2776 
   2777 void
   2778 bcmi_egr_ip_tnl_mpls_free_indexes_clear(int unit, int tnl_id,
   2779                 bcmi_egr_ip_tnl_free_indexes_t *fi)
   2780 {
   2781     int idx = 0,free_idx = 0;
   2782     int idx_min = tnl_id * _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit);
   2783     int idx_max = idx_min + _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit);
   2784     int entry_count = 0;
   2785 
   2786     for (idx=0;idx < MAX_ENTRY_INDEXES; idx++) {
   2787         /* MAX FREE ENTRY COUNTING = 8 */
   2788         entry_count = fi->free_index_count[idx];
   2789         if (entry_count) {
   2790             for (free_idx=0; free_idx<MAX_FREE_ENTRY_INDEXES; free_idx++) {
   2791 
   2792                 entry_count = fi->free_index_count[idx];
   2793                 if (fi->free_entry_indexes[idx][free_idx] == -1) {
   2794                     continue;
   2795                 }
   2796 
   2797                 if ((fi->free_entry_indexes[idx][free_idx] >= idx_min) &&
   2798                     (fi->free_entry_indexes[idx][free_idx] < idx_max)) {
   2799 
   2800 
   2801                     if (free_idx == (entry_count - 1)) {
   2802                         /* This is the last entry in free list. just clean it.*/
   2803                         fi->free_entry_indexes[idx][free_idx] = -1;
   2804                     } else {
   2805                         fi->free_entry_indexes[idx][free_idx] =
   2806                             fi->free_entry_indexes[idx][entry_count -1];
   2807 
   2808                         fi->free_entry_indexes[idx][entry_count -1] = -1;
   2809                     }
   2810                     fi->free_index_count[idx]--;
   2811                     free_idx = -1;
   2812                 }
   2813             }
   2814         }
   2815     }
   2816 }
   2817 
   2818 /*
   2819  * Function:
   2820  *      bcmi_egr_ip_tnl_mpls_free_indexes_dump
   2821  * Purpose:
   2822  *      Dump free indexes.
   2823  * Parameters:
   2824  *      unit - Device Number
   2825  *      fi   - Pointer to free index structure.
   2826  * Returns:
   2827  *      None.
   2828  */
   2829 void
   2830 bcmi_egr_ip_tnl_mpls_free_indexes_dump(int unit,
   2831                 bcmi_egr_ip_tnl_free_indexes_t *fi)
   2832 {
   2833 
   2834     int idx = 0,free_idx = 0;
   2835 
   2836     /* MAX_FREE_ENTRY = */
   2837     for (;idx < MAX_ENTRY_INDEXES; idx++) {
   2838         /* MAX FREE ENTRY COUNTING = 8 */
   2839         free_idx=0;
   2840         LOG_ERROR(BSL_LS_BCM_L3,
   2841             (BSL_META_U(unit, "%s:%d: tnl idx = %d, count = %d \n"),
   2842             __FUNCTION__, __LINE__, idx, fi->free_index_count[idx]));
   2843 
   2844        for (; free_idx<MAX_FREE_ENTRY_INDEXES; free_idx++) {
   2845             if (fi->free_entry_indexes[idx][free_idx] == -1) {
   2846                 continue;
   2847             }
   2848 
   2849             LOG_CLI((BSL_META_U(unit, "start idx[%d] = %d "),
   2850                 free_idx, fi->free_entry_indexes[idx][free_idx]));
   2851         }
   2852 
   2853         LOG_CLI((BSL_META_U(unit, "\n")));
   2854     }
   2855 }
   2856 
   2857 /*
   2858  * Function:
   2859  *      bcmi_egr_ip_tunnel_mpls_sw_cleanup
   2860  * Purpose:
   2861  *      cleanup and deallocate sw state for mpls tunnel.
   2862  * Parameters:
   2863  *      unit - Device Number
   2864  * Returns:
   2865  *      BCM_E_NONE.
   2866  */
   2867 int
   2868 bcmi_egr_ip_tunnel_mpls_sw_cleanup(int unit)
   2869 {
   2870     bcmi_egr_ip_tnl_mpls_tunnel_entry_t **tnl_sw_entry;
   2871     int num_ip_tnl_mpls;
   2872     int i,j;
   2873     soc_mem_t mem;
   2874 
   2875     mem = bcmi_egr_ip_tnl_mem_name_get(unit);
   2876 
   2877     num_ip_tnl_mpls = soc_mem_index_count(unit, mem);
   2878 
   2879     tnl_sw_entry = egr_mpls_tnl_sw_state[unit];
   2880 
   2881     if (tnl_sw_entry == NULL) {
   2882         return BCM_E_NONE;
   2883     }
   2884 
   2885     for (i=0; i<num_ip_tnl_mpls; i++) {
   2886 
   2887         if (tnl_sw_entry[i] == NULL) {
   2888             continue;
   2889         }
   2890 
   2891         if (tnl_sw_entry[i]->label_entry == NULL) {
   2892             continue;
   2893         }
   2894 
   2895         for (j=0; j<_BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit); j++) {
   2896 
   2897             if (tnl_sw_entry[i]->label_entry[j] == NULL) {
   2898                 continue;
   2899             }
   2900 
   2901             sal_free(tnl_sw_entry[i]->label_entry[j]);
   2902             tnl_sw_entry[i]->label_entry[j] = NULL;
   2903         }
   2904 
   2905         sal_free(tnl_sw_entry[i]->label_entry);
   2906         tnl_sw_entry[i]->label_entry = NULL;
   2907 
   2908         sal_free(tnl_sw_entry[i]);
   2909         tnl_sw_entry[i] = NULL;
   2910     }
   2911 
   2912     sal_free(tnl_sw_entry);
   2913     tnl_sw_entry = NULL;
   2914 
   2915     return BCM_E_NONE;
   2916 }
   2917 
   2918 /*
   2919  * Function:
   2920  *      bcmi_egr_ip_tunnel_mpls_sw_init
   2921  * Purpose:
   2922  *      initialize s/w state for egress mpls tunnel.
   2923  * Parameters:
   2924  *      unit - Device Number
   2925  * Returns:
   2926  *      BCME_XXX.
   2927  */
   2928 int
   2929 bcmi_egr_ip_tunnel_mpls_sw_init(int unit)
   2930 {
   2931     int num_ip_tnl_mpls;
   2932     int i,j;
   2933     int ent_per_tnl = _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit);
   2934     soc_mem_t mem;
   2935 
   2936     mem = bcmi_egr_ip_tnl_mem_name_get(unit);
   2937 
   2938     num_ip_tnl_mpls = soc_mem_index_count(unit, mem);
   2939 
   2940     egr_mpls_tnl_sw_state[unit] = (bcmi_egr_ip_tnl_mpls_tunnel_entry_t **)
   2941         sal_alloc((num_ip_tnl_mpls *
   2942             sizeof(bcmi_egr_ip_tnl_mpls_tunnel_entry_t *)),
   2943         "egress mpls tunnel sw state");
   2944 
   2945     if (egr_mpls_tnl_sw_state[unit] == NULL) {
   2946         return BCM_E_MEMORY;
   2947     }
   2948     sal_memset(egr_mpls_tnl_sw_state[unit], 0,
   2949         (num_ip_tnl_mpls * sizeof(bcmi_egr_ip_tnl_mpls_tunnel_entry_t *)));
   2950 
   2951     for (i=0; i<num_ip_tnl_mpls; i++) {
   2952         egr_mpls_tnl_sw_state[unit][i] = (bcmi_egr_ip_tnl_mpls_tunnel_entry_t *)
   2953             sal_alloc((sizeof(bcmi_egr_ip_tnl_mpls_tunnel_entry_t)),
   2954             "egress mpls tunnel entry");
   2955 
   2956         sal_memset(egr_mpls_tnl_sw_state[unit][i], 0,
   2957             sizeof(bcmi_egr_ip_tnl_mpls_tunnel_entry_t));
   2958 
   2959         if (egr_mpls_tnl_sw_state[unit][i] == NULL) {
   2960             bcmi_egr_ip_tunnel_mpls_sw_cleanup(unit);
   2961             return BCM_E_MEMORY;
   2962         }
   2963 
   2964         egr_mpls_tnl_sw_state[unit][i]->label_entry =
   2965             (bcmi_egr_ip_tnl_mpls_label_entry_t **)
   2966             sal_alloc((ent_per_tnl *
   2967                 sizeof(bcmi_egr_ip_tnl_mpls_label_entry_t *)),
   2968             "egress mpls tunnel label bucket");
   2969 
   2970         if (egr_mpls_tnl_sw_state[unit][i]->label_entry == NULL) {
   2971             bcmi_egr_ip_tunnel_mpls_sw_cleanup(unit);
   2972             return BCM_E_MEMORY;
   2973         }
   2974 
   2975         for (j=0; j<_BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit); j++) {
   2976             egr_mpls_tnl_sw_state[unit][i]->label_entry[j] =
   2977                 (bcmi_egr_ip_tnl_mpls_label_entry_t *)
   2978                 sal_alloc((sizeof(bcmi_egr_ip_tnl_mpls_label_entry_t)),
   2979                 "egress mpls tunnel label entry");
   2980 
   2981             if (egr_mpls_tnl_sw_state[unit][i]->label_entry[j] == NULL) {
   2982                 bcmi_egr_ip_tunnel_mpls_sw_cleanup(unit);
   2983                 return BCM_E_MEMORY;
   2984             }
   2985 
   2986             egr_mpls_tnl_sw_state[unit][i]->label_entry[j]->intf_list = NULL;
   2987             egr_mpls_tnl_sw_state[unit][i]->label_entry[j]->flags = 0;
   2988             egr_mpls_tnl_sw_state[unit][i]->label_entry[j]->num_elements = 0;
   2989         }
   2990     }
   2991     bcmi_egr_ip_tnl_mpls_free_indexes_init(unit, &(fi_db[unit]));
   2992     return 0;
   2993 }
   2994 
   2995 /*
   2996  * Function:
   2997  *      bcmi_egr_ip_tnl_mpls_tunnel_ref_count_get
   2998  * Purpose:
   2999  *      get the current reference Count
   3000  * Parameters:
   3001  *      unit              Unit number
   3002  *      index            (IN) Entry Index
   3003  */
   3004 
   3005 STATIC void
   3006 bcmi_egr_ip_tnl_mpls_tunnel_ref_count_get(int unit, int index, int *cnt_value)
   3007 {
   3008     bcmi_mpls_bookkeeping_t *mpls_info = MPLS_INFO(unit);
   3009 
   3010     *cnt_value = mpls_info->egr_tunnel_ref_count[index];
   3011 }
   3012 
   3013 /*
   3014  * Function:
   3015  *      bcmi_egr_ip_tnl_mpls_ref_count_adjust
   3016  * Purpose:
   3017  *      Increment / Decrement Reference Count for Egress Tunnel
   3018  * Parameters:
   3019  *      unit              Unit number
   3020  *      index            (IN) Entry Index
   3021  *      step             (IN) no of references
   3022  */
   3023 
   3024 STATIC void
   3025 bcmi_egr_ip_tnl_mpls_ref_count_adjust (int unit, int index, int step)
   3026 {
   3027     bcmi_mpls_bookkeeping_t *mpls_info = MPLS_INFO(unit);
   3028 
   3029     if (( mpls_info->egr_tunnel_ref_count[index] == 0 ) && (step < 0)) {
   3030          mpls_info->egr_tunnel_ref_count[index] = 0;
   3031     } else {
   3032          mpls_info->egr_tunnel_ref_count[index] += step;
   3033     }
   3034 
   3035 }
   3036 
   3037 /*
   3038  * Function:
   3039  *      bcmi_egr_ip_tnl_mpls_ref_count_reset
   3040  * Purpose:
   3041  *      reset the reference Count
   3042  * Parameters:
   3043  *      unit              Unit number
   3044  *      index             (IN) Entry Index
   3045  */
   3046 
   3047 STATIC void
   3048 bcmi_egr_ip_tnl_mpls_ref_count_reset (int unit, int index)
   3049 {
   3050     bcmi_mpls_bookkeeping_t *mpls_info = MPLS_INFO(unit);
   3051 
   3052     mpls_info->egr_tunnel_ref_count[index] = 0;
   3053 }
   3054 
   3055 /*
   3056  * Function:
   3057  *      bcmi_egr_ip_tnl_mpls_check_dup_free_index
   3058  * Purpose:
   3059  *      check for duplicate free index.
   3060  * Parameters:
   3061  *      unit              Unit number
   3062  *      fi                (IN) free index structure.
   3063  *      free_entry_idx    (IN) free index where we should look.
   3064  *      mpls_tnl_idx      (IN) original mpls tnl idx.
   3065  * Return
   3066  *      TRUE/FALSE;
   3067  */
   3068 int
   3069 bcmi_egr_ip_tnl_mpls_check_dup_free_index(int unit,
   3070                       bcmi_egr_ip_tnl_free_indexes_t *fi,
   3071                       int free_entry_num, int mpls_tnl_idx)
   3072 {
   3073 
   3074     int free_idx=0;
   3075     int ent_idx = free_entry_num - 1;
   3076 
   3077     for (; free_idx < 8; free_idx++) {
   3078         if (fi->free_index_count[ent_idx]) {
   3079             if (fi->free_entry_indexes[ent_idx][free_idx] == -1) {
   3080                 break;
   3081             }
   3082             if (fi->free_entry_indexes[ent_idx][free_idx] == mpls_tnl_idx) {
   3083                 return TRUE;
   3084             }
   3085 
   3086         }
   3087     }
   3088     return FALSE;
   3089 }
   3090 
   3091 /*
   3092  * Function:
   3093  *      bcmi_egr_ip_tnl_mpls_free_idx_update
   3094  * Purpose:
   3095  *      check for duplicate free index.
   3096  * Parameters:
   3097  *      unit              Unit number
   3098  *      fi                (IN) free index structure.
   3099  *      free_entries      (IN) no of free entries.
   3100  *      start_index       (IN) start index.
   3101  * Return
   3102  *      TRUE/FALSE;
   3103  */
   3104 void
   3105 bcmi_egr_ip_tnl_mpls_free_idx_update(int unit, int free_entries,
   3106         int start_index, bcmi_egr_ip_tnl_free_indexes_t *fi)
   3107 {
   3108     int free_entry_count;
   3109 
   3110     if (!(bcmi_egr_ip_tnl_mpls_check_dup_free_index(unit,
   3111         fi, free_entries, start_index))) {
   3112 
   3113         if (fi->free_index_count[free_entries-1] < MAX_FREE_ENTRY_INDEXES) {
   3114             free_entry_count = fi->free_index_count[free_entries-1];
   3115             fi->free_entry_indexes[free_entries-1][free_entry_count] = start_index;
   3116             fi->free_index_count[free_entries-1]++;
   3117         }
   3118     }
   3119 }
   3120 
   3121 /*
   3122  * Function:
   3123  *      bcm_egr_ip_tnl_mpls_remark_free_indexes
   3124  * Purpose:
   3125  *      Mark correct free indexes for mpls tunnel entries.
   3126  * Parameters:
   3127  *      unit         - Device Number
   3128  *      free_entries - number of free entries
   3129  *      start_index  - Start index of tunnel entry
   3130  *      fi           - free indexes database pointer.
   3131  * Returns:
   3132  *      BCM_E_XXX
   3133  */
   3134 bcm_error_t
   3135 bcm_egr_ip_tnl_mpls_remark_free_indexes(int unit, int free_entries,
   3136         int start_index, bcmi_egr_ip_tnl_free_indexes_t *fi)
   3137 {
   3138     int temp_free_entries;
   3139     int ent_per_tnl = _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit);
   3140 
   3141     if (free_entries == 0) {
   3142         return BCM_E_NONE;
   3143     }
   3144     if (start_index == -1) {
   3145         return BCM_E_NONE;
   3146     }
   3147 
   3148     /*
   3149      * if start index is 0, then any entry can be put there.
   3150      * if start index is 4, then only 3 and 4 number of entries
   3151      * can be put there.
   3152      */
   3153     if (((start_index % ent_per_tnl) == 0) ||
   3154         (((start_index %
   3155             (ent_per_tnl / 2)) == 0) &&
   3156         ((free_entries > 2) && free_entries < 5))) {
   3157 
   3158         bcmi_egr_ip_tnl_mpls_free_idx_update(unit, free_entries,
   3159             start_index, fi);
   3160     } else {
   3161         if ((free_entries >= 4)
   3162                 && ((((start_index + free_entries) %  ent_per_tnl) == 0))) {
   3163 
   3164             /*
   3165              * the entry is free till end and has more
   3166              * than 4 consecutive spaces then
   3167              * break them into smaller and take
   3168              * 4 spaces into single big entry.
   3169              */
   3170             temp_free_entries = free_entries - 4;
   3171             while(temp_free_entries > 0) {
   3172                 if (temp_free_entries == 1) {
   3173                     bcmi_egr_ip_tnl_mpls_free_idx_update(unit, 1,
   3174                         start_index, fi);
   3175 
   3176                     start_index++;
   3177                     temp_free_entries--;
   3178                 } else if (temp_free_entries >= 2) {
   3179 
   3180                     bcmi_egr_ip_tnl_mpls_free_idx_update(unit, 2,
   3181                         start_index, fi);
   3182 
   3183                     start_index +=2;
   3184                     temp_free_entries-=2;
   3185                 }
   3186             }
   3187             if (!(bcmi_egr_ip_tnl_mpls_check_dup_free_index(unit,
   3188                 fi, 4, start_index))) {
   3189 
   3190                 bcmi_egr_ip_tnl_mpls_free_idx_update(unit, 4, start_index, fi);
   3191                 start_index +=4;
   3192                 temp_free_entries-=4;
   3193             }
   3194         } else if ((free_entries >= 3)  &&
   3195             ((((start_index + free_entries) %  ent_per_tnl) == 7))) {
   3196             /*
   3197              * the entry is free till second last and has more
   3198              * than 3 consecutive spaces then break them into smaller
   3199              * and take 3 spaces into single big entry.
   3200              */
   3201             temp_free_entries = free_entries - 3;
   3202             while(temp_free_entries > 0) {
   3203                 if (temp_free_entries == 1) {
   3204                     bcmi_egr_ip_tnl_mpls_free_idx_update(unit, 1,
   3205                         start_index, fi);
   3206 
   3207                     start_index++;
   3208                     temp_free_entries--;
   3209                 } else if (temp_free_entries >= 2) {
   3210                     bcmi_egr_ip_tnl_mpls_free_idx_update(unit, 2,
   3211                         start_index, fi);
   3212 
   3213                     start_index +=2;
   3214                     temp_free_entries-=2;
   3215                 }
   3216             }
   3217             bcmi_egr_ip_tnl_mpls_free_idx_update(unit, 3, start_index, fi);
   3218             start_index +=3;
   3219             temp_free_entries-=3;
   3220         } else {
   3221             temp_free_entries = free_entries;
   3222             while(temp_free_entries > 0) {
   3223                 if (temp_free_entries == 1) {
   3224                     bcmi_egr_ip_tnl_mpls_free_idx_update(unit, 1,
   3225                         start_index, fi);
   3226 
   3227                     start_index++;
   3228                     temp_free_entries--;
   3229                 } else if (temp_free_entries >= 2) {
   3230                     bcmi_egr_ip_tnl_mpls_free_idx_update(unit, 2,
   3231                         start_index, fi);
   3232 
   3233                     start_index +=2;
   3234                     temp_free_entries-=2;
   3235                 }
   3236             }
   3237         }
   3238     }
   3239     return BCM_E_NONE;
   3240 }
   3241 
   3242 /*
   3243  * Function:
   3244  *      bcm_egr_ip_tnl_mpls_move_entries
   3245  * Purpose:
   3246  *      Move enties to create space for other entry.
   3247  * Parameters:
   3248  *      unit               - Device Number
   3249  *      src_tnl_index      - Tunnel start index.
   3250  *      src_entry_offset   - Mpls entry offset.
   3251  *      dst_free_mpls_idx  - Dest mpls tunnel entry index.
   3252  *      no_of_elements     - Number of elements to move.
   3253  * Returns:
   3254  *      BCM_E_XXX
   3255  */
   3256 bcm_error_t
   3257 bcm_egr_ip_tnl_mpls_move_entries(int unit,
   3258                         bcmi_egr_ip_tnl_mpls_tunnel_entry_t **tnl_sw_entry,
   3259                         int src_tnl_index, int src_entry_offset,
   3260                         int dst_free_mpls_idx, int no_of_elements)
   3261 {
   3262 
   3263     int dst_offset;
   3264     int src_offset;
   3265     int i = 0;
   3266     int ent_per_tnl = _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit);
   3267     int src_tnl_mpls_idx, dst_tnl_index;
   3268     int ref_count;
   3269     int rv;
   3270     uint32 l3_max_entry[SOC_MAX_MEM_WORDS]; /* Buffer to write interface info. */
   3271     uint32  *l3_if_entry_p;        /* Write buffer address.           */
   3272     soc_mem_t mem;                 /* Interface table memory.         */
   3273     intf_list_t *intf_list = NULL;
   3274     uint32 src_tnl_entry[SOC_MAX_MEM_WORDS];
   3275     uint32 dst_tnl_entry[SOC_MAX_MEM_WORDS];
   3276     uint32 src_buf[3] = {0};
   3277 
   3278     bcmi_egr_ip_tnl_mpls_table_memset(unit, src_tnl_entry);
   3279     bcmi_egr_ip_tnl_mpls_table_memset(unit, dst_tnl_entry);
   3280 
   3281     /* Get interface table memory. */
   3282     mem = BCM_XGS3_L3_MEM(unit,  intf);
   3283 
   3284     /* Zero the buffer. */
   3285     l3_if_entry_p = (uint32 *)&l3_max_entry;
   3286 
   3287     /* Compute offsets */
   3288     src_offset = src_entry_offset;
   3289     dst_offset = dst_free_mpls_idx % ent_per_tnl;
   3290     dst_tnl_index = dst_free_mpls_idx / ent_per_tnl;
   3291 
   3292      /*Read src_tnl_entry*/
   3293     bcmi_egr_ip_tnl_mpls_table_read(unit, src_tnl_index, src_tnl_entry);
   3294 
   3295      /*Read dst_entry*/
   3296     bcmi_egr_ip_tnl_mpls_table_read(unit, dst_tnl_index, dst_tnl_entry);
   3297 
   3298     if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   3299         for (; i < no_of_elements; i++) {
   3300             /*Get Label,Pushaction,expselect,exp,pri,cfi,expptr,ttl into src_buf
   3301              *and write src_buf into dst_entry_double.*/
   3302             bcmi_egress_tnl_label_entry_get(unit , src_tnl_entry,
   3303                     src_offset+i, src_buf);
   3304             bcmi_egress_tnl_label_entry_set(unit , dst_tnl_entry,
   3305                     dst_offset+i, src_buf);
   3306         }
   3307     } else {
   3308         bcmi_egr_ip_tnl_copy_src_label_info_to_dest(unit, src_tnl_entry,
   3309                 dst_tnl_entry, src_offset, dst_offset, no_of_elements);
   3310     }
   3311 
   3312     rv = bcmi_egr_ip_tnl_mpls_table_write(unit, dst_tnl_index, dst_tnl_entry);
   3313 
   3314     if (rv == BCM_E_NONE) {
   3315         src_tnl_mpls_idx = (src_tnl_index * ent_per_tnl) + src_entry_offset;
   3316         for (i=0; i < no_of_elements; i++) {
   3317             _BCM_MPLS_TNL_USED_SET(unit, dst_free_mpls_idx + i);
   3318             _BCM_MPLS_TNL_USED_CLR(unit, src_tnl_mpls_idx + i);
   3319         }
   3320         /* get the moved entry's original ref counter number */
   3321         bcmi_egr_ip_tnl_mpls_tunnel_ref_count_get (unit,
   3322             src_tnl_mpls_idx, &ref_count);
   3323         bcmi_egr_ip_tnl_mpls_ref_count_reset (unit, src_tnl_mpls_idx);
   3324         bcmi_egr_ip_tnl_mpls_ref_count_adjust (unit,
   3325             dst_free_mpls_idx, ref_count);
   3326 
   3327         /*
   3328          * Now change tunnel index in L3 interface entry.
   3329          */
   3330         intf_list = tnl_sw_entry[src_tnl_index]->label_entry[src_entry_offset]->intf_list;
   3331 
   3332         while (intf_list) {
   3333             sal_memset(l3_if_entry_p, 0, BCM_XGS3_L3_ENT_SZ(unit, intf));
   3334             BCM_IF_ERROR_RETURN(
   3335                 BCM_XGS3_MEM_READ(unit, mem, intf_list->intf_num, l3_if_entry_p));
   3336 
   3337             soc_mem_field32_set(unit, mem, l3_if_entry_p,
   3338                 MPLS_TUNNEL_INDEXf, dst_free_mpls_idx);
   3339 
   3340             rv = soc_mem_write(unit, mem, MEM_BLOCK_ANY, intf_list->intf_num, l3_if_entry_p);
   3341 
   3342             if (BCM_FAILURE(rv)) {
   3343                 return rv;
   3344             }
   3345             intf_list = intf_list->next;
   3346         }
   3347 
   3348     }
   3349 
   3350     return BCM_E_NONE;
   3351 }
   3352 
   3353 /*
   3354  * Function:
   3355  *      bcmi_egr_ip_tnl_mpls_intf_list_alloc
   3356  * Purpose:
   3357  *      Allocates link memory and sets interface chain.
   3358  * Parameters:
   3359  *      intf_num - interface number
   3360  * Returns:
   3361  *      pointer to allocated link memory
   3362  */
   3363 intf_list_t *
   3364 bcmi_egr_ip_tnl_mpls_intf_list_alloc(bcm_if_t intf_num)
   3365 {
   3366     intf_list_t *ptr;
   3367 
   3368     ptr = (intf_list_t *) sal_alloc(sizeof(intf_list_t), "egr mpls tnl sw intf list");
   3369     sal_memset(ptr, 0, sizeof(intf_list_t));
   3370 
   3371     ptr->intf_num = intf_num;
   3372     ptr->next = NULL;
   3373 
   3374     return ptr;
   3375 }
   3376 
   3377 /*
   3378  * Function:
   3379  *      bcmi_egr_ip_tnl_mpls_intf_list_dump
   3380  * Purpose:
   3381  *      Dumps interface chain.
   3382  * Parameters:
   3383  *      unit         - device number
   3384  *      tnl_sw_entry - pointer to tunnel database.
   3385  *      intf_num     - interface number
   3386  *      tnl_idx      - Tunnel Index
   3387  *      mpls_offset  - mpls entry offset in tunnel
   3388  * Returns:
   3389  *      None.
   3390  */
   3391 void
   3392 bcmi_egr_ip_tnl_mpls_intf_list_dump(int unit,
   3393                     bcmi_egr_ip_tnl_mpls_tunnel_entry_t **tnl_sw_entry,
   3394                     bcm_if_t intf_num, int tnl_idx, int mpls_offset)
   3395 {
   3396 
   3397    intf_list_t *temp;
   3398 
   3399     temp = tnl_sw_entry[tnl_idx]->label_entry[mpls_offset]->intf_list;
   3400 
   3401     while (temp)  {
   3402        LOG_ERROR(BSL_LS_BCM_L3,
   3403            (BSL_META_U(unit, "intf index = %d, tnl_idx = %d, mpls_off = %d\n"),
   3404             temp->intf_num, tnl_idx, mpls_offset));
   3405 
   3406         temp = temp->next;
   3407     }
   3408 }
   3409 
   3410 /*
   3411  * Function:
   3412  *      bcmi_egr_ip_tnl_mpls_intf_list_add
   3413  * Purpose:
   3414  *      Adds interface chain at a mpls entry index.
   3415  * Parameters:
   3416  *      unit         - device number
   3417  *      tnl_sw_entry - pointer to tunnel database.
   3418  *      intf_id      - interface number
   3419  *      tnl_idx      - Tunnel Index
   3420  *      mpls_offset  - mpls entry offset in tunnel
   3421  * Returns:
   3422  *      bcm_error_t
   3423  */
   3424 bcm_error_t
   3425 bcmi_egr_ip_tnl_mpls_intf_list_add(int unit,
   3426                     bcmi_egr_ip_tnl_mpls_tunnel_entry_t **tnl_sw_entry,
   3427                     bcm_if_t intf_id, int tnl_idx, int mpls_offset)
   3428 {
   3429 
   3430     intf_list_t *ptr, *temp, *prev;
   3431 
   3432     temp = tnl_sw_entry[tnl_idx]->label_entry[mpls_offset]->intf_list;
   3433     prev = temp;
   3434     while (temp) {
   3435         if (temp->intf_num == intf_id) {
   3436         /*
   3437          * We already have this interface at this index.
   3438          * this is just a negative case test if
   3439          * someone tries to send same entry at same intf.
   3440          */
   3441             return BCM_E_NONE;
   3442         }
   3443         prev = temp;
   3444         temp = temp->next;
   3445     }
   3446 
   3447     ptr = bcmi_egr_ip_tnl_mpls_intf_list_alloc(intf_id);
   3448 
   3449     if (ptr == NULL) {
   3450         return BCM_E_MEMORY;
   3451     }
   3452 
   3453     if(temp == prev) {
   3454         tnl_sw_entry[tnl_idx]->label_entry[mpls_offset]->intf_list = ptr;
   3455     } else {
   3456         prev->next = ptr;
   3457     }
   3458     return BCM_E_NONE;
   3459 }
   3460 
   3461 /*
   3462  * Function:
   3463  *      bcmi_egr_ip_tnl_mpls_intf_list_delete
   3464  * Purpose:
   3465  *      Deletes interface chain matching to a
   3466  *      particular interface number.
   3467  * Parameters:
   3468  *      unit         - device number
   3469  *      tnl_sw_entry - pointer to tunnel database.
   3470  *      intf_num     - interface number
   3471  *      tnl_idx      - Tunnel Index
   3472  *      mpls_offset  - mpls entry offset in tunnel
   3473  * Returns:
   3474  *      bcm_error_t
   3475  */
   3476 bcm_error_t
   3477 bcmi_egr_ip_tnl_mpls_intf_list_delete(int unit, bcmi_egr_ip_tnl_mpls_tunnel_entry_t **tnl_sw_entry,
   3478                     bcm_if_t intf_num, int tnl_idx, int mpls_offset)
   3479 {
   3480 
   3481     intf_list_t *temp_ptr, *prev_ptr;
   3482 
   3483     if(tnl_sw_entry[tnl_idx]->label_entry[mpls_offset]->intf_list == NULL) {
   3484         /* why we are here. this is not possible */
   3485         return BCM_E_INTERNAL;
   3486     }
   3487 
   3488     temp_ptr = tnl_sw_entry[tnl_idx]->label_entry[mpls_offset]->intf_list;
   3489     prev_ptr = temp_ptr;
   3490 
   3491     while ((temp_ptr) && ((temp_ptr->intf_num) != intf_num)) {
   3492         prev_ptr = temp_ptr;
   3493         temp_ptr = temp_ptr->next;
   3494     }
   3495 
   3496     if (temp_ptr) {
   3497         if (temp_ptr == prev_ptr) {
   3498             tnl_sw_entry[tnl_idx]->label_entry[mpls_offset]->intf_list = temp_ptr->next;
   3499         } else {
   3500             prev_ptr->next = temp_ptr->next;
   3501         }
   3502 
   3503         sal_free(temp_ptr);
   3504     } else {
   3505         return BCM_E_NOT_FOUND;
   3506     }
   3507     return BCM_E_NONE;
   3508 }
   3509 
   3510 /*
   3511  * Function:
   3512  *      bcmi_egr_ip_tnl_mpls_intf_list_delete_all
   3513  * Purpose:
   3514  *      Deletes all nodex of Interface chain at that mpls
   3515  *      entry index.
   3516  * Parameters:
   3517  *      unit         - device number
   3518  *      tnl_sw_entry - pointer to tunnel database.
   3519  *      intf_num     - interface number
   3520  *      tnl_idx      - Tunnel Index
   3521  *      mpls_offset  - mpls entry offset in tunnel
   3522  * Returns:
   3523  *      bcm_error_t
   3524  */
   3525 
   3526 void
   3527 bcmi_egr_ip_tnl_mpls_intf_list_delete_all(int unit,
   3528                     bcmi_egr_ip_tnl_mpls_tunnel_entry_t **tnl_sw_entry,
   3529                     int tnl_idx, int mpls_offset)
   3530 {
   3531 
   3532     intf_list_t *temp_ptr;
   3533 
   3534     temp_ptr = tnl_sw_entry[tnl_idx]->label_entry[mpls_offset]->intf_list;
   3535 
   3536     while (temp_ptr) {
   3537         tnl_sw_entry[tnl_idx]->label_entry[mpls_offset]->intf_list =
   3538             temp_ptr->next;
   3539 
   3540         sal_free(temp_ptr);
   3541         temp_ptr = tnl_sw_entry[tnl_idx]->label_entry[mpls_offset]->intf_list;
   3542     }
   3543 }
   3544 
   3545 #if 0
   3546 void
   3547 bcmi_egr_ip_tnl_mpls_intf_list_copy(int unit,
   3548                      bcmi_egr_ip_tnl_mpls_tunnel_entry_t **tnl_sw_entry,
   3549                      int dst_tnl_idx, int dst_mpls_offset,
   3550                      int tnl_idx, int mpls_offset)
   3551 {
   3552 
   3553 
   3554     /* we can just change the pointer and whole list can be picked from there */
   3555     tnl_sw_entry[dst_tnl_idx]->label_entry[dst_mpls_offset]->intf_list =
   3556         tnl_sw_entry[tnl_idx]->label_entry[mpls_offset]->intf_list;
   3557 
   3558     tnl_sw_entry[tnl_idx]->label_entry[mpls_offset]->intf_list = NULL;
   3559 }
   3560 #endif
   3561 
   3562 /*
   3563  * Function:
   3564  *      bcm_egr_ip_tnl_mpls_sw_entry_reset
   3565  * Purpose:
   3566  *      Dumps interface chain.
   3567  * Parameters:
   3568  *      unit         - device number
   3569  *      tnl_sw_entry - pointer to tunnel database.
   3570  *      tnl_idx      - Tunnel Index
   3571  *      mpls_offset  - mpls entry offset in tunnel
   3572  *      clean_list   _ flag to decide whether to clean interface list.
   3573  * Returns:
   3574  *      bcm_error_t
   3575  */
   3576 
   3577 
   3578 void bcm_egr_ip_tnl_mpls_sw_entry_reset(int unit,
   3579                     bcmi_egr_ip_tnl_mpls_tunnel_entry_t **tnl_sw_entry,
   3580                     int tnl_idx, int mpls_offset, int clean_list)
   3581 {
   3582 
   3583     if (clean_list) {
   3584         tnl_sw_entry[tnl_idx]->label_entry[mpls_offset]->intf_list = NULL;
   3585     }
   3586     tnl_sw_entry[tnl_idx]->label_entry[mpls_offset]->flags = 0;
   3587     tnl_sw_entry[tnl_idx]->label_entry[mpls_offset]->num_elements = 0;
   3588 }
   3589 
   3590 /*
   3591  * Function:
   3592  *      bcmi_mpls_egr_tunnel_delete_free_indexes
   3593  * Purpose:
   3594  *      Delete free index entry from free indexes if the entry is used up.
   3595  * Parameters:
   3596  *      unit           - device number
   3597  *      fi             - Pointer to free indexes database.
   3598  *      num_labels     - Number of labels that entry contains.
   3599  *      mpls_entry_idx - index to mpls entry index that is used up.
   3600  * Returns:
   3601  *      None.
   3602  */
   3603 void
   3604 bcmi_mpls_egr_tunnel_delete_free_indexes(int unit,
   3605                     bcmi_egr_ip_tnl_free_indexes_t *fi,
   3606                     int num_labels, int mpls_entry_idx)
   3607 {
   3608     int idx=0,free_idx=0;
   3609     int entry_count = 0;
   3610     int idx_min=0, idx_max=0;
   3611 
   3612 
   3613     idx_min = mpls_entry_idx;
   3614     idx_max = mpls_entry_idx + num_labels;
   3615 
   3616     if ((num_labels <= 0) || (num_labels > 8)) {
   3617         return;
   3618     }
   3619 
   3620     for (; idx<MAX_ENTRY_INDEXES; idx++) {
   3621 
   3622         if (!(fi->free_index_count[idx])) {
   3623             continue;
   3624         }
   3625 
   3626         for (free_idx=0; free_idx<MAX_FREE_ENTRY_INDEXES; free_idx++) {
   3627             /* need to keep it here as we are chaning counts for next run. */
   3628             entry_count = fi->free_index_count[idx];
   3629 
   3630             if (fi->free_entry_indexes[idx][free_idx] == -1) {
   3631                 break;
   3632             }
   3633 
   3634             if ((fi->free_entry_indexes[idx][free_idx] >= idx_min) &&
   3635                 (fi->free_entry_indexes[idx][free_idx] < idx_max)) {
   3636                 /* free this space */
   3637                 if (free_idx == (entry_count - 1)) {
   3638                     fi->free_entry_indexes[idx][free_idx] = -1;
   3639                 } else {
   3640                     fi->free_entry_indexes[idx][free_idx] =
   3641                         fi->free_entry_indexes[idx][entry_count-1];
   3642                     fi->free_entry_indexes[idx][entry_count-1] = -1;
   3643                    /*
   3644                     * We should check free_idx from start again here.
   3645                     * as some matching index may have come to this slot.
   3646                     */
   3647                    free_idx = -1;
   3648                 }
   3649                 fi->free_index_count[idx]--;
   3650             }
   3651         }
   3652     }
   3653 }
   3654 
   3655 /*
   3656  * Function:
   3657  *      bcmi_egr_ip_tnl_mpls_move_tunnel_entries
   3658  * Purpose:
   3659  *      Once we identify that this is the tunnel index that can create
   3660  *      space for our new entry, we try to move the mple tunnel entries
   3661  *      from that tunnel index.
   3662  * Parameters:
   3663  *      unit           - (IN)device number
   3664  *      fi             - (IN)Pointer to free indexes database.
   3665  *      tunnel_entry   - (IN)Number of labels that entry contains.
   3666  *      idx            - (IN)index to mpls entry index that is used up.
   3667  *      num_labels     - (IN)Number of labels for which free space is made.
   3668  *      mpls_tnl_idx   - (IN)mpls offset from where entry needs to be moved.
   3669  * Returns:
   3670  *      None.
   3671  */
   3672 int
   3673 bcmi_egr_ip_tnl_mpls_move_tunnel_entries(int unit,
   3674                       bcmi_egr_ip_tnl_free_indexes_t *fi,
   3675                       bcmi_egr_ip_tnl_mpls_tunnel_entry_t **tunnel_entry,
   3676                       int src_tnl_idx, int src_mpls_tnl_off, int num_labels)
   3677 {
   3678     int ent_per_idx = _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit);
   3679     int temp_num_labels = num_labels;
   3680     int left_free_entries = 0;
   3681     int found = 0;
   3682     int rv = BCM_E_NONE;
   3683     int mpls_index = 0;
   3684     int mpls_off = 0;
   3685     int no_of_elements = 0;
   3686     int f_idx, free_idx;
   3687     int new_start_index;
   3688     int chk_tnl_idx, chk_mpls_idx;
   3689     bcmi_egr_ip_tnl_mpls_label_entry_t *label_entry;
   3690     bcmi_egr_ip_tnl_mpls_label_entry_t *src_label_entry;
   3691     int free_db_entries = 0;
   3692     int total_free_entries = 0;
   3693 
   3694 
   3695     mpls_index = (src_tnl_idx * _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit));
   3696     /* check for entry free */
   3697     for(mpls_off=src_mpls_tnl_off; mpls_off < ent_per_idx; mpls_off++) {
   3698         found = 0;
   3699 
   3700         if (!_BCM_MPLS_TNL_USED_GET(unit, (mpls_index + mpls_off))) {
   3701             temp_num_labels--;
   3702             free_db_entries++;
   3703             total_free_entries++;
   3704             continue;
   3705         }
   3706 
   3707         /* If we are looking at same index as free index. then continue. */
   3708         if (free_db_entries) {
   3709             bcmi_mpls_egr_tunnel_delete_free_indexes(unit,
   3710                 fi, free_db_entries, (mpls_index + mpls_off - free_db_entries));
   3711         }
   3712         free_db_entries = 0;
   3713         src_label_entry = tunnel_entry[src_tnl_idx]->label_entry[mpls_off];
   3714         if(src_label_entry->flags
   3715             & BCMI_EGR_IP_TUNNEL_MPLS_START_OF_ENTRY) {
   3716             /* this is the start of this entry,
   3717              * we should check if we have some free space for this entry
   3718              */
   3719             no_of_elements = src_label_entry->num_elements;
   3720 
   3721             /* we also should check if there are some bigger entries in this
   3722              * tunnel entry, big entries can be adjusted to other big entries
   3723              * if exists.
   3724              * else we might have to move smaller entries to bigger entries.
   3725              */
   3726             for (f_idx=no_of_elements-1; f_idx < 8; f_idx++) {
   3727 
   3728                 if (fi->free_index_count[f_idx] == 0) {
   3729                     continue;
   3730                 }
   3731 
   3732                 for (free_idx=0; free_idx<8; free_idx++) {
   3733                     /* There is some empty place here.
   3734                      * lets use the same size entry or bigger.
   3735                      * returning the first free entry in that block.
   3736                      */
   3737                     if (fi->free_entry_indexes[f_idx][free_idx] == -1) {
   3738                         break;
   3739                     }
   3740                     chk_tnl_idx  = fi->free_entry_indexes[f_idx][free_idx] /
   3741                         _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit);
   3742 
   3743                     chk_mpls_idx =  fi->free_entry_indexes[f_idx][free_idx] %
   3744                         _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit);
   3745 
   3746                     label_entry =
   3747                         tunnel_entry[chk_tnl_idx]->label_entry[chk_mpls_idx];
   3748                     if (!(label_entry->flags &
   3749                         BCMI_EGR_IP_TUNNEL_MPLS_ENTRY_CHECKED)) {
   3750 
   3751                         /*
   3752                          * we can use free_entry_indexes[idx][free_idx];
   3753                          * mark this entry used so that next lookup should
   3754                          * not use this.
   3755                          */
   3756                         label_entry->flags |=
   3757                             BCMI_EGR_IP_TUNNEL_MPLS_ENTRY_CHECKED;
   3758                         found = 1;
   3759                         rv = bcm_egr_ip_tnl_mpls_move_entries(unit,
   3760                                     tunnel_entry, src_tnl_idx, mpls_off,
   3761                                     fi->free_entry_indexes[f_idx][free_idx],
   3762                                     no_of_elements);
   3763 
   3764                         if (rv == BCM_E_NONE) {
   3765                         /* movement is successful */
   3766                         label_entry->flags |=
   3767                                 BCMI_EGR_IP_TUNNEL_MPLS_START_OF_ENTRY;
   3768                         label_entry->num_elements = no_of_elements;
   3769                         /* now copy interfaces.
   3770                          * even if we are keeping pointer here for linked list,
   3771                          * we can assign the same pointer to the new list.
   3772                          */
   3773                         label_entry->intf_list = src_label_entry->intf_list;
   3774                         bcm_egr_ip_tnl_mpls_sw_entry_reset(unit, tunnel_entry,
   3775                             src_tnl_idx, mpls_off, 1);
   3776                         } else {
   3777                             return rv;
   3778                         }
   3779 
   3780                         temp_num_labels -= no_of_elements;
   3781                         /* mpls_off will also get incremented in this loop. */
   3782                         mpls_off += (no_of_elements - 1);
   3783                         new_start_index =
   3784                             fi->free_entry_indexes[f_idx][free_idx] +
   3785                             no_of_elements;
   3786 
   3787                         bcmi_mpls_egr_tunnel_delete_free_indexes(unit, fi,
   3788                             no_of_elements,
   3789                             fi->free_entry_indexes[f_idx][free_idx]);
   3790 
   3791                         left_free_entries = (f_idx+1)-no_of_elements;
   3792                         total_free_entries += no_of_elements;
   3793                         bcm_egr_ip_tnl_mpls_remark_free_indexes(unit,
   3794                             left_free_entries, new_start_index, fi);
   3795 
   3796                         break;
   3797                     }
   3798                 }
   3799                 if (found) {
   3800                     /*break from loop so that we can check next entry*/
   3801                     break;
   3802                 }
   3803             }
   3804             if (!found) {
   3805                 temp_num_labels = num_labels;
   3806             }
   3807         }
   3808         if (temp_num_labels <= 0) {
   3809 
   3810             /* we have moved all the entries to some other space.
   3811              * we have this space free now.
   3812              */
   3813             bcm_egr_ip_tnl_mpls_remark_free_indexes(unit,
   3814                 (total_free_entries - num_labels),
   3815                 ((src_tnl_idx*ent_per_idx) + src_mpls_tnl_off + num_labels), fi);
   3816 
   3817             return BCM_E_NONE;
   3818         }
   3819      }
   3820     /* We cant not free any entry here. so return BCM_E_FULL */
   3821     return BCM_E_FULL;
   3822 }
   3823 
   3824 /*
   3825  * Function:
   3826  *           bcmi_xgs5_mpls_egr_tunnel_lookup
   3827  * Purpose:
   3828  *           loopup matching entry into  EGR_IP_TUNNEL_MPLS
   3829  * Parameters:
   3830  *           IN :  Unit
   3831  *           IN :  push_action
   3832  *           IN :  label_array
   3833  *           OUT : match_mpls_tunnel_index
   3834  * Returns:
   3835  *      BCM_E_XXX
   3836  */
   3837 
   3838 STATIC int
   3839 bcmi_xgs5_mpls_egr_tunnel_lookup (int unit, int push_action,
   3840                               bcmi_egr_ip_tnl_mpls_tunnel_entry_t **tunnel_entry,
   3841                               bcm_mpls_egress_label_t *label_array,
   3842                               int *match_mpls_tunnel_index)
   3843 {
   3844     int rv = BCM_E_NONE;
   3845     uint32 label_value;
   3846     uint32 entry_ttl, entry_exp, entry_push_action;
   3847     int num_ip_tnl_mpls;
   3848     int i = 0, j = 0, tnl_index = -1, mpls_index = -1;
   3849     int temp_push_action = 0;
   3850     int offset;
   3851     soc_mem_t  mem;
   3852     uint32 tnl_entry[SOC_MAX_MEM_WORDS];
   3853     uint32 iptun_mpls_entry_format[3] = {0};
   3854 
   3855     mem = bcmi_egr_ip_tnl_mem_name_get(unit);
   3856     num_ip_tnl_mpls = soc_mem_index_count(unit, mem);
   3857 
   3858     /* parameter checking */
   3859     if (push_action != 0 && label_array == NULL) {
   3860         return BCM_E_PARAM;
   3861     }
   3862 
   3863     for (tnl_index = 0; tnl_index < num_ip_tnl_mpls; tnl_index++) {
   3864         if (!_BCM_MPLS_IP_TNL_USED_GET(unit, tnl_index)) {
   3865            continue;
   3866         }
   3867 
   3868         mpls_index = tnl_index * _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit);
   3869 
   3870         for (i = 0; i <  _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit); i++) {
   3871             if (!(tunnel_entry[tnl_index]->label_entry[i]->flags &
   3872                 BCMI_EGR_IP_TUNNEL_MPLS_START_OF_ENTRY)) {
   3873                 continue;
   3874             }
   3875             if (!push_action) {
   3876                 if ((tunnel_entry[tnl_index]->label_entry[i]->flags &
   3877                     BCMI_EGR_IP_TUNNEL_MPLS_ENTRY_ZERO)) {
   3878                     *match_mpls_tunnel_index = (tnl_index *
   3879                         _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit)) + i;
   3880                 }
   3881                 return BCM_E_NONE;
   3882             }
   3883 
   3884             if (!(tunnel_entry[tnl_index]->label_entry[i]->num_elements ==
   3885                 push_action)) {
   3886                 continue;
   3887             }
   3888 
   3889             rv = bcmi_egr_ip_tnl_mpls_table_read(unit, tnl_index, tnl_entry);
   3890             if (rv < 0) {
   3891                 return rv;
   3892             }
   3893 
   3894             if (push_action > 1) {
   3895                 j = 0;
   3896                 temp_push_action = push_action;
   3897 
   3898                 while (temp_push_action > 1) {
   3899                     if (!(_BCM_MPLS_TNL_USED_GET(unit, mpls_index + i + j))) {
   3900                         break;
   3901                     }
   3902 
   3903 
   3904                     offset = (i+j);
   3905                     if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   3906                         bcmi_egress_tnl_label_entry_get(unit, tnl_entry,
   3907                                 offset, iptun_mpls_entry_format);
   3908                     }
   3909 
   3910                     bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   3911                             tnl_entry, offset,
   3912                             iptun_mpls_entry_format, bcmiMplsLabel,
   3913                             &label_value);
   3914 
   3915                     bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   3916                             tnl_entry, offset,
   3917                             iptun_mpls_entry_format, bcmiMplsTtl,
   3918                             &entry_ttl);
   3919 
   3920                     bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   3921                             tnl_entry, offset,
   3922                             iptun_mpls_entry_format, bcmiMplsExp,
   3923                             &entry_exp);
   3924 
   3925                     bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   3926                             tnl_entry, offset,
   3927                             iptun_mpls_entry_format, bcmiMplsPushAction,
   3928                             &entry_push_action);
   3929                     /*
   3930                      * entry_push_action should be 2 as next entry will also
   3931                      * be checked with this entry.
   3932                      */
   3933                     if ((label_array[j].label == label_value) &&
   3934                         (label_array[j].ttl == entry_ttl) &&
   3935                         (label_array[j].exp == entry_exp) &&
   3936                         (entry_push_action == 2)) {
   3937                          /* Do nothing. This is good case so continue */
   3938                          temp_push_action--;
   3939                     } else {
   3940                          /* we are not getting matching entry here */
   3941                          break;
   3942                     }
   3943                     j++;
   3944                  }
   3945 
   3946                 offset = (i+j);
   3947 
   3948                 if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   3949                     sal_memset(&iptun_mpls_entry_format, 0,
   3950                             sizeof(iptun_mpls_entry_format));
   3951 
   3952                     bcmi_egress_tnl_label_entry_get(unit, tnl_entry,
   3953                             offset, iptun_mpls_entry_format);
   3954                 }
   3955 
   3956                 bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   3957                         tnl_entry, offset,
   3958                         iptun_mpls_entry_format, bcmiMplsLabel,
   3959                         &label_value);
   3960 
   3961                 bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   3962                         tnl_entry, offset,
   3963                         iptun_mpls_entry_format, bcmiMplsTtl,
   3964                         &entry_ttl);
   3965 
   3966                 bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   3967                         tnl_entry, offset,
   3968                         iptun_mpls_entry_format, bcmiMplsExp,
   3969                         &entry_exp);
   3970 
   3971                 bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   3972                         tnl_entry, offset,
   3973                         iptun_mpls_entry_format, bcmiMplsPushAction,
   3974                         &entry_push_action);
   3975                 /*
   3976                  * This is the last entry in the chain, therefore
   3977                  * entry push actions should be 1.
   3978                  */
   3979                 if ((label_array[j].label == label_value) &&
   3980                     (label_array[j].ttl == entry_ttl) &&
   3981                     (label_array[j].exp == entry_exp) &&
   3982                     (entry_push_action == 1)) {
   3983 
   3984                     *match_mpls_tunnel_index = (tnl_index *
   3985                         _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit)) + i;
   3986                     return BCM_E_NONE;
   3987                 }
   3988 
   3989             } else if (push_action == 0x1) {
   3990 
   3991                 offset = i;
   3992 
   3993                 if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   3994                     bcmi_egress_tnl_label_entry_get(unit, tnl_entry,
   3995                        offset, iptun_mpls_entry_format);
   3996                 }
   3997 
   3998                 bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   3999                         tnl_entry, offset,
   4000                         iptun_mpls_entry_format, bcmiMplsLabel,
   4001                         &label_value);
   4002 
   4003                 bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   4004                         tnl_entry, offset,
   4005                         iptun_mpls_entry_format, bcmiMplsTtl,
   4006                         &entry_ttl);
   4007 
   4008                 bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   4009                         tnl_entry, offset,
   4010                         iptun_mpls_entry_format, bcmiMplsExp,
   4011                         &entry_exp);
   4012 
   4013                 offset = (i+j);
   4014 
   4015                 sal_memset(&iptun_mpls_entry_format, 0,
   4016                         sizeof(iptun_mpls_entry_format));
   4017 
   4018                 bcmi_egress_tnl_label_entry_get(unit, tnl_entry,
   4019                         offset, iptun_mpls_entry_format);
   4020 
   4021                 bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   4022                         tnl_entry, offset,
   4023                         iptun_mpls_entry_format, bcmiMplsPushAction,
   4024                         &entry_push_action);
   4025 
   4026                 if ((label_array[0].label == label_value) &&
   4027                         (label_array[0].ttl == entry_ttl) &&
   4028                         (label_array[0].exp == entry_exp) &&
   4029                         (push_action == entry_push_action)) {
   4030 
   4031                     *match_mpls_tunnel_index = (tnl_index *
   4032                             _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit)) + i;
   4033                     return BCM_E_NONE;
   4034                 }
   4035             } else if (push_action == 0x0) {
   4036 
   4037                 offset = i;
   4038                 bcmi_egress_tnl_label_entry_get(unit, tnl_entry,
   4039                         offset, iptun_mpls_entry_format);
   4040 
   4041                 bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   4042                         tnl_entry, offset,
   4043                         iptun_mpls_entry_format, bcmiMplsLabel,
   4044                         &label_value);
   4045 
   4046                 bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   4047                         tnl_entry, offset,
   4048                         iptun_mpls_entry_format, bcmiMplsTtl,
   4049                         &entry_ttl);
   4050 
   4051                 bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   4052                         tnl_entry, offset,
   4053                         iptun_mpls_entry_format, bcmiMplsExp,
   4054                         &entry_exp);
   4055 
   4056                 offset = (i+j);
   4057                 sal_memset(&iptun_mpls_entry_format, 0,
   4058                         sizeof(iptun_mpls_entry_format));
   4059 
   4060                 bcmi_egress_tnl_label_entry_get(unit, tnl_entry,
   4061                         offset, iptun_mpls_entry_format);
   4062                 bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   4063                         tnl_entry, offset,
   4064                         iptun_mpls_entry_format, bcmiMplsPushAction,
   4065                         &entry_push_action);
   4066 
   4067                 /* Case of Dummy entry */
   4068                 if ((0 == label_value) &&
   4069                     (0 == entry_ttl) &&
   4070                     (0 == entry_exp) &&
   4071                     (0 == entry_push_action)) {
   4072 
   4073                     *match_mpls_tunnel_index = (tnl_index *
   4074                         _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit)) + i;
   4075                     return BCM_E_NONE;
   4076                 }
   4077             }
   4078         }
   4079     }
   4080     return BCM_E_NONE;
   4081 }
   4082 
   4083 /*
   4084  * Function:
   4085  *      bcmi_egr_ip_tnl_mpls_check_availability
   4086  * Purpose:
   4087  *      Checks availability for incoming mpls tunnel
   4088  *      entry into the existing free entries.
   4089  * Parameters:
   4090  *      unit         - (IN)device number
   4091  *      fi           - (IN)Pointer to free indexes database.
   4092  *      num_labels   - (IN)Number of labels that entry contains.
   4093  * Returns:
   4094  *      (INT)
   4095  */
   4096 int
   4097 bcmi_egr_ip_tnl_mpls_check_availability(int unit,
   4098                 bcmi_egr_ip_tnl_free_indexes_t *fi,
   4099                 int num_labels)
   4100 {
   4101     int idx,free_idx;
   4102     int mpls_entry_index;
   4103 
   4104     if (num_labels == 0) {
   4105         return -1;
   4106     }
   4107     /* MAX_FREE_ENTRY = */
   4108     for (idx=num_labels-1; idx < MAX_ENTRY_INDEXES; idx++) {
   4109         /* MAX FREE ENTRY COUNTING = 8 */
   4110         if (fi->free_index_count[idx]) {
   4111             /* entry array starts from 0 but count is from 1 */
   4112             free_idx=fi->free_index_count[idx] - 1;
   4113             for (; free_idx>=0; free_idx--) {
   4114                 /* There is some empty place here.
   4115                  * lets use the same size ehtry or bigger.
   4116                  * returning the first free entry in that block.
   4117                  */
   4118                 if (fi->free_entry_indexes[idx][free_idx] == -1) {
   4119                     /*
   4120                      * count is set but no free index here.
   4121                      * please reduce the count
   4122                      */
   4123                     fi->free_index_count[idx]--;
   4124                     continue;
   4125                 }
   4126                 /*
   4127                  * if we have reached here that means we have got the space
   4128                  */
   4129                 mpls_entry_index = fi->free_entry_indexes[idx][free_idx];
   4130                 fi->free_entry_indexes[idx][free_idx] = -1;
   4131                 fi->free_index_count[idx]--;
   4132                 bcm_egr_ip_tnl_mpls_remark_free_indexes(unit,
   4133                     (idx+1)-num_labels, mpls_entry_index+num_labels, fi);
   4134 
   4135                 return mpls_entry_index;
   4136             }
   4137         }
   4138     }
   4139     return -1;
   4140 }
   4141 
   4142 /*
   4143  * Function:
   4144  *      bcmi_egr_ip_tnl_mpls_get_free_index
   4145  * Purpose:
   4146  *      fills the free entry index database with after
   4147  *      reading all the tunnel entries.
   4148  * Parameters:
   4149  *      unit         - (IN)device number
   4150  *      num_labels   - (IN)Number of labels that entry contains.
   4151  *      tunnel_entry - (IN)Pointer to mpls tunnel s/w state.
   4152  *      fi           - (IN/OUT)Pointer to free indexes database.
   4153  * Returns:
   4154  *      (INT)
   4155  */
   4156 int
   4157 bcmi_egr_ip_tnl_mpls_get_free_index(int unit, int num_labels,
   4158                        bcmi_egr_ip_tnl_mpls_tunnel_entry_t **tunnel_entry,
   4159                        bcmi_egr_ip_tnl_free_indexes_t *fi)
   4160 {
   4161     int idx=0, mpls_off=0;
   4162     int mpls_index;
   4163     int start_index = -1;
   4164     int number_of_free_entries = 0;
   4165     int free_tunnel_index = -1;
   4166     int num_ip_tnl;
   4167     bcmi_egr_ip_tnl_mpls_label_entry_t *label_entry;
   4168     soc_mem_t mem;
   4169 
   4170     if (num_labels == 0) {
   4171         return -1;
   4172     }
   4173 
   4174     mem = bcmi_egr_ip_tnl_mem_name_get(unit);
   4175 
   4176     num_ip_tnl = soc_mem_index_count(unit, mem);
   4177 
   4178     for (;idx < num_ip_tnl; idx++) {
   4179 
   4180         if (!_BCM_MPLS_IP_TNL_USED_GET(unit, idx)) {
   4181             continue;
   4182         }
   4183 
   4184         mpls_index = idx * _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit);
   4185         start_index = -1;
   4186         mpls_off = 0;
   4187         number_of_free_entries = 0;
   4188         for(;mpls_off < _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit); mpls_off++) {
   4189 
   4190             if (_BCM_MPLS_TNL_USED_GET(unit, (mpls_index + mpls_off))) {
   4191 
   4192                 label_entry = tunnel_entry[idx]->label_entry[mpls_off];
   4193 
   4194                 if (label_entry->flags &
   4195                     BCMI_EGR_IP_TUNNEL_MPLS_START_OF_ENTRY) {
   4196 
   4197                     mpls_off +=
   4198                         label_entry->num_elements - 1;
   4199                 }
   4200                 if (!(bcmi_egr_ip_tnl_mpls_check_dup_free_index(unit,
   4201                         fi,number_of_free_entries, start_index))) {
   4202 
   4203                     bcm_egr_ip_tnl_mpls_remark_free_indexes(unit,
   4204                         number_of_free_entries, start_index, fi);
   4205                 }
   4206                 start_index = -1;
   4207                 number_of_free_entries = 0;
   4208 
   4209             } else {
   4210 
   4211                 number_of_free_entries++;
   4212                 if (start_index == -1) {
   4213                     start_index = mpls_index + mpls_off;
   4214                 }
   4215                 if (mpls_off == 7) {
   4216                     /*
   4217                      * this is the last tunnel index and therefore we
   4218                      * should just update free entries
   4219                      */
   4220                     if (!(bcmi_egr_ip_tnl_mpls_check_dup_free_index(unit,
   4221                             fi,number_of_free_entries, start_index))) {
   4222 
   4223                         bcm_egr_ip_tnl_mpls_remark_free_indexes(unit,
   4224                             number_of_free_entries, start_index, fi);
   4225                     }
   4226                     start_index= -1;
   4227                     number_of_free_entries = 0;
   4228 
   4229                 }
   4230             }
   4231         }
   4232         if (idx % num_labels == 0) {
   4233            /* just checking after getting data of five labels */
   4234             free_tunnel_index = bcmi_egr_ip_tnl_mpls_check_availability(unit,
   4235                                     fi, num_labels);
   4236         }
   4237         if (free_tunnel_index != -1) {
   4238             return free_tunnel_index;
   4239         }
   4240     }
   4241     return -1;
   4242 }
   4243 
   4244 /*
   4245  * Function:
   4246  *      bcmi_egr_ip_tnl_mpls_create_local_free_indexes
   4247  * Purpose:
   4248  *      Create duplicate free indexes for local arithmatic.
   4249  * Parameters:
   4250  *      unit                         - (IN)device number
   4251  *      free_entry_structures        - (IN)Pointer to free indexes database.
   4252  *      local_free_indexes_structure - (IN)Pointer to free indexes database.
   4253  * Returns:
   4254  *      None.
   4255  */
   4256 void
   4257 bcmi_egr_ip_tnl_mpls_create_local_free_indexes(int unit,
   4258                     bcmi_egr_ip_tnl_free_indexes_t *free_entry_structures,
   4259                     bcmi_egr_ip_tnl_free_indexes_t *local_free_indexes_structure)
   4260 {
   4261     int i, j;
   4262 
   4263     sal_memset(local_free_indexes_structure, 0,
   4264         sizeof(bcmi_egr_ip_tnl_free_indexes_t));
   4265     for (i=0; i<MAX_ENTRY_INDEXES;i++) {
   4266         for (j=0;j<MAX_FREE_ENTRY_INDEXES; j++) {
   4267             local_free_indexes_structure->free_entry_indexes[i][j] =
   4268                 free_entry_structures->free_entry_indexes[i][j];
   4269         }
   4270         local_free_indexes_structure->free_index_count[i] =
   4271             free_entry_structures->free_index_count[i];
   4272     }
   4273 }
   4274 
   4275 /*
   4276  * Function:
   4277  *      bcmi_egr_ip_tnl_mpls_uncheck_free_indexes
   4278  * Purpose:
   4279  *      while looking for entries, we mark some entries as checkes
   4280  *      already so that we do not try to use the same entry
   4281  *      while looking for multiple entries..
   4282  * Parameters:
   4283  *      unit         - (IN)device number
   4284  *      fi           - (IN)Pointer to free indexes database.
   4285  *      tunnel_entry - (IN)Pointer to tunnel database
   4286  * Returns:
   4287  *      None.
   4288  */
   4289 void
   4290 bcmi_egr_ip_tnl_mpls_uncheck_free_indexes(int unit,
   4291                     bcmi_egr_ip_tnl_free_indexes_t *fi,
   4292                     bcmi_egr_ip_tnl_mpls_tunnel_entry_t **tunnel_entry)
   4293 {
   4294     int i, j;
   4295     int tnl_idx, tnl_mpls_idx;
   4296 
   4297     for (i=0; i<MAX_ENTRY_INDEXES;i++) {
   4298         for (j=0;j<MAX_FREE_ENTRY_INDEXES; j++) {
   4299 
   4300             if (fi->free_entry_indexes[i][j] == -1) {
   4301                 continue;
   4302                                     }
   4303             tnl_idx      = fi->free_entry_indexes[i][j] /
   4304                                _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit);
   4305             tnl_mpls_idx = fi->free_entry_indexes[i][j] %
   4306                                _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit);
   4307 
   4308             tunnel_entry[tnl_idx]->label_entry[tnl_mpls_idx]->flags &=
   4309                 (~BCMI_EGR_IP_TUNNEL_MPLS_ENTRY_CHECKED);
   4310         }
   4311 
   4312     }
   4313 }
   4314 
   4315 /*
   4316  * Function:
   4317  *      bcmi_egr_ip_tnl_mpls_adjust_entry
   4318  * Purpose:
   4319  *      Reshuffle the entries if we are not able to fit
   4320  *      the incoming entry.
   4321  * Parameters:
   4322  *      unit         - (IN)device number
   4323  *      num_labels   - (IN)Number of labels that entry contains.
   4324  *      tunnel_entry - (IN_Pointer to mpls tunnel s/w state.
   4325  *      fi           - (IN)Pointer to free indexes database.
   4326  *      tnl_idx      - (OUT)Pointer to index of freed entry if possible.
   4327  * Returns:
   4328  *      bcm_error_t
   4329  */
   4330 bcm_error_t
   4331 bcmi_egr_ip_tnl_mpls_adjust_entry(int unit,
   4332                     int num_labels,
   4333                     bcmi_egr_ip_tnl_mpls_tunnel_entry_t **tunnel_entry,
   4334                     bcmi_egr_ip_tnl_free_indexes_t *fi,
   4335                     int *tnl_idx)
   4336 {
   4337     int idx=0;
   4338     bcmi_egr_ip_tnl_free_indexes_t local_fi; /* locan free indexes */
   4339     int num_ip_tnl;
   4340     int mpls_off;
   4341     int no_of_elements;
   4342     int temp_num_labels;
   4343     int found = 0;
   4344     int free_indexes_changed = 1;
   4345     int f_idx, free_idx;
   4346     int mpls_index;
   4347     int left_free_entries;
   4348     int new_start_index;
   4349     int chk_tnl_idx, chk_mpls_idx;
   4350     int rv;
   4351     int src_mpls_index = 0;
   4352     int ent_per_tunnel = _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit);
   4353     bcmi_egr_ip_tnl_mpls_label_entry_t *label_entry;
   4354     soc_mem_t mem;
   4355     int free_db_entries=0;
   4356 
   4357     mem = bcmi_egr_ip_tnl_mem_name_get(unit);
   4358 
   4359     num_ip_tnl = soc_mem_index_count(unit, mem);
   4360 
   4361     for (;idx < num_ip_tnl; idx++) {
   4362         mpls_off = 0;
   4363         temp_num_labels = num_labels;
   4364 
   4365         bcmi_egr_ip_tnl_mpls_uncheck_free_indexes(unit, fi, tunnel_entry);
   4366 
   4367         if (!_BCM_MPLS_IP_TNL_USED_GET(unit, idx)) {
   4368             continue;
   4369         }
   4370         if (free_indexes_changed) {
   4371             bcmi_egr_ip_tnl_mpls_create_local_free_indexes(unit, fi, &local_fi);
   4372         }
   4373         free_indexes_changed=0;
   4374         mpls_index = idx * ent_per_tunnel;
   4375         /* check for quad entry free */
   4376         for(;mpls_off < ent_per_tunnel; mpls_off++) {
   4377             found = 0;
   4378             /*
   4379              * if we have just started for entry, then do basic index checking.
   4380              * if number of labels are 3 or 4 then only index 0 or index 4 are
   4381              * valid indexes.
   4382              * if number of labels are bigger than 4 then entry can start only
   4383              * at index 0.
   4384              * based on above rules, move the index to the next valid index.
   4385              */
   4386             if (temp_num_labels == num_labels) {
   4387                 src_mpls_index = mpls_index + mpls_off;
   4388                 if ((num_labels < 5) && (num_labels > 2)) {
   4389                     if (mpls_off < 4 && mpls_off > 0) {
   4390                         mpls_off = 4;
   4391                     } else if (mpls_off > 4) {
   4392                         mpls_off = 7;
   4393                         continue;
   4394                     }
   4395                 }
   4396                 if ((num_labels > 4) && (mpls_off > 0)) {
   4397                     mpls_off = 7;
   4398                     continue;
   4399                 }
   4400             }
   4401 
   4402             /* If this is free index then continue until you get free space. */
   4403             if (!_BCM_MPLS_TNL_USED_GET(unit, (mpls_index + mpls_off))) {
   4404                 temp_num_labels--;
   4405                 free_db_entries++;
   4406                 if (temp_num_labels) {
   4407                     continue;
   4408                 }
   4409             }
   4410 
   4411             /* If we are looking at same index as free index. then continue. */
   4412             if (free_db_entries) {
   4413                 bcmi_mpls_egr_tunnel_delete_free_indexes(unit,
   4414                     &local_fi, free_db_entries, (mpls_index + mpls_off - free_db_entries));
   4415                 free_indexes_changed = 1;
   4416             }
   4417 
   4418             free_db_entries = 0;
   4419             if(tunnel_entry[idx]->label_entry[mpls_off]->flags &
   4420                 BCMI_EGR_IP_TUNNEL_MPLS_START_OF_ENTRY) {
   4421                 /* this is the start of this entry,
   4422                  * we should check if we have some free space for this entry
   4423                  */
   4424                 no_of_elements =
   4425                     tunnel_entry[idx]->label_entry[mpls_off]->num_elements;
   4426                 /* we also should check if there are some bigger entries
   4427                  * in this tunnel entry,
   4428                  * big entries can be adjusted to other big entries if exists.
   4429                  * else we might have to move smaller entries to bigger entries
   4430                  */
   4431                 if (no_of_elements >= num_labels) {
   4432                     /*
   4433                      * no need to look for bigger entry as this is already
   4434                      * checked above.
   4435                      * if we could move bigger entry then we could have moved
   4436                      * incoming entry itself
   4437                      * so please return back with update to indexes.
   4438                      */
   4439                     mpls_off += no_of_elements;
   4440                     temp_num_labels = num_labels;
   4441                     if (free_indexes_changed) {
   4442                         bcmi_egr_ip_tnl_mpls_create_local_free_indexes(unit,
   4443                             fi, &local_fi);
   4444                     }
   4445 
   4446                      /*
   4447                       * we are doing continue here because we may like to
   4448                       * check further entries also.
   4449                       */
   4450                      bcmi_egr_ip_tnl_mpls_uncheck_free_indexes(unit,
   4451                          fi, tunnel_entry);
   4452                      continue;
   4453                 }
   4454 
   4455                 for (f_idx=no_of_elements-1; f_idx < 8; f_idx++) {
   4456                     if (!(local_fi.free_index_count[f_idx])) {
   4457                         continue;
   4458                     }
   4459                     for (free_idx=0; free_idx<8; free_idx++) {
   4460                         /* There is some empty place here.
   4461                          * lets use the same size entry or bigger.
   4462                          * returning the first free entry in that block.
   4463                          */
   4464                         if (local_fi.free_entry_indexes[f_idx][free_idx]
   4465                             == -1) {
   4466 
   4467                             break;
   4468                         }
   4469 
   4470                         chk_tnl_idx =
   4471                           local_fi.free_entry_indexes[f_idx][free_idx] /
   4472                               ent_per_tunnel;
   4473                         chk_mpls_idx =
   4474                           local_fi.free_entry_indexes[f_idx][free_idx] %
   4475                               ent_per_tunnel;
   4476 
   4477                         label_entry =
   4478                           tunnel_entry[chk_tnl_idx]->label_entry[chk_mpls_idx];
   4479 
   4480                         if (!(label_entry->flags &
   4481                                     BCMI_EGR_IP_TUNNEL_MPLS_ENTRY_CHECKED)) {
   4482                             /*
   4483                              * we can use free_entry_indexes[idx][free_idx];
   4484                              * mark this entry used so that next lookup should
   4485                              * not use this.
   4486                              */
   4487                             label_entry->flags |=
   4488                                 BCMI_EGR_IP_TUNNEL_MPLS_ENTRY_CHECKED;
   4489 
   4490                             found = 1;
   4491                             free_indexes_changed = 1;
   4492 
   4493                             temp_num_labels -= no_of_elements;
   4494                             /* mpls_off is loop incrementing value. so reduce it. */
   4495                             mpls_off += (no_of_elements - 1);
   4496                             new_start_index =
   4497                                 local_fi.free_entry_indexes[f_idx][free_idx] +
   4498                                 no_of_elements;
   4499                             bcmi_mpls_egr_tunnel_delete_free_indexes(unit,
   4500                                 &local_fi, no_of_elements,
   4501                                 fi->free_entry_indexes[f_idx][free_idx]);
   4502 
   4503                             left_free_entries = (f_idx+1)-no_of_elements;
   4504                             bcm_egr_ip_tnl_mpls_remark_free_indexes(unit,
   4505                                 left_free_entries, new_start_index, &local_fi);
   4506                             break;
   4507                         }
   4508                     }
   4509                     if (found) {
   4510                         break;
   4511                     }
   4512                 }
   4513                 if (!found) {
   4514                     temp_num_labels = num_labels;
   4515                 }
   4516             }
   4517             if (temp_num_labels <= 0) {
   4518 
   4519                 /* if we are here that means we have got required space.
   4520                  * get ready to move the entries.
   4521                  */
   4522                 int mpls_tnl_off = src_mpls_index % ent_per_tunnel;
   4523 
   4524                 bcmi_egr_ip_tnl_mpls_uncheck_free_indexes(unit, fi,
   4525                     tunnel_entry);
   4526                 rv = bcmi_egr_ip_tnl_mpls_move_tunnel_entries(unit, fi,
   4527                     tunnel_entry, idx, mpls_tnl_off, num_labels);
   4528 
   4529                 if (rv == BCM_E_NONE) {
   4530                     *tnl_idx = src_mpls_index;
   4531                     /* we have got the index where we can fill this entry
   4532                      * But we can have some free entries beneath it.
   4533                      * so return those free entries to free indexes.
   4534                      */
   4535 /*
   4536                     bcm_egr_ip_tnl_mpls_remark_free_indexes(unit,
   4537                         (ent_per_tunnel - num_labels - mpls_tnl_off),
   4538                         src_mpls_index, &(fi_db[unit]));
   4539 */
   4540                     return rv;
   4541                 }
   4542             }
   4543         }
   4544     }
   4545     /*
   4546      * if we are here then we have not got the space.
   4547      * Currently return BCM_E_FULLL.
   4548      */
   4549     return BCM_E_FULL;
   4550 }
   4551 
   4552 /*
   4553  * Function:
   4554  *      bcmi_xgs5_mpls_tunnel_initiator_set
   4555  * Purpose:
   4556  *      Set MPLS Tunnel initiator
   4557  * Parameters:
   4558  *      unit - Device Number
   4559  *      intf - The egress L3 interface
   4560  *      num_labels  - Number of labels in the array
   4561  *      label_array - Array of MPLS label and header information
   4562  * Returns:
   4563  *      BCM_E_XXX
   4564  */
   4565 int
   4566 bcmi_xgs5_mpls_tunnel_initiator_set(int unit, bcm_if_t intf, int num_labels,
   4567                                  bcm_mpls_egress_label_t *label_array)
   4568 {
   4569     egr_l3_intf_entry_t if_entry;
   4570     int rv, num_mpls_map, i, push_action=0, offset = 0;
   4571     int found = 0, tnl_index = 0, mpls_index = 0;
   4572     int hw_map_idx;
   4573     bcm_tunnel_initiator_t tnl_init;
   4574     uint32 tnl_flags = 0;
   4575     int match_mpls_tunnel_index=-1;
   4576     int ent_per_tnl = 0;
   4577     int tnl_id = 0;
   4578     int mpls_offset = 0;
   4579     int mpls_tunnel_update = 0;
   4580     bcmi_egr_ip_tnl_mpls_tunnel_entry_t **tunnel_entry;
   4581     soc_mem_t mem;
   4582     uint32 tnl_entry[SOC_MAX_MEM_WORDS];
   4583     uint32 iptun_mpls_entry_format[3] = {0};
   4584 
   4585     mem = bcmi_egr_ip_tnl_mem_name_get(unit);
   4586     ent_per_tnl = _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit);
   4587     tunnel_entry = egr_mpls_tnl_sw_state[unit];
   4588 
   4589     if ((num_labels < 0) || (num_labels > ent_per_tnl)  ||
   4590         (intf < 0) || (intf >= L3_INFO(unit)->l3_intf_table_size)) {
   4591         return BCM_E_PARAM;
   4592     }
   4593 
   4594     if ((num_labels > 2) &&
   4595          !(soc_feature(unit, soc_feature_mpls_segment_routing)) &&
   4596          !(soc_feature(unit, soc_feature_th3_style_simple_mpls))) {
   4597         return BCM_E_UNAVAIL;
   4598     }
   4599 
   4600     /* Derive action from labels.
   4601      * based on number of labels, we can set multiple entries to add
   4602      * desired number of labels into the tunnel.
   4603      * Therefore push action is directly derived from num labels.
   4604      */
   4605     push_action = num_labels;
   4606 
   4607     /* Param checking */
   4608     num_mpls_map = soc_mem_index_count(unit, EGR_MPLS_EXP_MAPPING_1m) / 64;
   4609     for (i = 0; i < num_labels; i++) {
   4610         if (label_array[i].qos_map_id == 0) { /* treat it as using default */
   4611             hw_map_idx = 0;
   4612         } else {
   4613             BCM_IF_ERROR_RETURN(_egr_qos_id2hw_idx(unit,
   4614                             label_array[i].qos_map_id,&hw_map_idx));
   4615         }
   4616         if ((label_array[i].label > 0xfffff) ||
   4617             (hw_map_idx < 0) ||
   4618             (hw_map_idx >= num_mpls_map) ||
   4619             (label_array[i].exp > 7) || (label_array[i].pkt_pri > 7) ||
   4620             (label_array[i].pkt_cfi > 1)) {
   4621             return BCM_E_PARAM;
   4622         }
   4623     }
   4624     if (!BCM_L3_INTF_USED_GET(unit, intf)) {
   4625         LOG_INFO(BSL_LS_BCM_L3,
   4626                  (BSL_META_U(unit,
   4627                              "L3 interface not created\n")));
   4628         return BCM_E_NOT_FOUND;
   4629     }
   4630 
   4631     /* L3 interface info */
   4632     rv = READ_EGR_L3_INTFm(unit, MEM_BLOCK_ANY, intf, &if_entry);
   4633     if (rv < 0) {
   4634         return rv;
   4635     }
   4636    /* init the allocated entry */
   4637    bcmi_egr_ip_tnl_mpls_table_memset(unit,tnl_entry);
   4638 
   4639    /* Case of Dummy Tunnel entry sharing by multiple L3_INTF */
   4640    if (num_labels == 0) {
   4641        /* Lookup if Tunnel Entry with Tunnel Label exists? */
   4642        rv = bcmi_xgs5_mpls_egr_tunnel_lookup (unit, push_action, tunnel_entry,
   4643                                NULL, &match_mpls_tunnel_index);
   4644        if (rv < 0) {
   4645           return rv;
   4646        }
   4647 
   4648        if (match_mpls_tunnel_index != -1) {
   4649            /* L3_Interface to point to mpls_tunnel */
   4650            soc_EGR_L3_INTFm_field32_set(unit, &if_entry,
   4651                               MPLS_TUNNEL_INDEXf, match_mpls_tunnel_index);
   4652            /* Increment Ref count */
   4653            bcmi_egr_ip_tnl_mpls_ref_count_adjust (unit,
   4654                               match_mpls_tunnel_index, 1);
   4655            rv = WRITE_EGR_L3_INTFm(unit, MEM_BLOCK_ANY, intf, &if_entry);
   4656 
   4657            if (rv == BCM_E_NONE) {
   4658                tnl_id = match_mpls_tunnel_index/ent_per_tnl;
   4659                mpls_offset = match_mpls_tunnel_index % ent_per_tnl;
   4660                rv = bcmi_egr_ip_tnl_mpls_intf_list_add
   4661                    (unit, tunnel_entry, intf, tnl_id, mpls_offset);
   4662 
   4663            }
   4664            return rv;
   4665        }
   4666    }
   4667 
   4668    for (i = 0; i < num_labels; i++) {
   4669        /* Check for Port_independent Label mapping */
   4670        rv = bcm_tr_mpls_port_independent_range (unit, label_array[i].label,
   4671                                                       BCM_GPORT_INVALID);
   4672        /* Either Port-scope-label or Explicit-Null-label */
   4673        if ((rv == BCM_E_CONFIG) || (label_array[i].label == 0)) {
   4674            /* Tunnel-label is Port-based */
   4675            /* Lookup if Tunnel Entry with Tunnel Label exists? */
   4676            rv = bcmi_xgs5_mpls_egr_tunnel_lookup (unit, push_action,
   4677                tunnel_entry, label_array, &match_mpls_tunnel_index);
   4678            if (rv < 0) {
   4679               return rv;
   4680            }
   4681 
   4682            if (match_mpls_tunnel_index != -1) {
   4683                /* L3_Interface to point to mpls_tunnel */
   4684                soc_EGR_L3_INTFm_field32_set(unit, &if_entry,
   4685                    MPLS_TUNNEL_INDEXf, match_mpls_tunnel_index);
   4686                /* Increment Ref count */
   4687                bcmi_egr_ip_tnl_mpls_ref_count_adjust (unit,
   4688                    match_mpls_tunnel_index, 1);
   4689                /* we also need to add this entry into sw state linked list */
   4690                rv = WRITE_EGR_L3_INTFm(unit, MEM_BLOCK_ANY, intf, &if_entry);
   4691                if (rv == BCM_E_NONE) {
   4692                    tnl_id = match_mpls_tunnel_index/ent_per_tnl;
   4693                    offset = match_mpls_tunnel_index % ent_per_tnl;
   4694                    rv = bcmi_egr_ip_tnl_mpls_intf_list_add(unit, tunnel_entry,
   4695                        intf, tnl_id, offset);
   4696                }
   4697                return rv;
   4698            }
   4699        }
   4700     }
   4701     mpls_index = soc_EGR_L3_INTFm_field32_get(unit, &if_entry,
   4702                                               MPLS_TUNNEL_INDEXf);
   4703     tnl_index = mpls_index / ent_per_tnl;
   4704 
   4705     if ((mpls_index != 0) && (_BCM_MPLS_TNL_USED_GET(unit, mpls_index))) {
   4706        /* Obtain referenced Tunnel entry */
   4707        /* try using existing entry in tunnel */
   4708         rv = bcmi_egr_ip_tnl_mpls_table_read(unit,tnl_index,tnl_entry);
   4709 
   4710         if (rv < 0) {
   4711             return rv;
   4712         }
   4713 
   4714         rv = bcmi_egr_ip_tnl_mpls_entry_type_check(unit, tnl_entry);
   4715 
   4716         if (rv < 0) {
   4717             return rv;
   4718         }
   4719 
   4720         /* we need to check here if at least number of labels is same.*/
   4721         offset = mpls_index % ent_per_tnl;
   4722         if (tunnel_entry[tnl_index]->label_entry[offset]->flags &
   4723             BCMI_EGR_IP_TUNNEL_MPLS_START_OF_ENTRY) {
   4724             if (tunnel_entry[tnl_index]->label_entry[offset]->num_elements !=
   4725                 num_labels) {
   4726                 /* Changing push action/ num labels is not permitted,
   4727                  * need to clear/set
   4728                  */
   4729                 return BCM_E_PARAM;
   4730             }
   4731         } else {
   4732             return BCM_E_PARAM;
   4733         }
   4734         mpls_tunnel_update = 1;
   4735 
   4736     } else {
   4737         /* allocate an unused EGR_IP_TUNNEL_MPLS_ENTRY */
   4738         /*
   4739          * First try finding an allocated tunnel entry with
   4740          * unused MPLS entries.
   4741          */
   4742         mpls_index =  bcmi_egr_ip_tnl_mpls_check_availability(unit,
   4743             &(fi_db[unit]), num_labels);
   4744 
   4745         if (mpls_index == -1) {
   4746             /*
   4747              * we have not got corresponding free indexes.
   4748              * lets try to create some more free indexes
   4749              * and then try again.
   4750              */
   4751             mpls_index = bcmi_egr_ip_tnl_mpls_get_free_index(unit, num_labels,
   4752                 tunnel_entry, &(fi_db[unit]));
   4753         }
   4754         if (mpls_index != -1) {
   4755                found = 1;
   4756             tnl_index = mpls_index /
   4757                 (_BCM_MPLS_EGR_L3_INTF_MPLS_INDEX_OFFSET_MASK(unit) + 1);
   4758 
   4759             rv = bcmi_egr_ip_tnl_mpls_table_read(unit,tnl_index,tnl_entry);
   4760             if (rv < 0) {
   4761                 return rv;
   4762             }
   4763 
   4764         } else {
   4765             /*
   4766              * Alloc an egr_ip_tunnel entry. By calling bcm_xgs3_tnl_init_add
   4767              * with _BCM_L3_SHR_WRITE_DISABLE flag, a tunnel index is
   4768              * allocated but nothing is written to hardware. The "tnl_init"
   4769              * information is not used, set to all zero.
   4770              */
   4771             sal_memset(&tnl_init, 0, sizeof(bcm_tunnel_initiator_t));
   4772             tnl_flags = _BCM_L3_SHR_MATCH_DISABLE | _BCM_L3_SHR_WRITE_DISABLE |
   4773                 _BCM_L3_SHR_SKIP_INDEX_ZERO;
   4774             tnl_init.type =  bcmTunnelTypeMpls;
   4775             rv = bcm_xgs3_tnl_init_add(unit, tnl_flags, &tnl_init, &tnl_index);
   4776             if (rv == BCM_E_FULL) {
   4777 
   4778                 /* There is no entry left unused.
   4779                  * now see if we can move some entries and make space
   4780                  */
   4781 
   4782                 rv = bcmi_egr_ip_tnl_mpls_adjust_entry(unit, num_labels,
   4783                     tunnel_entry, &(fi_db[unit]), &mpls_index);
   4784                 if (rv < 0) {
   4785                     return rv;
   4786                 }
   4787 
   4788             } else {
   4789                 found = 1;
   4790                 /* we have got full entry here. start at 0 index.
   4791                  * we will get double entry from l3_tbl_add as it
   4792                  *  works on common resorce of egr_ip_tunnel.
   4793                  *  But egr_ip_tunnel_mpls uses double entries.
   4794                  */
   4795                 tnl_index = (tnl_index + 1)/2;
   4796                 mpls_index =  tnl_index *
   4797                     (_BCM_MPLS_EGR_L3_INTF_MPLS_INDEX_OFFSET_MASK(unit) + 1);
   4798                 /* we are using two tunnel entries at same time.*/
   4799                 _BCM_MPLS_IP_TNL_USED_SET(unit, tnl_index);
   4800                 _BCM_MPLS_TNL_USED_SET(unit, mpls_index);
   4801 
   4802                 bcmi_egr_ip_tnl_mpls_table_memset(unit,tnl_entry);
   4803                 if (num_labels < ent_per_tnl) {
   4804                     bcm_egr_ip_tnl_mpls_remark_free_indexes(unit,
   4805                         (ent_per_tnl - ((num_labels) ? num_labels : 1)),
   4806                         mpls_index+((num_labels) ? num_labels : 1),
   4807                         &(fi_db[unit]));
   4808                 }
   4809             }
   4810         }
   4811     }
   4812 
   4813     offset = mpls_index & _BCM_MPLS_EGR_L3_INTF_MPLS_INDEX_OFFSET_MASK(unit);
   4814     tnl_id = mpls_index /
   4815         (_BCM_MPLS_EGR_L3_INTF_MPLS_INDEX_OFFSET_MASK(unit) + 1);
   4816 
   4817     tunnel_entry[tnl_id]->label_entry[offset]->flags |=
   4818                 BCMI_EGR_IP_TUNNEL_MPLS_START_OF_ENTRY;
   4819     tunnel_entry[tnl_id]->label_entry[offset]->num_elements =
   4820         ((num_labels) ? num_labels : 1);
   4821 
   4822     if (!num_labels) {
   4823         tunnel_entry[tnl_id]->label_entry[offset]->flags |=
   4824                 BCMI_EGR_IP_TUNNEL_MPLS_ENTRY_ZERO;
   4825     }
   4826 
   4827     rv = bcmi_egr_ip_tnl_mpls_table_read(unit, tnl_id,tnl_entry);
   4828     if (rv < 0) {
   4829         return rv;
   4830     }
   4831 
   4832     for (i = 0; i < num_labels; i++) {
   4833         if (label_array[i].qos_map_id == 0) { /* treat it as using default */
   4834             hw_map_idx = 0;
   4835         } else {
   4836             rv = _egr_qos_id2hw_idx(unit,
   4837                             label_array[i].qos_map_id,&hw_map_idx);
   4838             if (rv < 0) {
   4839                 goto cleanup;
   4840             }
   4841         }
   4842 
   4843         bcmi_egr_ip_tnl_mpls_entry_format_set(unit, bcmiMplsPushAction,
   4844                 tnl_entry, offset,
   4845                 iptun_mpls_entry_format,
   4846                 ((i == (num_labels - 1)) ? 1 : 2));
   4847         if (num_labels > 0) {
   4848             bcmi_egr_ip_tnl_mpls_entry_format_set(unit, bcmiMplsLabel,
   4849                     tnl_entry, offset,
   4850                     iptun_mpls_entry_format, label_array[i].label);
   4851         }
   4852 
   4853 #if defined(BCM_TRIDENT3_SUPPORT)
   4854         if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   4855             bcmi_egr_ip_tnl_mpls_entry_format_set(unit, bcmiSpecialLabelPushType,
   4856                     tnl_entry, offset,
   4857                     iptun_mpls_entry_format, label_array[i].spl_label_push_type);
   4858         }
   4859 #endif
   4860 
   4861         if ((label_array[i].flags & BCM_MPLS_EGRESS_LABEL_EXP_SET) ||
   4862             (label_array[i].flags & BCM_MPLS_EGRESS_LABEL_PRI_SET)) {
   4863 
   4864             /* Use the specified EXP, PRI and CFI */
   4865             if ((label_array[i].flags & BCM_MPLS_EGRESS_LABEL_EXP_REMARK) ||
   4866                 (label_array[i].flags & BCM_MPLS_EGRESS_LABEL_EXP_COPY) ||
   4867                 (label_array[i].flags & BCM_MPLS_EGRESS_LABEL_PRI_REMARK)) {
   4868                 rv = BCM_E_PARAM;
   4869                 goto cleanup;
   4870             }
   4871 
   4872             bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   4873                     bcmiMplsExpSelect,
   4874                     tnl_entry, offset,
   4875                     iptun_mpls_entry_format, 0);
   4876 
   4877             bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   4878                     bcmiMplsExp,
   4879                     tnl_entry, offset,
   4880                     iptun_mpls_entry_format,
   4881                     label_array[i].exp);
   4882 
   4883             bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   4884                     bcmiNewPri,
   4885                     tnl_entry, offset,
   4886                     iptun_mpls_entry_format,
   4887                     label_array[i].pkt_pri);
   4888 
   4889             bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   4890                     bcmiNewCfi,
   4891                     tnl_entry, offset,
   4892                     iptun_mpls_entry_format,
   4893                     label_array[i].pkt_cfi);
   4894         } else if (label_array[i].flags & BCM_MPLS_EGRESS_LABEL_EXP_REMARK) {
   4895             if (label_array[i].flags & BCM_MPLS_EGRESS_LABEL_PRI_SET) {
   4896                 rv = BCM_E_PARAM;
   4897                 goto cleanup;
   4898             }
   4899             /* Use EXP-map for EXP, PRI and CFI */
   4900             bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   4901                     bcmiMplsExpSelect,
   4902                     tnl_entry, offset,
   4903                     iptun_mpls_entry_format, 0x1);
   4904 
   4905             bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   4906                     bcmiMplsExpMappingPtr,
   4907                     tnl_entry, offset,
   4908                     iptun_mpls_entry_format,
   4909                     hw_map_idx);
   4910 
   4911             if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   4912                 if(i == 1) {
   4913                     /*EGR_MPLS_EXP_MAPPING_3 for Tunnel label 2*/
   4914                     bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   4915                             bcmiExpMappingTableSelect,
   4916                             tnl_entry, offset,
   4917                             iptun_mpls_entry_format, 0x2);
   4918                 }
   4919 
   4920                 if(i == 0) {
   4921                     /*EGR_MPLS_EXP_MAPPING_2 for Tunnel label 1*/
   4922                     bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   4923                             bcmiExpMappingTableSelect,
   4924                             tnl_entry, offset,
   4925                             iptun_mpls_entry_format, 0x1);
   4926                 }
   4927             }
   4928 
   4929         } else { /* BCM_MPLS_EGRESS_LABEL_EXP_COPY */
   4930             /* Use EXP from inner label. If there is no inner label,
   4931              * use the specified EXP value. Use EXP-map for PRI/CFI.
   4932              */
   4933             bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   4934                     bcmiMplsExpSelect,
   4935                     tnl_entry, offset,
   4936                     iptun_mpls_entry_format, 0x2); /* USE_INNER */
   4937 
   4938             bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   4939                     bcmiMplsExp,
   4940                     tnl_entry, offset,
   4941                     iptun_mpls_entry_format,
   4942                     label_array[i].exp);
   4943 
   4944             bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   4945                     bcmiMplsExpMappingPtr,
   4946                     tnl_entry, offset,
   4947                     iptun_mpls_entry_format,
   4948                     hw_map_idx);
   4949 
   4950         }
   4951 
   4952         if (label_array[i].flags & BCM_MPLS_EGRESS_LABEL_TTL_SET) {
   4953             bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   4954                     bcmiMplsTtl,
   4955                     tnl_entry, offset,
   4956                     iptun_mpls_entry_format,
   4957                     label_array[i].ttl);
   4958         } else {
   4959             bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   4960                     bcmiMplsTtl,
   4961                     tnl_entry, offset,
   4962                     iptun_mpls_entry_format,
   4963                     0);
   4964         }
   4965 
   4966 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   4967         if (soc_feature(unit, soc_feature_mpls_ecn)) {
   4968             if (label_array[i].flags & BCM_MPLS_EGRESS_LABEL_ECN_TO_EXP_MAP) {
   4969                 int ecn_map_index;
   4970                 int ecn_map_type;
   4971                 int ecn_map_num;
   4972                 int ecn_map_hw_idx;
   4973                 soc_mem_t mem;
   4974 
   4975                 ecn_map_type = label_array[i].ecn_map_id & 
   4976                                 _BCM_XGS5_MPLS_ECN_MAP_TYPE_MASK;
   4977                 ecn_map_index = label_array[i].ecn_map_id & 
   4978                                 _BCM_XGS5_MPLS_ECN_MAP_NUM_MASK;
   4979 
   4980 #if defined(BCM_TRIDENT3_SUPPORT)
   4981                 if(soc_feature(unit, soc_feature_td3_style_mpls)) {
   4982                     mem = EGR_PKT_ECN_TO_EXP_MAPPING_1m;
   4983                 } else
   4984 #endif
   4985                 {   
   4986                     mem = EGR_IP_ECN_TO_EXP_MAPPING_TABLEm;
   4987                 }
   4988 
   4989                 ecn_map_num = soc_mem_index_count(unit, mem) /
   4990                     _BCM_ECN_MAX_ENTRIES_PER_MAP;
   4991                 if (ecn_map_type != _BCM_XGS5_MPLS_ECN_MAP_TYPE_ECN2EXP) {
   4992                     rv = BCM_E_PARAM;
   4993                     goto cleanup;
   4994                 }
   4995                 if (ecn_map_index >= ecn_map_num) {
   4996                     rv = BCM_E_PARAM;
   4997                     goto cleanup;
   4998                 }
   4999                 if (!bcmi_xgs5_ecn_map_used_get(unit, ecn_map_index, 
   5000                                                 _bcmEcnmapTypeIpEcn2Exp)) {
   5001                     rv = BCM_E_PARAM;
   5002                     goto cleanup; 
   5003                 }
   5004                 rv = bcmi_ecn_map_id2hw_idx(unit, label_array[i].ecn_map_id, 
   5005                                             &ecn_map_hw_idx);
   5006                 if (BCM_FAILURE(rv)) {
   5007                     goto cleanup;
   5008                 }
   5009 #if defined(BCM_TRIDENT3_SUPPORT)
   5010                 if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   5011                     bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   5012                             bcmiPktEcnToExpMappingPtr,
   5013                             tnl_entry, offset,
   5014                             iptun_mpls_entry_format,
   5015                             ecn_map_hw_idx);
   5016 
   5017                     /*ECN_MAPPING_ENABLE Remap EXP to encode ECN.*/
   5018                     bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   5019                             bcmiEcnMappingEnable,
   5020                             tnl_entry, offset,
   5021                             iptun_mpls_entry_format, 1);
   5022 
   5023                     bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   5024                             bcmiEcnMappingTableSelect,
   5025                             tnl_entry, offset,
   5026                             iptun_mpls_entry_format, 2);
   5027 
   5028                     if (label_array[i].flags & 
   5029                             BCM_MPLS_EGRESS_LABEL_ECN_EXP_MAP_TRUST) {
   5030                         bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   5031                                 bcmiPktEcnToExpPriority,
   5032                                 tnl_entry, offset,
   5033                                 iptun_mpls_entry_format, 1);
   5034                     } else {
   5035                         bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   5036                                 bcmiPktEcnToExpPriority,
   5037                                 tnl_entry, offset,
   5038                                 iptun_mpls_entry_format, 0);
   5039                     }
   5040                 } else 
   5041 #endif
   5042                 {
   5043                 /* Coverity issue ignored:
   5044                  * It cannot overrun size by 8 since the macro
   5045                  * _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX is 8 or 4
   5046                  * hence, the scenario does not arise */
   5047                 /* coverity[overrun-local : FALSE] */
   5048                 soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, &tnl_entry, 
   5049                                     _tnl_ecn_ptr_f[offset], 
   5050                                     ecn_map_hw_idx); 
   5051                 if (label_array[i].flags & 
   5052                     BCM_MPLS_EGRESS_LABEL_ECN_EXP_MAP_TRUST) {
   5053                     /* coverity[overrun-local : FALSE] */
   5054                     soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, &tnl_entry, 
   5055                                         _tnl_ecn_ptr_pri_f[offset], 1);
   5056                 } else {
   5057                     /* coverity[overrun-local : FALSE] */
   5058                     soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, &tnl_entry, 
   5059                                         _tnl_ecn_ptr_pri_f[offset], 0);
   5060 
   5061                 }
   5062             }
   5063             }
   5064             if (label_array[i].flags & BCM_MPLS_EGRESS_LABEL_INT_CN_TO_EXP_MAP) {
   5065                 int ecn_map_index;
   5066                 int ecn_map_type;
   5067                 int ecn_map_num;
   5068                 int ecn_map_hw_idx;
   5069                 soc_mem_t mem;
   5070                 ecn_map_type = label_array[i].int_cn_map_id & 
   5071                                 _BCM_XGS5_MPLS_ECN_MAP_TYPE_MASK;
   5072                 ecn_map_index = label_array[i].int_cn_map_id & 
   5073                                 _BCM_XGS5_MPLS_ECN_MAP_NUM_MASK;
   5074 
   5075 #if defined(BCM_TRIDENT3_SUPPORT)
   5076                 if(soc_feature(unit, soc_feature_td3_style_mpls)) {
   5077                     mem = EGR_PKT_ECN_TO_EXP_MAPPING_1m;
   5078                 } else
   5079 #endif
   5080                 {
   5081                     mem = EGR_IP_ECN_TO_EXP_MAPPING_TABLEm;
   5082                 }
   5083 
   5084                 ecn_map_num = soc_mem_index_count(unit, mem) /
   5085                     _BCM_ECN_MAX_ENTRIES_PER_MAP;
   5086 
   5087                 if (ecn_map_type != _BCM_XGS5_MPLS_ECN_MAP_TYPE_INTCN2EXP) {
   5088                     rv = BCM_E_PARAM;
   5089                     goto cleanup;
   5090 
   5091                 }
   5092                 if (ecn_map_index >= ecn_map_num) {
   5093                     rv = BCM_E_PARAM;
   5094                     goto cleanup;
   5095                 }
   5096                 if (!bcmi_xgs5_ecn_map_used_get(unit, ecn_map_index, 
   5097                                                 _bcmEcnmapTypeIntcn2Exp)) {
   5098                     rv = BCM_E_PARAM;
   5099                     goto cleanup;
   5100                 }
   5101                 rv = bcmi_ecn_map_id2hw_idx(unit, label_array[i].int_cn_map_id, 
   5102                                             &ecn_map_hw_idx);
   5103                 if (BCM_FAILURE(rv)) {
   5104                     goto cleanup;
   5105                 }
   5106                 /* Coverity issue ignored:
   5107                  * It cannot overrun size by 8 since the macro
   5108                  * _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX is 8 or 4
   5109                  * hence, the scenario does not arise */
   5110                 /* coverity[overrun-local : FALSE] */
   5111                 soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, &tnl_entry, 
   5112                                     _tnl_int_cn_ptr_f[offset], 
   5113                                     ecn_map_hw_idx); 
   5114                 if (label_array[i].flags & 
   5115                     BCM_MPLS_EGRESS_LABEL_ECN_EXP_MAP_TRUST) {
   5116                     /* coverity[overrun-local : FALSE] */
   5117                     soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, &tnl_entry, 
   5118                                         _tnl_int_cn_ptr_pri_f[offset], 1);
   5119                 } else {
   5120                     /* coverity[overrun-local : FALSE] */
   5121                     soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, &tnl_entry, 
   5122                                         _tnl_int_cn_ptr_pri_f[offset], 0);
   5123 
   5124                 }
   5125             }            
   5126         }
   5127 #endif  
   5128  
   5129          /*After filling all fields in EGR_IP_TUNNEL_MPLS_ENTRY_FORMAT
   5130           *set MPLS_ENTRY_Xf*/
   5131          /* Coverity issue ignored:
   5132           * It cannot overrun size by 8 since the macro
   5133           * _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX is 8 or 4
   5134           * hence, the scenario does not arise */
   5135         /* coverity[overrun-local : FALSE] */
   5136         if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   5137             bcmi_egress_tnl_label_entry_set(unit, tnl_entry,
   5138                     offset, iptun_mpls_entry_format);
   5139         }
   5140 
   5141         offset++;
   5142         _BCM_MPLS_TNL_USED_SET(unit, mpls_index + i);
   5143     }
   5144     bcmi_egr_ip_tnl_mpls_ref_count_adjust (unit,
   5145                                 mpls_index, 1);
   5146 
   5147 #if defined(BCM_TRIDENT3_SUPPORT)
   5148     if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   5149         soc_mem_field32_set(unit, mem,
   5150                 &tnl_entry, DATA_TYPEf, 0x14);
   5151         soc_mem_field32_set(unit, mem,
   5152                 &tnl_entry, DATA_TYPE_COPYf, 0x14);
   5153     } else
   5154 #endif
   5155     {
   5156         soc_mem_field32_set(unit, mem, &tnl_entry,
   5157                 ENTRY_TYPEf, 0x3);
   5158         soc_mem_field32_set(unit, mem, &tnl_entry,
   5159                 ENTRY_TYPE_COPYf, 0x3);
   5160     }
   5161 
   5162     /* Commit the values to HW */
   5163     rv = bcmi_egr_ip_tnl_mpls_table_write(unit, tnl_id, tnl_entry);
   5164     if (rv < 0) {
   5165         goto cleanup;
   5166     }
   5167 
   5168     /* Update the EGR_L3_INTF to point to the MPLS tunnel entry */
   5169     rv = soc_mem_field32_modify(unit, EGR_L3_INTFm, intf,
   5170                                 MPLS_TUNNEL_INDEXf, mpls_index);
   5171     if (rv < 0) {
   5172         goto cleanup;
   5173     }
   5174 
   5175 
   5176     offset = mpls_index & _BCM_MPLS_EGR_L3_INTF_MPLS_INDEX_OFFSET_MASK(unit);
   5177     tnl_id = mpls_index / (_BCM_MPLS_EGR_L3_INTF_MPLS_INDEX_OFFSET_MASK(unit) + 1);
   5178 
   5179     rv = bcmi_egr_ip_tnl_mpls_intf_list_add(unit, tunnel_entry, intf, tnl_id, offset);
   5180     if (rv < 0) {
   5181         goto cleanup;
   5182     }
   5183 
   5184 #ifdef BCM_WARM_BOOT_SUPPORT
   5185     SOC_CONTROL_LOCK(unit);
   5186     SOC_CONTROL(unit)->scache_dirty = 1;
   5187     SOC_CONTROL_UNLOCK(unit);
   5188 #endif
   5189 
   5190     return rv;
   5191 
   5192   cleanup:
   5193     if (mpls_tunnel_update) {
   5194         return rv;
   5195     }
   5196     if (!found) {
   5197         /* Free the tunnel entry */
   5198         (void) bcm_xgs3_tnl_init_del(unit, tnl_flags, tnl_index * 2);
   5199 
   5200         /* Clear "in-use" for the IP tunnel entry */
   5201         _BCM_MPLS_IP_TNL_USED_CLR(unit, tnl_index);
   5202     }
   5203     /* Clear "in-use" for the MPLS tunnel entry(s) */
   5204     for (i = 0; i < num_labels; i++) {
   5205         _BCM_MPLS_TNL_USED_CLR(unit, mpls_index + i);
   5206     }
   5207     return rv;
   5208 }
   5209 
   5210 /*
   5211  * Function:
   5212  *      bcmi_mpls_egr_tunnel_add_free_indexes
   5213  * Purpose:
   5214  *      Adds free index entry into free indexes if the entry is freed.
   5215  * Parameters:
   5216  *      unit           - device number
   5217  *      fi             - Pointer to free indexes database.
   5218  *      num_labels     - Number of labels that entry contains.
   5219  *      mpls_entry_idx - index to mpls entry index that is used up.
   5220  * Returns:
   5221  *      None.
   5222  */
   5223 
   5224 void
   5225 bcmi_mpls_egr_tunnel_add_free_indexes(int unit,
   5226                     bcmi_egr_ip_tnl_free_indexes_t *fi,
   5227                     int num_labels, int mpls_entry_idx)
   5228 {
   5229     int tnl_index, mpls_index, offset;
   5230     int new_mpls_entry_idx, new_num_elements;
   5231     int i=0, j=0;
   5232     int ent_per_tnl = _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit);
   5233 
   5234     tnl_index = mpls_entry_idx/ent_per_tnl;
   5235     mpls_index = tnl_index * ent_per_tnl;
   5236 
   5237     new_mpls_entry_idx = mpls_entry_idx;
   5238     new_num_elements     = num_labels;
   5239    /* check from the start of an entry */
   5240     for(; i<ent_per_tnl; i++) {
   5241         if (_BCM_MPLS_TNL_USED_GET(unit, mpls_index + i)) {
   5242             continue;
   5243         }
   5244         while ((mpls_index + i + j) < mpls_entry_idx) {
   5245 
   5246             if (_BCM_MPLS_TNL_USED_GET(unit, mpls_index + i + j)) {
   5247                 i += j;
   5248                 j = 0;
   5249                 break;
   5250             }
   5251             j++;
   5252         }
   5253     }
   5254 
   5255     /* delete this free entry from the free entry db */
   5256     if (j > 0) {
   5257         new_mpls_entry_idx = mpls_entry_idx - j;
   5258         new_num_elements     = num_labels+j;
   5259         bcmi_mpls_egr_tunnel_delete_free_indexes(unit, fi, j,
   5260             new_mpls_entry_idx);
   5261     }
   5262 
   5263     offset = mpls_entry_idx % ent_per_tnl;
   5264     offset += num_labels;
   5265 
   5266     j = 0;
   5267     /* now check towards end of the entry */
   5268     for(i=offset; i<ent_per_tnl; i++) {
   5269         if (_BCM_MPLS_TNL_USED_GET(unit, mpls_index + i)) {
   5270             break;
   5271         }
   5272 
   5273         j++;
   5274     }
   5275     if (j > 0) {
   5276         /* delete this free entries from free entry db */
   5277         bcmi_mpls_egr_tunnel_delete_free_indexes(unit, fi, j,
   5278             mpls_index + offset);
   5279         new_num_elements += j;
   5280     }
   5281     /* Now we can remark this new entry into the database. */
   5282     bcm_egr_ip_tnl_mpls_remark_free_indexes(unit, new_num_elements,
   5283         new_mpls_entry_idx, fi);
   5284 }
   5285 
   5286 /*
   5287  * Function:
   5288  *      _bcm_tr_mpls_tunnel_initiator_clear
   5289  * Purpose:
   5290  *      Clear MPLS Tunnel initiator
   5291  * Parameters:
   5292  *      unit        - (IN)Device Number
   5293  *      intf        - (IN)Egress L3 interface
   5294  * Returns:
   5295  *      BCM_E_XXX
   5296  */
   5297 bcm_error_t
   5298 bcmi_xgs5_mpls_tunnel_initiator_clear(int unit, int intf_id)
   5299 {
   5300     egr_l3_intf_entry_t if_entry;
   5301     int rv, mpls_offset, mpls_entry_used, i;
   5302     int tnl_idx = 0, mpls_index = 0;
   5303     uint32 tnl_flags;
   5304     _bcm_tr_mpls_bookkeeping_t *mpls_info = MPLS_INFO(unit);
   5305     bcmi_egr_ip_tnl_mpls_tunnel_entry_t **tunnel_entry;
   5306     bcmi_egr_ip_tnl_free_indexes_t *fi = &(fi_db[unit]);
   5307     int mpls_tnl_start_index = 0;
   5308     int no_of_elements;
   5309     uint32 tnl_entry[SOC_MAX_MEM_WORDS];
   5310     uint32 data_buf[3] = {0};
   5311 
   5312     tunnel_entry = egr_mpls_tnl_sw_state[unit];
   5313 
   5314     if (tunnel_entry == NULL) {
   5315         return BCM_E_INIT;
   5316     }
   5317 
   5318     bcmi_egr_ip_tnl_mpls_table_memset(unit, tnl_entry);
   5319 
   5320     /* L3 interface info */
   5321     rv = READ_EGR_L3_INTFm(unit, MEM_BLOCK_ANY, intf_id, &if_entry);
   5322     if (rv < 0) {
   5323         return rv;
   5324     }
   5325     mpls_index = soc_EGR_L3_INTFm_field32_get(unit, &if_entry,
   5326                                               MPLS_TUNNEL_INDEXf);
   5327     tnl_idx = mpls_index / _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit);
   5328     mpls_tnl_start_index = tnl_idx * _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit);
   5329 
   5330     if (!_BCM_MPLS_TNL_USED_GET(unit, mpls_index)) {
   5331         return BCM_E_NOT_FOUND;
   5332     }
   5333 
   5334     rv = bcmi_egr_ip_tnl_mpls_table_read(unit, tnl_idx, tnl_entry);
   5335     if (rv < 0) {
   5336         return rv;
   5337     }
   5338 
   5339     rv = bcmi_egr_ip_tnl_mpls_entry_type_check(unit, tnl_entry);
   5340     if (rv < 0) {
   5341         return BCM_E_NOT_FOUND;
   5342     }
   5343 
   5344     mpls_offset = mpls_index & _BCM_MPLS_EGR_L3_INTF_MPLS_INDEX_OFFSET_MASK(unit);
   5345 
   5346 
   5347     if (tunnel_entry[tnl_idx]->label_entry[mpls_offset]->flags
   5348          & BCMI_EGR_IP_TUNNEL_MPLS_START_OF_ENTRY) {
   5349 
   5350         no_of_elements =
   5351             tunnel_entry[tnl_idx]->label_entry[mpls_offset]->num_elements;
   5352 
   5353         bcmi_egr_ip_tnl_mpls_ref_count_adjust (unit, mpls_index, -1);
   5354     } else {
   5355         return BCM_E_NOT_FOUND;
   5356     }
   5357 
   5358     rv = bcmi_egr_ip_tnl_mpls_intf_list_delete(unit, tunnel_entry, intf_id,
   5359         tnl_idx, mpls_offset);
   5360 
   5361 
   5362     if (rv < 0) {
   5363         return rv;
   5364     }
   5365 
   5366     /* Update the EGR_L3_INTF to no longer point to the MPLS tunnel entry */
   5367     rv = soc_mem_field32_modify(unit, EGR_L3_INTFm, intf_id,
   5368                                 MPLS_TUNNEL_INDEXf, 0);
   5369     if (rv < 0) {
   5370         return rv;
   5371     }
   5372 
   5373     if ( mpls_info->egr_tunnel_ref_count[mpls_index] != 0x0 ) {
   5374          return BCM_E_NONE;
   5375     }
   5376 
   5377     bcm_egr_ip_tnl_mpls_sw_entry_reset(unit, tunnel_entry, tnl_idx,
   5378         mpls_offset, 0);
   5379 
   5380     /* Clear the MPLS tunnel entry(s) */
   5381     rv = bcmi_egr_ip_tnl_mpls_table_read(unit,tnl_idx,tnl_entry);
   5382     if (rv < 0) {
   5383         return rv;
   5384     }
   5385 
   5386     for (i=0; i < no_of_elements; i++) {
   5387 
   5388         if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   5389             bcmi_egress_tnl_label_entry_set(unit, tnl_entry,
   5390                     mpls_offset + i, data_buf);
   5391         } else {
   5392             /*data_buf is dontcare in non TD3*/
   5393             /*label*/
   5394             bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   5395                     bcmiMplsLabel,
   5396                     tnl_entry, mpls_offset + i,
   5397                     data_buf,
   5398                     0);
   5399             /*Pushaction*/
   5400             bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   5401                     bcmiMplsPushAction,
   5402                     tnl_entry, mpls_offset + i,
   5403                     data_buf,
   5404                     0);
   5405             /*Expselect*/
   5406             bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   5407                     bcmiMplsExpSelect,
   5408                     tnl_entry, mpls_offset + i,
   5409                     data_buf,
   5410                     0);
   5411             /*Expptr*/
   5412             bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   5413                     bcmiMplsExpMappingPtr,
   5414                     tnl_entry, mpls_offset + i,
   5415                     data_buf,
   5416                     0);
   5417             /*Exp*/
   5418             bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   5419                     bcmiMplsExp,
   5420                     tnl_entry, mpls_offset + i,
   5421                     data_buf,
   5422                     0);
   5423             /*TTl*/
   5424             bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   5425                     bcmiMplsTtl,
   5426                     tnl_entry, mpls_offset + i,
   5427                     data_buf,
   5428                     0);
   5429         }
   5430 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   5431         if (soc_feature(unit, soc_feature_mpls_ecn)) {
   5432             if(soc_feature(unit, soc_feature_td3_style_mpls)) {
   5433                 bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   5434                         bcmiPktEcnToExpMappingPtr,
   5435                         tnl_entry, mpls_offset + i,
   5436                         data_buf,
   5437                         0);
   5438 
   5439                 bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   5440                         bcmiPktEcnToExpPriority,
   5441                         tnl_entry, mpls_offset + i,
   5442                         data_buf,
   5443                         0);
   5444 
   5445                 bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   5446                         bcmiEcnMappingEnable,
   5447                         tnl_entry, mpls_offset + i,
   5448                         data_buf,
   5449                         0);
   5450 
   5451                 bcmi_egr_ip_tnl_mpls_entry_format_set(unit,
   5452                         bcmiEcnMappingTableSelect,
   5453                         tnl_entry, mpls_offset + i,
   5454                         data_buf,
   5455                         0);
   5456             } else {
   5457             soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, &tnl_entry,
   5458                                 _tnl_ecn_ptr_f[mpls_offset + i], 0);
   5459             soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, &tnl_entry,
   5460                                 _tnl_ecn_ptr_pri_f[mpls_offset + i], 0);
   5461             soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, &tnl_entry,
   5462                                 _tnl_int_cn_ptr_f[mpls_offset + i], 0);
   5463             soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, &tnl_entry,
   5464                                 _tnl_int_cn_ptr_pri_f[mpls_offset + i], 0);            
   5465         }
   5466         }
   5467 #endif
   5468         _BCM_MPLS_TNL_USED_CLR(unit, mpls_index + i);
   5469     }
   5470 
   5471     /* See if we can free the IP tunnel base entry */
   5472     _BCM_MPLS_TNL_USED_RANGE_GET(unit, mpls_tnl_start_index,
   5473             _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit), mpls_entry_used);
   5474 
   5475     if (!mpls_entry_used) {
   5476         /* None of the 4 or 8 entries are used, free base entry */
   5477         tnl_flags = 0;
   5478         (void) bcm_xgs3_tnl_init_del(unit, tnl_flags, tnl_idx * 2);
   5479 
   5480         /* Clear "in-use" for the IP tunnel entry */
   5481         _BCM_MPLS_IP_TNL_USED_CLR(unit, tnl_idx);
   5482 
   5483         /* Clear HW Entry-Type */
   5484 #if defined(BCM_TRIDENT3_SUPPORT)
   5485         if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   5486             soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLS_DOUBLE_WIDEm,
   5487                     tnl_entry, DATA_TYPE_COPYf, 0x0);
   5488             soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLS_DOUBLE_WIDEm,
   5489                     tnl_entry, DATA_TYPEf, 0x0);
   5490         } else
   5491 #endif
   5492         {
   5493             soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, tnl_entry,
   5494                     ENTRY_TYPEf, 0);
   5495             soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, tnl_entry,
   5496                     ENTRY_TYPE_COPYf, 0);
   5497         }
   5498         bcmi_egr_ip_tnl_mpls_free_indexes_clear(unit, tnl_idx, fi);
   5499     } else {
   5500         bcmi_mpls_egr_tunnel_add_free_indexes(unit, fi, no_of_elements,
   5501              mpls_index);
   5502     }
   5503 
   5504     rv = bcmi_egr_ip_tnl_mpls_table_write(unit, tnl_idx, tnl_entry);
   5505     if (rv < 0) {
   5506         return rv;
   5507     }
   5508 
   5509 #ifdef BCM_WARM_BOOT_SUPPORT
   5510     SOC_CONTROL_LOCK(unit);
   5511     SOC_CONTROL(unit)->scache_dirty = 1;
   5512     SOC_CONTROL_UNLOCK(unit);
   5513 #endif
   5514 
   5515     return BCM_E_NONE;
   5516 }
   5517 
   5518 /*
   5519  * Function:
   5520  *      bcmi_xgs5_mpls_tunnel_initiator_clear_all
   5521  * Purpose:
   5522  *      Clear all MPLS Tunnel Initiators
   5523  * Parameters:
   5524  *      unit - (IN)Device Number
   5525  * Returns:
   5526  *      BCM_E_XXX
   5527  */
   5528 int
   5529 bcmi_xgs5_mpls_tunnel_initiator_clear_all(int unit)
   5530 {
   5531     egr_l3_intf_entry_t if_entry;
   5532     int mpls_index;
   5533     int rv=BCM_E_NONE;
   5534     int num_ip_tnl_mpls;
   5535     int i,j;
   5536     soc_mem_t mem;
   5537 
   5538     for (i = 0; i < L3_INFO(unit)->l3_intf_table_size; i++) {
   5539         if (!BCM_L3_INTF_USED_GET(unit, i)) {
   5540             continue;
   5541         }
   5542 
   5543         rv = READ_EGR_L3_INTFm(unit, MEM_BLOCK_ANY, i, &if_entry);
   5544         if (rv < 0) {
   5545             return rv;
   5546         }
   5547         mpls_index = soc_EGR_L3_INTFm_field32_get(unit, &if_entry,
   5548                                                   MPLS_TUNNEL_INDEXf);
   5549         if (!_BCM_MPLS_TNL_USED_GET(unit, mpls_index)) {
   5550             continue;
   5551         }
   5552         rv = bcmi_xgs5_mpls_tunnel_initiator_clear(unit, i);
   5553         if (rv < 0) {
   5554             return rv;
   5555         }
   5556     }
   5557 
   5558     /* cleanup the s/w state for tunnel table. */
   5559     mem = bcmi_egr_ip_tnl_mem_name_get(unit);
   5560 
   5561     num_ip_tnl_mpls = soc_mem_index_count(unit, mem);
   5562     for (i=0; i<num_ip_tnl_mpls; i++) {
   5563         for (j=0; j<_BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit); j++) {
   5564             bcmi_egr_ip_tnl_mpls_intf_list_delete_all(unit,
   5565                 egr_mpls_tnl_sw_state[unit], i, j);
   5566 
   5567             egr_mpls_tnl_sw_state[unit][i]->label_entry[j]->intf_list = NULL;
   5568             egr_mpls_tnl_sw_state[unit][i]->label_entry[j]->flags = 0;
   5569             egr_mpls_tnl_sw_state[unit][i]->label_entry[j]->num_elements = 0;
   5570 
   5571         }
   5572     }
   5573 
   5574     /* cleanup the free indexes */
   5575     bcmi_egr_ip_tnl_mpls_free_indexes_init(unit, &(fi_db[unit]));
   5576 
   5577     return rv;
   5578 }
   5579 
   5580 
   5581 /*
   5582  * Function:
   5583  *      bcmi_xgs5_mpls_tunnel_initiator_reinit
   5584  * Purpose:
   5585  *      set s/w state of MPLS tunnel during warmboot.
   5586  * Parameters:
   5587  *      unit        - (IN) Device Number
   5588  * Returns:
   5589  *      BCM_E_XXX
   5590  */
   5591 bcm_error_t
   5592 bcmi_xgs5_mpls_tunnel_initiator_reinit(int unit)
   5593 {
   5594     int tnl_idx=0, mpls_off = 0;
   5595     int start_of_entry = 0;
   5596     bcmi_egr_ip_tnl_mpls_tunnel_entry_t **tunnel_entry;
   5597     /* Indexes to iterate over memories, chunks and entries */
   5598     int             chnk_idx, ent_idx, chnk_idx_max, mem_idx_max;
   5599     int             buf_size, chunksize, chnk_end;
   5600     uint32          *tbl_chnk;
   5601     uint32          *el3inf_entry;
   5602     int             rv = BCM_E_NONE;
   5603     soc_mem_t mem;
   5604     int last_push_action = 0;
   5605     int num_labels = 0;
   5606     int push_action = 0;
   5607     int mpls_offset = 0;
   5608     int mpls_index = 0;
   5609     int index_min, index_max;
   5610     uint8 *tunnel_entry_buf = NULL;
   5611 #if defined(BCM_TRIDENT3_SUPPORT)
   5612     egr_ip_tunnel_mpls_double_wide_entry_t *tnl_entry_double = NULL;
   5613     uint32 iptun_mpls_entry_format[3] = {0};
   5614 #endif
   5615     egr_ip_tunnel_mpls_entry_t *tnl_entry = NULL;
   5616 
   5617     if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   5618         mem = EGR_IP_TUNNEL_MPLS_DOUBLE_WIDEm;
   5619     } else {
   5620         mem = EGR_IP_TUNNEL_MPLSm;
   5621     }
   5622 
   5623     tunnel_entry = egr_mpls_tnl_sw_state[unit];
   5624 
   5625     tunnel_entry_buf = soc_cm_salloc(unit,
   5626             SOC_MEM_TABLE_BYTES(unit, mem), "MPLS TUNNEL ENTRY buffer");
   5627     if (NULL == tunnel_entry_buf) {
   5628         return BCM_E_MEMORY;
   5629     }
   5630 
   5631     index_min = soc_mem_index_min(unit, mem);
   5632     index_max = soc_mem_index_max(unit, mem);
   5633     rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY,
   5634             index_min, index_max, tunnel_entry_buf);
   5635     if (SOC_FAILURE(rv)) {
   5636         soc_cm_sfree(unit, tunnel_entry_buf);
   5637         return rv;
   5638     }
   5639 
   5640     for (tnl_idx = index_min; tnl_idx <= index_max; tnl_idx++) {
   5641 
   5642         if (!_BCM_MPLS_IP_TNL_USED_GET(unit, tnl_idx)) {
   5643             continue;
   5644         }
   5645 
   5646         last_push_action = 0;
   5647         start_of_entry = 0;
   5648         num_labels = 0;
   5649 
   5650 #if defined(BCM_TRIDENT3_SUPPORT)
   5651         if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   5652             tnl_entry_double = soc_mem_table_idx_to_pointer
   5653                 (unit, EGR_IP_TUNNEL_MPLS_DOUBLE_WIDEm,
   5654                  egr_ip_tunnel_mpls_double_wide_entry_t *,
   5655                  tunnel_entry_buf, tnl_idx);
   5656         } else
   5657 #endif
   5658         {
   5659             tnl_entry = soc_mem_table_idx_to_pointer
   5660                 (unit, EGR_IP_TUNNEL_MPLSm, egr_ip_tunnel_mpls_entry_t *, tunnel_entry_buf, tnl_idx);
   5661         }
   5662 
   5663         /* Check for valid entry */
   5664 
   5665         for(mpls_off = 0; mpls_off<_BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit); mpls_off++) {
   5666             mpls_index = tnl_idx * _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit) + mpls_off;
   5667 
   5668             if (!_BCM_MPLS_TNL_USED_GET(unit, mpls_index)) {
   5669                 start_of_entry = 0;
   5670                 last_push_action = 0;
   5671                 num_labels = 0;
   5672                 continue;
   5673             }
   5674 
   5675             if (last_push_action == 2) {
   5676                 start_of_entry = 0;
   5677             } else {
   5678                 start_of_entry = 1;
   5679             }
   5680 
   5681             if (start_of_entry) {
   5682                 tunnel_entry[tnl_idx]->label_entry[mpls_off]->flags |=
   5683                     BCMI_EGR_IP_TUNNEL_MPLS_START_OF_ENTRY;
   5684             }
   5685 
   5686 #if defined(BCM_TRIDENT3_SUPPORT)
   5687             if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   5688                 soc_mem_field_get(unit, mem,
   5689                         (uint32 *)tnl_entry_double,
   5690                         _tnl_label_entry_f[mpls_off],
   5691                         iptun_mpls_entry_format);
   5692 
   5693                 bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   5694                         tnl_entry_double, mpls_off,
   5695                         iptun_mpls_entry_format, bcmiMplsPushAction,
   5696                         (uint32 *)&push_action);
   5697             } else
   5698 #endif
   5699             {
   5700                 push_action = soc_mem_field32_get(unit, mem,
   5701                         tnl_entry, _tnl_push_action_f[mpls_off]);
   5702             }
   5703 
   5704             if (push_action == 2) {
   5705                 num_labels++;
   5706             } else {
   5707                 if (last_push_action == 2) {
   5708                     mpls_offset = mpls_off-num_labels;
   5709                 } else {
   5710                     mpls_offset = mpls_off;
   5711                 }
   5712                 num_labels++;
   5713                 tunnel_entry[tnl_idx]->label_entry[mpls_offset]->num_elements =
   5714                    num_labels;
   5715                 start_of_entry = 0;
   5716                 num_labels = 0;
   5717             }
   5718             last_push_action = push_action;
   5719         }
   5720     }
   5721 
   5722     soc_cm_sfree(unit, tunnel_entry_buf);
   5723 
   5724     /* need to look into EGR_L3_INTF table to get interface entry */
   5725     mem = EGR_L3_INTFm;
   5726 
   5727     chunksize = 0x400; /* 1k */
   5728     buf_size = sizeof(egr_l3_intf_entry_t) * chunksize;
   5729     tbl_chnk = soc_cm_salloc(unit, buf_size, "egr_l3_intf traverse");
   5730     if (NULL == tbl_chnk) {
   5731         return BCM_E_MEMORY;
   5732     }
   5733 
   5734     mem_idx_max = soc_mem_index_max(unit, mem);
   5735     for (chnk_idx = soc_mem_index_min(unit, mem);
   5736          chnk_idx <= mem_idx_max;
   5737          chnk_idx += chunksize) {
   5738         sal_memset((void *)tbl_chnk, 0, buf_size);
   5739 
   5740         chnk_idx_max =
   5741             ((chnk_idx + chunksize) <= mem_idx_max) ?
   5742             chnk_idx + chunksize - 1: mem_idx_max;
   5743 
   5744         soc_mem_lock(unit, mem);
   5745         rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY,
   5746                                 chnk_idx, chnk_idx_max, tbl_chnk);
   5747         if (SOC_FAILURE(rv)) {
   5748             soc_mem_unlock(unit, mem);
   5749             break;
   5750         }
   5751         chnk_end = (chnk_idx_max - chnk_idx);
   5752         for (ent_idx = 0 ; ent_idx <= chnk_end; ent_idx ++) {
   5753             el3inf_entry =
   5754                 soc_mem_table_idx_to_pointer(unit, mem, uint32 *,
   5755                                              tbl_chnk, ent_idx);
   5756 
   5757             mpls_index = soc_mem_field32_get(unit, mem, el3inf_entry,
   5758                                             MPLS_TUNNEL_INDEXf);
   5759 
   5760             if (!mpls_index) {
   5761                 continue;
   5762             }
   5763 
   5764             tnl_idx = mpls_index  /
   5765                 _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit);
   5766             mpls_off = mpls_index %
   5767                _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit);
   5768 
   5769             rv = bcmi_egr_ip_tnl_mpls_intf_list_add(unit, tunnel_entry,
   5770                 chnk_idx + ent_idx, tnl_idx, mpls_off);
   5771             if (BCM_FAILURE(rv)) {
   5772                 break;
   5773             }
   5774         }
   5775         soc_mem_unlock(unit, mem);
   5776         if (BCM_FAILURE(rv)) {
   5777             break;
   5778         }
   5779     }
   5780 
   5781     soc_cm_sfree(unit, tbl_chnk);
   5782     return BCM_E_NONE;
   5783 }
   5784 
   5785 /*
   5786  * Function:
   5787  *      bcmi_xgs5_mpls_tunnel_initiator_get
   5788  * Purpose:
   5789  *      Get MPLS Tunnel Initiator info
   5790  * Parameters:
   5791  *      unit        - (IN) Device Number
   5792  *      intf        - (IN) The egress L3 interface
   5793  *      label_max   - (IN) Number of entries in label_array
   5794  *      label_array - (OUT) MPLS header information
   5795  *      label_count - (OUT) Actual number of labels returned
   5796  * Returns:
   5797  *      BCM_E_XXX
   5798  */
   5799 int
   5800 bcmi_xgs5_mpls_tunnel_initiator_get(int unit, bcm_if_t intf, int label_max,
   5801                                  bcm_mpls_egress_label_t *label_array,
   5802                                  int *label_count)
   5803 {
   5804     egr_l3_intf_entry_t if_entry;
   5805     int rv, i, ix, offset;
   5806     int tnl_index = 0, mpls_index = 0;
   5807     bcmi_egr_ip_tnl_mpls_tunnel_entry_t **tunnel_entry = egr_mpls_tnl_sw_state[unit];
   5808     int no_of_elements;
   5809     int mpls_exp_select=0,mpls_tnl_ttl=0;
   5810     uint32 iptun_mpls_entry_format[3];
   5811     uint32 tnl_lbl=0, tnl_exp=0, tnl_exp_ptr=0;
   5812     uint32 tnl_pri=0, tnl_cfi=0;
   5813     uint32 tnl_entry[SOC_MAX_MEM_WORDS];
   5814 
   5815     bcmi_egr_ip_tnl_mpls_table_memset(unit, tnl_entry);
   5816 
   5817     if ((label_array == NULL) ||
   5818         (intf < 0) || (intf >= L3_INFO(unit)->l3_intf_table_size)) {
   5819         return BCM_E_PARAM;
   5820     }
   5821 
   5822     if (!BCM_L3_INTF_USED_GET(unit, intf)) {
   5823         LOG_INFO(BSL_LS_BCM_L3,
   5824                  (BSL_META_U(unit,
   5825                              "L3 interface not created\n")));
   5826         return BCM_E_NOT_FOUND;
   5827     }
   5828 
   5829     /* L3 interface info */
   5830     rv = READ_EGR_L3_INTFm(unit, MEM_BLOCK_ANY, intf, &if_entry);
   5831     if (rv < 0) {
   5832         return rv;
   5833     }
   5834     mpls_index = soc_EGR_L3_INTFm_field32_get(unit, &if_entry,
   5835                                               MPLS_TUNNEL_INDEXf);
   5836     tnl_index = mpls_index / _BCM_MPLS_NUM_MPLS_ENTRIES_PER_INDEX(unit);
   5837 
   5838     if (!_BCM_MPLS_TNL_USED_GET(unit, mpls_index)) {
   5839         return BCM_E_NOT_FOUND;
   5840     }
   5841 
   5842     rv = bcmi_egr_ip_tnl_mpls_table_read(unit, tnl_index, tnl_entry);
   5843 
   5844     if (rv < 0) {
   5845         return rv;
   5846     }
   5847 
   5848 
   5849     rv = bcmi_egr_ip_tnl_mpls_entry_type_check(unit, tnl_entry);
   5850 
   5851     if (rv < 0) {
   5852         return BCM_E_NOT_FOUND;
   5853     }
   5854 
   5855     *label_count = 0;
   5856     sal_memset(label_array, 0, sizeof(bcm_mpls_egress_label_t) * label_max);
   5857     offset = mpls_index & _BCM_MPLS_EGR_L3_INTF_MPLS_INDEX_OFFSET_MASK(unit);
   5858     if (tunnel_entry[tnl_index]->label_entry[offset]->flags
   5859         & BCMI_EGR_IP_TUNNEL_MPLS_START_OF_ENTRY) {
   5860 
   5861         if (tunnel_entry[tnl_index]->label_entry[offset]->flags
   5862             & BCMI_EGR_IP_TUNNEL_MPLS_ENTRY_ZERO) {
   5863             no_of_elements = 0;
   5864         } else {
   5865             no_of_elements =
   5866                 tunnel_entry[tnl_index]->label_entry[offset]->num_elements;
   5867         }
   5868 
   5869     } else {
   5870         return BCM_E_NOT_FOUND;
   5871     }
   5872 
   5873     if (label_max < no_of_elements) {
   5874         *label_count = label_max;
   5875     } else {
   5876         *label_count = no_of_elements;
   5877     }
   5878 
   5879 
   5880     for (i = 0; i < *label_count; i++) {
   5881         bcmi_egress_tnl_label_entry_get(unit, tnl_entry,
   5882                 offset + i,iptun_mpls_entry_format);
   5883 
   5884         bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   5885                 tnl_entry, offset + i,
   5886                 iptun_mpls_entry_format, bcmiSpecialLabelPushType,
   5887                 ((uint32 *)(&(label_array[i].spl_label_push_type))));
   5888 
   5889         bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   5890                 tnl_entry, offset + i,
   5891                 iptun_mpls_entry_format, bcmiMplsLabel,
   5892                 &tnl_lbl);
   5893 
   5894         label_array[i].label = tnl_lbl;
   5895         bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   5896                 tnl_entry, offset + i,
   5897                 iptun_mpls_entry_format, bcmiMplsTtl,
   5898                 (uint32 *)&mpls_tnl_ttl);
   5899 
   5900         bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   5901                 tnl_entry, offset + i,
   5902                 iptun_mpls_entry_format, bcmiMplsExpSelect,
   5903                 (uint32 *)&mpls_exp_select);
   5904 
   5905         if (mpls_exp_select == 0x0) {
   5906             /* Use the specified EXP, PRI and CFI */
   5907             label_array[i].flags |= BCM_MPLS_EGRESS_LABEL_EXP_SET;
   5908             label_array[i].flags |= BCM_MPLS_EGRESS_LABEL_PRI_SET;
   5909 
   5910             bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   5911                     tnl_entry, offset + i,
   5912                     iptun_mpls_entry_format, bcmiMplsExp,
   5913                     &tnl_exp);
   5914 
   5915             label_array[i].exp = tnl_exp;
   5916             bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   5917                     tnl_entry, offset + i,
   5918                     iptun_mpls_entry_format, bcmiNewPri,
   5919                     &tnl_pri);
   5920 
   5921             label_array[i].pkt_pri = tnl_pri;
   5922             bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   5923                     tnl_entry, offset + i,
   5924                     iptun_mpls_entry_format, bcmiNewCfi,
   5925                     &tnl_cfi);
   5926 
   5927             label_array[i].pkt_cfi = tnl_cfi;
   5928 
   5929         } else if (mpls_exp_select == 0x1) {
   5930             /* Use EXP-map for EXP, PRI and CFI */
   5931             label_array[i].flags |= BCM_MPLS_EGRESS_LABEL_EXP_REMARK;
   5932             label_array[i].flags |= BCM_MPLS_EGRESS_LABEL_PRI_REMARK;
   5933 
   5934             bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   5935                     tnl_entry, offset + i,
   5936                     iptun_mpls_entry_format, bcmiMplsExpMappingPtr,
   5937                     &tnl_exp_ptr);
   5938 
   5939             ix = tnl_exp_ptr;
   5940 
   5941             BCM_IF_ERROR_RETURN(
   5942                     _egr_qos_hw_idx2id(unit, ix, &label_array[i].qos_map_id));
   5943         } else {
   5944             /* Use EXP from incoming label. If there is no incoming label,
   5945              * use the specified EXP value.
   5946              */
   5947             label_array[i].flags |= BCM_MPLS_EGRESS_LABEL_EXP_COPY;
   5948             label_array[i].flags |= BCM_MPLS_EGRESS_LABEL_PRI_REMARK;
   5949 
   5950             bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   5951                     tnl_entry, offset + i,
   5952                     iptun_mpls_entry_format, bcmiMplsExp,
   5953                     &tnl_exp);
   5954 
   5955             label_array[i].exp = tnl_exp;
   5956             bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   5957                     tnl_entry, offset + i,
   5958                     iptun_mpls_entry_format, bcmiMplsExpMappingPtr,
   5959                     &tnl_exp_ptr);
   5960 
   5961             ix = tnl_exp_ptr;
   5962             BCM_IF_ERROR_RETURN(
   5963                     _egr_qos_hw_idx2id(unit, ix, &label_array[i].qos_map_id));
   5964         }
   5965 
   5966         if (mpls_tnl_ttl){
   5967             /* Use specified TTL value */
   5968             label_array[i].flags |= BCM_MPLS_EGRESS_LABEL_TTL_SET;
   5969             label_array[i].ttl    = mpls_tnl_ttl;
   5970         } else {
   5971             label_array[i].flags |= BCM_MPLS_EGRESS_LABEL_TTL_DECREMENT;
   5972         }
   5973 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 
   5974         if (soc_feature(unit, soc_feature_mpls_ecn)) {
   5975             int ecn_map_trust;
   5976             int ecn_map_hw_idx;
   5977             int ecn_map_id;
   5978             int rv;
   5979 
   5980             if(soc_feature(unit, soc_feature_td3_style_mpls)) {
   5981                 bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   5982                         tnl_entry, offset + i,
   5983                         iptun_mpls_entry_format, bcmiPktEcnToExpMappingPtr,
   5984                         (uint32 *)&ecn_map_hw_idx);
   5985             } else {
   5986             ecn_map_hw_idx = soc_mem_field32_get(unit, EGR_IP_TUNNEL_MPLSm, 
   5987                                                  &tnl_entry,
   5988                                                  _tnl_ecn_ptr_f[offset + i]);
   5989             }
   5990 
   5991             rv = bcmi_ecn_map_hw_idx2id(unit, ecn_map_hw_idx, 
   5992                                         _BCM_XGS5_MPLS_ECN_MAP_TYPE_ECN2EXP, 
   5993                                         &ecn_map_id);  
   5994             if (BCM_SUCCESS(rv)) {
   5995                 label_array[i].flags |= BCM_MPLS_EGRESS_LABEL_ECN_TO_EXP_MAP;
   5996                 label_array[i].ecn_map_id = ecn_map_id;  
   5997 
   5998                 if(soc_feature(unit, soc_feature_td3_style_mpls)) {
   5999                     bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   6000                             tnl_entry, offset + i,
   6001                             iptun_mpls_entry_format, bcmiPktEcnToExpPriority,
   6002                             (uint32 *)&ecn_map_trust);
   6003                 } else {
   6004                 ecn_map_trust = soc_mem_field32_get(unit, EGR_IP_TUNNEL_MPLSm, 
   6005                                                     &tnl_entry,
   6006                                                     _tnl_ecn_ptr_pri_f[offset + i]);
   6007                 }
   6008                 if (ecn_map_trust) {
   6009                    label_array[i].flags |= BCM_MPLS_EGRESS_LABEL_ECN_EXP_MAP_TRUST; 
   6010                 }
   6011             }
   6012 
   6013             if (!soc_feature(unit, soc_feature_intcn_to_exp_nosupport)) {
   6014             ecn_map_hw_idx = soc_mem_field32_get(unit, EGR_IP_TUNNEL_MPLSm, 
   6015                                                 &tnl_entry,
   6016                                                 _tnl_int_cn_ptr_f[offset + i]);
   6017             rv = bcmi_ecn_map_hw_idx2id(unit, ecn_map_hw_idx, 
   6018                                         _BCM_XGS5_MPLS_ECN_MAP_TYPE_INTCN2EXP, 
   6019                                         &ecn_map_id);  
   6020             if (BCM_SUCCESS(rv)) {
   6021                 label_array[i].flags |= BCM_MPLS_EGRESS_LABEL_INT_CN_TO_EXP_MAP;
   6022                 label_array[i].int_cn_map_id = ecn_map_id;  
   6023                 ecn_map_trust = soc_mem_field32_get(unit, EGR_IP_TUNNEL_MPLSm, 
   6024                                                     &tnl_entry,
   6025                                                     _tnl_int_cn_ptr_pri_f[offset + i]);
   6026                 if (ecn_map_trust) {
   6027                    label_array[i].flags |= BCM_MPLS_EGRESS_LABEL_ECN_EXP_MAP_TRUST; 
   6028                 }
   6029             }            
   6030         }
   6031         }
   6032 #endif
   6033     }
   6034 
   6035     return BCM_E_NONE;
   6036 }
   6037 /*
   6038  * Function:
   6039  *      bcmi_xgs5_mpls_failover_nw_port_match_get
   6040  * Purpose:
   6041  *      Get match criteria of an MPLS port
   6042  * Parameters:
   6043  *      unit    - (IN) Device Number
   6044  *      mpls_port - (IN) mpls port information
   6045  *      vp  - (IN) Source Virtual Port
   6046  *      return_ment - (OUT) matched entry
   6047  * Returns:
   6048  *      BCM_E_XXX
   6049  */
   6050 int
   6051 bcmi_xgs5_mpls_failover_nw_port_match_get(int unit, bcm_mpls_port_t *mpls_port,
   6052                                     int vp, mpls_entry_entry_t *return_ment)
   6053 {
   6054     _bcm_tr_mpls_bookkeeping_t *mpls_info = MPLS_INFO(unit);
   6055     mpls_entry_entry_t ment;
   6056     int entry_index = -1;
   6057     int key_type = 0x00; /* mpls_key_type */
   6058     int rv = BCM_E_NONE;
   6059     bcm_module_t mod_out;
   6060     bcm_port_t port_out;
   6061     bcm_trunk_t trunk_id;
   6062     bcm_gport_t gport_id;
   6063     soc_mem_t mem = MPLS_ENTRYm;
   6064     soc_field_t validf = VALIDf;
   6065 
   6066     if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
   6067         mem = MPLS_ENTRY_SINGLEm;
   6068         validf = BASE_VALIDf;
   6069     }
   6070 
   6071     /* return not found if both inputs are invalid. */
   6072     if ((mpls_port == NULL) && (vp == -1)) {
   6073         return BCM_E_NOT_FOUND;
   6074     }
   6075 
   6076     sal_memset(&ment, 0, sizeof(mpls_entry_entry_t));
   6077     if (mpls_port != NULL) {
   6078         if (mpls_port->criteria == BCM_MPLS_PORT_MATCH_LABEL_PORT) {
   6079             /* Check for Port_independent Label mapping */
   6080             rv = bcm_tr_mpls_port_independent_range (unit, mpls_port->match_label, mpls_port->port);
   6081             if (rv < 0) {
   6082                 return rv;
   6083             }
   6084 
   6085             rv = _bcm_esw_gport_resolve(unit, mpls_port->port, &mod_out,
   6086                                 &port_out, &trunk_id, &gport_id);
   6087              BCM_IF_ERROR_RETURN(rv);
   6088 
   6089             if (BCM_GPORT_IS_TRUNK(mpls_port->port)) {
   6090                 soc_mem_field32_set(unit, mem, &ment, MPLS__Tf, 1);
   6091                 soc_mem_field32_set(unit, mem, &ment, MPLS__TGIDf, mpls_port->port);
   6092             } else {
   6093                 if (SOC_MEM_FIELD_VALID(unit, mem, MPLS__MODULE_IDf)) {
   6094                     soc_mem_field32_set(unit, mem, &ment, MPLS__MODULE_IDf, mod_out);
   6095                 }
   6096                 soc_mem_field32_set(unit, mem, &ment, MPLS__PORT_NUMf, port_out);
   6097             }
   6098         } else if (mpls_port->criteria == BCM_MPLS_PORT_MATCH_LABEL) {
   6099             if (SOC_MEM_FIELD_VALID(unit, mem, MPLS__MODULE_IDf)) {
   6100                 soc_mem_field32_set(unit, mem, &ment, MPLS__MODULE_IDf, 0);
   6101             }
   6102             soc_mem_field32_set(unit, mem, &ment, MPLS__PORT_NUMf, 0);
   6103         } else {
   6104             return BCM_E_NOT_FOUND;
   6105         }
   6106 
   6107         /* Use old label to get old mpls entry for replace operation */
   6108         soc_mem_field32_set(unit, mem, &ment, MPLS__MPLS_LABELf,
   6109                                     mpls_port->match_label);
   6110 
   6111         if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   6112             soc_mem_field32_set(unit, mem, &ment, BASE_VALID_0f, 3);
   6113             soc_mem_field32_set(unit, mem, &ment, BASE_VALID_1f, 7);
   6114         } else {
   6115             soc_mem_field32_set(unit, mem, &ment, validf, 1);
   6116         }
   6117 
   6118         soc_mem_field32_set(unit, mem, &ment, KEY_TYPEf, key_type);
   6119     } else {
   6120 
   6121         if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeMpls)) {
   6122             return BCM_E_NOT_FOUND;
   6123         }
   6124 
   6125         if ((mpls_info->match_key[vp].flags &
   6126                 _BCM_MPLS_PORT_MATCH_TYPE_LABEL) ||
   6127                (mpls_info->match_key[vp].flags ==
   6128                 _BCM_MPLS_PORT_MATCH_TYPE_LABEL_PORT)) {
   6129 
   6130         if (mpls_info->match_key[vp].flags &
   6131                     _BCM_MPLS_PORT_MATCH_TYPE_LABEL_PORT) {
   6132 
   6133             if (mpls_info->match_key[vp].trunk_id != -1) {
   6134                 soc_mem_field32_set(unit, mem, &ment, MPLS__Tf, 1);
   6135                 soc_mem_field32_set(unit, mem, &ment, MPLS__TGIDf,
   6136                     mpls_info->match_key[vp].trunk_id);
   6137             } else {
   6138                 if (SOC_MEM_FIELD_VALID(unit, mem, MPLS__MODULE_IDf)) {
   6139                     soc_mem_field32_set(unit, mem, &ment, MPLS__MODULE_IDf,
   6140                         mpls_info->match_key[vp].modid);
   6141                 }
   6142                 soc_mem_field32_set(unit, mem, &ment, MPLS__PORT_NUMf,
   6143                     mpls_info->match_key[vp].port);
   6144             }
   6145         }
   6146 
   6147         soc_mem_field32_set(unit, mem, &ment, MPLS__MPLS_LABELf,
   6148             mpls_info->match_key[vp].match_label);
   6149         soc_mem_field32_set(unit, mem, &ment, KEY_TYPEf, key_type);
   6150 
   6151         } else {
   6152             return BCM_E_NOT_FOUND;
   6153         }
   6154     }
   6155 
   6156     rv = soc_mem_search(unit, mem, MEM_BLOCK_ANY, &entry_index,
   6157              &ment, return_ment, 0);
   6158 
   6159     return rv;
   6160 }
   6161 
   6162 STATIC int
   6163 _bcmi_mpls_entry_field_val_set(int unit, void *tnl_buf, soc_field_t field,
   6164         uint32 *p_fn_data, uint32 *set_val,
   6165         uint32 offset, uint32 width)
   6166 {
   6167   int rv = BCM_E_NONE;
   6168 
   6169 #if defined(BCM_TRIDENT3_SUPPORT)
   6170   if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   6171       uint32 u32_mask;
   6172       int idx, wp, bp, len;
   6173 
   6174       if (NULL == p_fn_data || NULL == set_val) {
   6175           LOG_VERBOSE(BSL_LS_BCM_MPLS, (BSL_META("Invalid Parameters\n")));
   6176           return BCM_E_PARAM;
   6177       }
   6178 
   6179       wp = offset / 32;
   6180       bp = offset & (32 - 1);
   6181       idx = 0;
   6182 
   6183       for (len = width; len > 0; len -= 32) {
   6184           if (bp) {
   6185               if (len < 32) {
   6186                   u32_mask = (1 << len) - 1;
   6187                   if ((set_val[idx] & ~u32_mask) != 0) {
   6188                       return (BCM_E_PARAM);
   6189                   }
   6190               } else {
   6191                   u32_mask = 0xffffffff;
   6192               }
   6193 
   6194               p_fn_data[wp] &= ~(u32_mask << bp);
   6195               p_fn_data[wp++] |= set_val[idx] << bp;
   6196               p_fn_data[wp] &= ~(u32_mask >> (32 - bp));
   6197               p_fn_data[wp] |= set_val[idx] >> (32 - bp) & ((1 << bp) - 1);
   6198 
   6199           } else {
   6200               if (len < 32) {
   6201                   u32_mask = (1 << len) - 1;
   6202                   if ((set_val[idx] & ~u32_mask) != 0) {
   6203                       return (BCM_E_PARAM);
   6204                   }
   6205                   p_fn_data[wp] &= ~u32_mask;
   6206                   p_fn_data[wp++] |= set_val[idx];
   6207               } else {
   6208                   p_fn_data[wp++] = set_val[idx];
   6209               }
   6210           }
   6211 
   6212           idx++;
   6213       }
   6214   } else
   6215 #endif
   6216   {
   6217       soc_mem_field32_set(unit, EGR_IP_TUNNEL_MPLSm, tnl_buf,
   6218               field, *set_val);
   6219   }
   6220 
   6221   return rv;
   6222 }
   6223 
   6224 STATIC int
   6225 _bcmi_mpls_entry_field_val_get(int unit, void *tnl_buf, soc_field_t field,
   6226         uint32 *p_fn_data, uint32 *p_data,
   6227         uint32 offset, uint32 width)
   6228 {
   6229 
   6230   int rv = BCM_E_NONE;
   6231 
   6232 #if defined(BCM_TRIDENT3_SUPPORT)
   6233   if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   6234       int                 idx, wp, bp, len;
   6235 
   6236       /* Input parameters check. */
   6237       if (NULL == p_fn_data || NULL == p_data) {
   6238           LOG_VERBOSE(BSL_LS_BCM_MPLS, (BSL_META("Invalid Parameters\n")));
   6239           return (BCM_E_PARAM);
   6240       }
   6241 
   6242       wp = offset / 32;
   6243       bp = offset & (32 - 1);
   6244       idx = 0;
   6245 
   6246       for (len = width; len > 0; len -= 32) {
   6247           if (bp) {
   6248               p_data[idx] = (p_fn_data[wp++] >> bp) & ((1 << (32 - bp)) - 1);
   6249               p_data[idx] |= p_fn_data[wp] << (32 - bp);
   6250           } else {
   6251               p_data[idx] = p_fn_data[wp++];
   6252           }
   6253 
   6254           if (len < 32) {
   6255               p_data[idx] &= ((1 << len) - 1);
   6256           }
   6257 
   6258           idx++;
   6259       }
   6260   } else
   6261 #endif
   6262   {
   6263       soc_mem_t mem;
   6264       uint32 value;
   6265       mem = bcmi_egr_ip_tnl_mem_name_get(unit);
   6266       value = soc_mem_field32_get(unit, mem, tnl_buf, field);
   6267       *p_data = value;
   6268   }
   6269   return rv;
   6270 }
   6271 
   6272 
   6273 /*
   6274  * Function:
   6275  *     bcmi_egr_ip_tnl_mpls_entry_format_set 
   6276  * Purpose:
   6277  *      Set egress ip tunnel mpls entry format fields
   6278  * Parameters:
   6279  *      unit       - (IN)  Device Number
   6280  *      field_type - (IN)  Field type
   6281  *      tnl_buf    - (IN)  tnl entry buffer
   6282  *      lbl_offset - (OUT) offset
   6283  *      rebuf      - (OUT) return buffer
   6284  *      value      - (IN)  value
   6285  * Returns:
   6286  *      BCM_E_XXX
   6287  */
   6288 int
   6289 bcmi_egr_ip_tnl_mpls_entry_format_set(int unit,int field_type,
   6290         void *tnl_buf, int lbl_offset,
   6291         uint32 *retbuf, int value)
   6292 {
   6293     int rv = BCM_E_NONE;
   6294     uint32 set_val = 0;
   6295     set_val = value;
   6296 
   6297     /*use tnl_buf,lbl_offset is non TD3 chips,
   6298      *retbuf,offset,width is dont care.
   6299      *use retbuf in TD3 tnl_buf,lbl_offset is dontcare.
   6300      *Yet to set few fields in non TD3 chips*/
   6301     switch (field_type) {
   6302         case bcmiMplsLabel:
   6303 
   6304             rv = bcmi_validate_field_range(unit, set_val, 20);
   6305             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6306                     _tnl_label_f[lbl_offset], retbuf, &set_val, 0, 20);
   6307             break;
   6308         case bcmiMplsPushAction:
   6309 
   6310             rv = bcmi_validate_field_range(unit, set_val, 2);
   6311             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6312                     _tnl_push_action_f[lbl_offset], retbuf, &set_val, 20, 2);
   6313             break;
   6314         case bcmiMplsExpSelect:
   6315 
   6316             rv = bcmi_validate_field_range(unit, set_val, 2);
   6317             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6318                     _tnl_exp_select_f[lbl_offset], retbuf, &set_val, 22, 2);
   6319             break;
   6320         case bcmiMplsExpMappingPtr:
   6321 
   6322             rv = bcmi_validate_field_range(unit, set_val, 4);
   6323             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6324                     _tnl_exp_ptr_f[lbl_offset], retbuf, &set_val, 24, 4);
   6325             break;
   6326         case bcmiNewCfi:
   6327 
   6328             rv = bcmi_validate_field_range(unit, set_val, 1);
   6329             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6330                     _tnl_cfi_f[lbl_offset], retbuf, &set_val, 24, 1);
   6331             break;
   6332         case bcmiNewPri:
   6333 
   6334             rv = bcmi_validate_field_range(unit, set_val, 3);
   6335             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6336                     _tnl_pri_f[lbl_offset], retbuf, &set_val, 25, 3);
   6337             break;
   6338         case bcmiMplsExp:
   6339 
   6340             rv = bcmi_validate_field_range(unit, set_val, 3);
   6341             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6342                     _tnl_exp_f[lbl_offset], retbuf, &set_val, 28, 3);
   6343             break;
   6344         case bcmiLabelSelect:
   6345 
   6346             rv = bcmi_validate_field_range(unit, set_val, 1);
   6347             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6348                     _tnl_label_f[lbl_offset], retbuf, &set_val, 31, 1);
   6349             break;
   6350         case bcmiMplsTtl:
   6351 
   6352             rv = bcmi_validate_field_range(unit, set_val, 8);
   6353             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6354                     _tnl_ttl_f[lbl_offset], retbuf, &set_val, 32, 8);
   6355             break;
   6356         case bcmiSpecialLabelPushType:
   6357 
   6358             rv = bcmi_validate_field_range(unit, set_val, 2);
   6359             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6360                     _tnl_label_f[lbl_offset], retbuf, &set_val, 40, 2);
   6361             break;
   6362         case bcmiExpMappingTableSelect:
   6363 
   6364             rv = bcmi_validate_field_range(unit, set_val, 2);
   6365             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6366                     _tnl_label_f[lbl_offset], retbuf, &set_val, 42, 2);
   6367             break;
   6368         case bcmiPktEcnToExpMappingPtr:
   6369 
   6370             rv = bcmi_validate_field_range(unit, set_val, 2);
   6371             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6372                     _tnl_label_f[lbl_offset], retbuf, &set_val, 44, 2);
   6373             break;
   6374         case bcmiPktEcnToExpPriority:
   6375 
   6376             rv = bcmi_validate_field_range(unit, set_val, 1);
   6377             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6378                     _tnl_label_f[lbl_offset], retbuf, &set_val, 46, 1);
   6379             break;
   6380         case bcmiEgrFlexCtrActionSet:
   6381 
   6382             rv = bcmi_validate_field_range(unit, set_val, 19);
   6383             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6384                     _tnl_label_f[lbl_offset], retbuf, &set_val, 47, 19);
   6385             break;
   6386         case bcmiFlexCtrBaseCounterIdx:
   6387 
   6388             rv = bcmi_validate_field_range(unit, set_val, 13);
   6389             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6390                     _tnl_label_f[lbl_offset], retbuf, &set_val, 47, 13);
   6391             break;
   6392         case bcmiFlexCtrPoolNumber:
   6393 
   6394             rv = bcmi_validate_field_range(unit, set_val, 2);
   6395             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6396                     _tnl_label_f[lbl_offset], retbuf, &set_val, 61, 2);
   6397             break;
   6398         case bcmiRsvdFlexCtrPoolNumber:
   6399 
   6400             rv = bcmi_validate_field_range(unit, set_val, 2);
   6401             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6402                     _tnl_label_f[lbl_offset], retbuf, &set_val, 63, 1);
   6403             break;
   6404         case bcmiFlexCtrOffsetMode:
   6405 
   6406             rv = bcmi_validate_field_range(unit, set_val, 5);
   6407             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6408                     _tnl_label_f[lbl_offset], retbuf, &set_val, 64, 2);
   6409             break;
   6410         case bcmiEcnMappingEnable:
   6411 
   6412             rv = bcmi_validate_field_range(unit, set_val, 1);
   6413             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6414                     _tnl_label_f[lbl_offset], retbuf, &set_val, 66, 1);
   6415             break;
   6416         case bcmiEcnMappingTableSelect:
   6417 
   6418             rv = bcmi_validate_field_range(unit, set_val, 2);
   6419             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6420                     _tnl_label_f[lbl_offset], retbuf, &set_val, 67, 2);
   6421             break;
   6422         case bcmiMplsEntryFormatReserved:
   6423 
   6424             rv = bcmi_validate_field_range(unit, set_val, 2);
   6425             _bcmi_mpls_entry_field_val_set(unit, tnl_buf,
   6426                     _tnl_label_f[lbl_offset], retbuf, &set_val, 69, 2);
   6427             break;
   6428         default:
   6429             rv =  BCM_E_PARAM;
   6430             break;
   6431     }
   6432 
   6433     return rv;
   6434 }
   6435 
   6436 /*
   6437  * Function:
   6438  *     bcmi_egr_ip_tnl_mpls_entry_format_get
   6439  * Purpose:
   6440  *      get egress ip tunnel mpls entry format field value
   6441  * Parameters:
   6442  *      unit       - (IN)   Device Number
   6443  *      tnl_buf    - (IN)   tnl entry buffer
   6444  *      lbl_offset - (IN)   offset
   6445  *      inbuf      - (IN)   input buffer
   6446  *      field_type - (IN)   field type
   6447  *      value      - (OUT)  return value
   6448  * Returns:
   6449  *      BCM_E_XXX
   6450  */
   6451 int
   6452 bcmi_egr_ip_tnl_mpls_entry_format_get(int unit, void *tnl_buf, int lbl_offset,
   6453         uint32 *inbuf, int field_type, uint32 *retval)
   6454 {
   6455     int rv = BCM_E_NONE;
   6456 
   6457     switch (field_type) {
   6458         case bcmiMplsLabel:
   6459             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6460                     _tnl_label_f[lbl_offset], inbuf, retval, 0, 20);
   6461             break;
   6462         case bcmiMplsPushAction:
   6463             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6464                     _tnl_push_action_f[lbl_offset], inbuf, retval, 20, 2);
   6465             break;
   6466         case bcmiMplsExpSelect:
   6467             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6468                     _tnl_exp_select_f[lbl_offset], inbuf, retval, 22, 2);
   6469             break;
   6470         case bcmiMplsExpMappingPtr:
   6471             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6472                     _tnl_exp_ptr_f[lbl_offset], inbuf, retval, 24, 4);
   6473             break;
   6474         case bcmiNewCfi:
   6475             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6476                     _tnl_cfi_f[lbl_offset], inbuf, retval, 24, 1);
   6477             break;
   6478         case bcmiNewPri:
   6479             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6480                     _tnl_pri_f[lbl_offset], inbuf, retval, 25, 3);
   6481             break;
   6482         case bcmiMplsExp:
   6483             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6484                     _tnl_exp_f[lbl_offset], inbuf, retval, 28, 3);
   6485             break;
   6486         case bcmiLabelSelect:
   6487             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6488                     _tnl_label_f[lbl_offset], inbuf, retval, 31, 1);
   6489             break;
   6490         case bcmiMplsTtl:
   6491             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6492                     _tnl_ttl_f[lbl_offset], inbuf, retval, 32, 8);
   6493             break;
   6494         case bcmiSpecialLabelPushType:
   6495             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6496                     _tnl_label_f[lbl_offset], inbuf, retval, 40, 2);
   6497             break;
   6498         case bcmiExpMappingTableSelect:
   6499             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6500                     _tnl_label_f[lbl_offset], inbuf, retval, 42, 2);
   6501             break;
   6502         case bcmiPktEcnToExpMappingPtr:
   6503             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6504                     _tnl_label_f[lbl_offset], inbuf, retval, 44, 2);
   6505             break;
   6506         case bcmiPktEcnToExpPriority:
   6507             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6508                     _tnl_label_f[lbl_offset], inbuf, retval, 46, 1);
   6509             break;
   6510         case bcmiEgrFlexCtrActionSet:
   6511             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6512                 _tnl_label_f[lbl_offset], inbuf, retval, 47, 19);
   6513             break;
   6514         case bcmiFlexCtrBaseCounterIdx:
   6515             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6516                     _tnl_label_f[lbl_offset], inbuf, retval, 47, 13);
   6517             break;
   6518         case bcmiFlexCtrPoolNumber:
   6519             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6520                     _tnl_label_f[lbl_offset], inbuf, retval, 61, 2);
   6521             break;
   6522         case bcmiRsvdFlexCtrPoolNumber:
   6523             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6524                     _tnl_label_f[lbl_offset], inbuf, retval, 63, 1);
   6525             break;
   6526         case bcmiFlexCtrOffsetMode:
   6527             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6528                     _tnl_label_f[lbl_offset], inbuf, retval, 64, 2);
   6529             break;
   6530         case bcmiEcnMappingEnable:
   6531             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6532                     _tnl_label_f[lbl_offset], inbuf, retval, 66, 1);
   6533             break;
   6534         case bcmiEcnMappingTableSelect:
   6535             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6536                     _tnl_label_f[lbl_offset], inbuf, retval, 67, 2);
   6537             break;
   6538         case bcmiMplsEntryFormatReserved:
   6539             _bcmi_mpls_entry_field_val_get(unit, tnl_buf,
   6540                     _tnl_label_f[lbl_offset], inbuf, retval, 69, 2);
   6541             break;
   6542         default:
   6543             rv =  BCM_E_PARAM;
   6544             break;
   6545     }
   6546 
   6547     return rv;
   6548 }
   6549 
   6550 void
   6551 bcm_td3_ip_tnl_mpls_label_info_get(int unit, void *tnl_entry, int field_type,
   6552         int offset, int *retval)
   6553 {
   6554     uint32 iptun_mpls_entry_format[3] = {0};
   6555 
   6556     if (soc_feature(unit, soc_feature_td3_style_mpls)) {
   6557         bcmi_egress_tnl_label_entry_get(unit, tnl_entry,
   6558                 offset, iptun_mpls_entry_format);
   6559 
   6560 
   6561         bcmi_egr_ip_tnl_mpls_entry_format_get(unit,
   6562                 tnl_entry, offset,
   6563                 iptun_mpls_entry_format, field_type,
   6564                 (uint32 *)retval);
   6565     }
   6566 }
   6567 
   6568 #endif /* (BCM_TOMAHAWK_SUPPORT) || defined(BCM_TRIDENT2PLUS_SUPPORT) */
   6569 #endif /* BCM_MPLS_SUPPORT */
   6570 #endif /* INCLUDE_L3 */
   6571