openbcm

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

l3.c (72274B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:        l3.c
      8  * Purpose:     Triumph2 L3 function implementations
      9  */
     10 
     11 
     12 #include <soc/defs.h>
     13 
     14 #include <assert.h>
     15 #include <shared/bsl.h>
     16 #include <sal/core/libc.h>
     17 #if defined(BCM_TRIUMPH2_SUPPORT)  && defined(INCLUDE_L3)
     18 
     19 #include <shared/util.h>
     20 #include <soc/mem.h>
     21 #include <soc/cm.h>
     22 #include <soc/drv.h>
     23 #include <soc/register.h>
     24 #include <soc/memory.h>
     25 #include <soc/l3x.h>
     26 #include <soc/lpm.h>
     27 #include <soc/tnl_term.h>
     28 #include <soc/defragment.h>
     29 
     30 #include <bcm/l3.h>
     31 #include <bcm/tunnel.h>
     32 #include <bcm/debug.h>
     33 #include <bcm/error.h>
     34 #include <bcm/stack.h>
     35 
     36 #include <bcm_int/esw/mbcm.h>
     37 #include <bcm_int/esw/firebolt.h>
     38 #include <bcm_int/esw/trx.h>
     39 #include <bcm_int/esw/triumph2.h>
     40 #include <bcm_int/esw/l3.h>
     41 #include <bcm_int/esw/xgs3.h>
     42 #include <bcm_int/esw/stack.h>
     43 #include <bcm_int/esw_dispatch.h>
     44 #if defined(BCM_TRIDENT2_SUPPORT)
     45 #include <bcm_int/esw/trident2.h>
     46 #endif /* BCM_TRIDENT2_SUPPORT*/
     47 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
     48 #include <bcm_int/esw/trident2plus.h>
     49 #endif /* BCM_TRIDENT2_SUPPORT*/
     50 #if defined(BCM_TOMAHAWK_SUPPORT)
     51 #include <bcm_int/esw/tomahawk.h>
     52 #endif /* BCM_TOMAHAWK_SUPPORT */
     53 #if defined(BCM_TRIDENT3_SUPPORT)
     54 #include <bcm_int/esw/trident3.h>
     55 #endif /* BCM_TRIDENT3_SUPPORT */
     56 #include <bcm_int/esw/ecn.h>
     57 
     58 #define ECN_INFO(_unit_)   (&_bcm_xgs5_ecn_bk_info[_unit_])
     59 
     60 /* L3 ECMP table defragmentation buffer info */
     61 typedef struct _bcm_tr2_l3_ecmp_defragment_buffer_s {
     62     int base_ptr; /* Starting index of the buffer used
     63                      in ECMP table defragmentation */
     64     int size;     /* Size of the buffer */
     65 } _bcm_tr2_l3_ecmp_defragment_buffer_t;
     66 
     67 extern int ecmp_mode_hierarchical;
     68 extern int ecmp_mode_single;
     69 
     70 STATIC _bcm_tr2_l3_ecmp_defragment_buffer_t
     71        *_bcm_tr2_l3_ecmp_defragment_buffer_info[BCM_MAX_NUM_UNITS];
     72 
     73 /*
     74  * Function:
     75  *      _bcm_tr2_l3_tnl_term_add
     76  * Purpose:
     77  *      Add tunnel termination entry to the hw.
     78  * Parameters:
     79  *      unit     - (IN)SOC unit number.
     80  *      tnl_info - (IN)Tunnel terminator parameters. 
     81  * Returns:
     82  *      BCM_E_XXX
     83  */
     84 int
     85 _bcm_tr2_l3_tnl_term_add(int unit, uint32 *entry_ptr, bcm_tunnel_terminator_t *tnl_info)
     86 {
     87     bcm_module_t mod_in, mod_out, my_mod;
     88     bcm_port_t port_in, port_out;
     89     _bcm_l3_ingress_intf_t iif;
     90     int tunnel, wlan;
     91     int rv;
     92 
     93     /* Program remote port */
     94     if ((tnl_info->type == bcmTunnelTypeWlanWtpToAc) || 
     95         (tnl_info->type == bcmTunnelTypeWlanAcToAc) ||
     96         (tnl_info->type == bcmTunnelTypeWlanWtpToAc6) ||
     97         (tnl_info->type == bcmTunnelTypeWlanAcToAc6)) {
     98         wlan = 1;
     99     } else {
    100         wlan = 0;
    101     }
    102 
    103     if (wlan) {
    104         if (tnl_info->flags & BCM_TUNNEL_TERM_WLAN_REMOTE_TERMINATE) {
    105             if (!BCM_GPORT_IS_MODPORT(tnl_info->remote_port)) {
    106                 return BCM_E_PARAM;
    107             }
    108             mod_in = BCM_GPORT_MODPORT_MODID_GET(tnl_info->remote_port);
    109             port_in = BCM_GPORT_MODPORT_PORT_GET(tnl_info->remote_port); 
    110             BCM_IF_ERROR_RETURN
    111                 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, mod_in, 
    112                                         port_in, &mod_out, &port_out));
    113             if (!SOC_MODID_ADDRESSABLE(unit, mod_out)) {
    114                 return (BCM_E_BADID);
    115             }
    116             if (!SOC_PORT_ADDRESSABLE(unit, port_out)) {
    117                 return (BCM_E_PORT);
    118             }
    119             soc_L3_TUNNELm_field32_set(unit, entry_ptr, REMOTE_TERM_GPPf,
    120                                        (mod_out << 6) | port_out);
    121         } else {
    122             /* Send to the local loopback port */
    123             rv = bcm_esw_stk_my_modid_get(unit, &my_mod);
    124             BCM_IF_ERROR_RETURN(rv);
    125             port_in = 54;
    126             mod_in = my_mod;
    127             rv = _bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, mod_in, 
    128                                         port_in, &mod_out, &port_out);
    129             BCM_IF_ERROR_RETURN(rv);
    130 
    131             soc_L3_TUNNELm_field32_set(unit, entry_ptr, REMOTE_TERM_GPPf,
    132                                        (mod_out << 6) | port_out);
    133         }
    134         /* Program tunnel id */
    135         if (tnl_info->flags & BCM_TUNNEL_TERM_TUNNEL_WITH_ID) {
    136             if (!BCM_GPORT_IS_TUNNEL(tnl_info->tunnel_id)) {
    137                 return BCM_E_PARAM;
    138             }
    139             if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, TUNNEL_IDf)) {
    140                 tunnel = BCM_GPORT_TUNNEL_ID_GET(tnl_info->tunnel_id);
    141                 soc_L3_TUNNELm_field32_set(unit, entry_ptr, TUNNEL_IDf,
    142                                            tunnel);
    143             }
    144         }
    145 
    146     }
    147     if ((tnl_info->type == bcmTunnelTypeAutoMulticast) ||
    148         (tnl_info->type == bcmTunnelTypeAutoMulticast6)) {
    149         /* Program L3_IIFm */
    150         if(SOC_MEM_FIELD_VALID(unit, L3_IIFm, IPMC_L3_IIFf)) {
    151             sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t));
    152             iif.intf_id = tnl_info->vlan;
    153 
    154             rv = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif);
    155             BCM_IF_ERROR_RETURN(rv);
    156             iif.vrf = tnl_info->vrf;
    157 #if defined(BCM_TRIDENT2_SUPPORT)
    158             if (soc_feature(unit, soc_feature_l3_iif_profile)) {
    159                 iif.profile_flags |= _BCM_L3_IIF_PROFILE_DO_NOT_UPDATE;
    160             }
    161 #endif /* BCM_TRIDENT2_SUPPORT */
    162             rv = _bcm_tr_l3_ingress_interface_set(unit, &iif,NULL, NULL);
    163             BCM_IF_ERROR_RETURN(rv);
    164         }
    165 
    166         /* Program tunnel id */
    167         if (tnl_info->flags & BCM_TUNNEL_TERM_TUNNEL_WITH_ID) {
    168             if (!BCM_GPORT_IS_TUNNEL(tnl_info->tunnel_id)) {
    169                 return BCM_E_PARAM;
    170             }
    171             if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, TUNNEL_IDf)) {
    172                 tunnel = BCM_GPORT_TUNNEL_ID_GET(tnl_info->tunnel_id);
    173                 soc_L3_TUNNELm_field32_set(unit, entry_ptr, TUNNEL_IDf,
    174                                            tunnel);
    175             }
    176         }
    177     }
    178     return (BCM_E_NONE);
    179 }
    180 
    181 /*
    182  * Function:
    183  *      _bcm_tr2_l3_tnl_term_entry_init
    184  * Purpose:
    185  *      Initialize soc tunnel terminator entry key portion.
    186  * Parameters:
    187  *      unit     - (IN)  BCM device number. 
    188  *      tnl_info - (IN)  BCM buffer with tunnel info.
    189  *      entry    - (OUT) SOC buffer with key filled in.  
    190  * Returns:
    191  *      BCM_E_XXX
    192  */
    193 int
    194 _bcm_tr2_l3_tnl_term_entry_init(int unit, bcm_tunnel_terminator_t *tnl_info,
    195                                 soc_tunnel_term_t *entry)
    196 {
    197     int       idx;                /* Entry iteration index.     */
    198     int       idx_max;            /* Entry widht.               */
    199     uint32    *entry_ptr;         /* Filled entry pointer.      */
    200     _bcm_tnl_term_type_t tnl_type;/* Tunnel type.               */
    201     int       rv;                 /* Operation return status.   */
    202     int valid_bit = 0;
    203     soc_mem_t mem = L3_TUNNELm;
    204 
    205     /* Input parameters check. */
    206     if ((NULL == tnl_info) || (NULL == entry)) {
    207         return (BCM_E_PARAM);
    208     }
    209 
    210     if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
    211         mem = L3_TUNNEL_DOUBLEm;
    212     }
    213 
    214     /* Get tunnel type & sub_type. */
    215     BCM_IF_ERROR_RETURN
    216         (_bcm_xgs3_l3_set_tnl_term_type(unit, tnl_info, &tnl_type));
    217 
    218     /* Reset destination structure. */
    219     sal_memset(entry, 0, sizeof(soc_tunnel_term_t));
    220 
    221     /* Set Destination/Source pair. */
    222     entry_ptr = (uint32 *)&entry->entry_arr[0];
    223     if (tnl_type.tnl_outer_hdr_ipv6 == 1) {
    224         /* Apply mask on source address. */
    225         rv = bcm_xgs3_l3_mask6_apply(tnl_info->sip6_mask, tnl_info->sip6);
    226         BCM_IF_ERROR_RETURN(rv);
    227 
    228         /* SIP [0-63] */
    229         soc_mem_ip6_addr_set(unit, mem,
    230                              (uint32 *)&entry->entry_arr[0], IP_ADDRf,
    231                              tnl_info->sip6, SOC_MEM_IP6_LOWER_ONLY);
    232         /* SIP [64-127] */
    233         soc_mem_ip6_addr_set(unit, mem,
    234                              (uint32 *)&entry->entry_arr[1], IP_ADDRf,
    235                              tnl_info->sip6, SOC_MEM_IP6_UPPER_ONLY);
    236         /* DIP [0-63] */
    237         soc_mem_ip6_addr_set(unit, mem,
    238                              (uint32 *)&entry->entry_arr[2], IP_ADDRf,
    239                              tnl_info->dip6, SOC_MEM_IP6_LOWER_ONLY);
    240         /* DIP [64-127] */
    241         soc_mem_ip6_addr_set(unit, mem,
    242                              (uint32 *)&entry->entry_arr[3], IP_ADDRf,
    243                              tnl_info->dip6, SOC_MEM_IP6_UPPER_ONLY);
    244 
    245         /* SIP MASK [0-63] */
    246         soc_mem_ip6_addr_set(unit, mem,
    247                              (uint32 *)&entry->entry_arr[0], IP_ADDR_MASKf,
    248                              tnl_info->sip6_mask, SOC_MEM_IP6_LOWER_ONLY);
    249         /* SIP MASK [64-127] */
    250         soc_mem_ip6_addr_set(unit, mem,
    251                              (uint32 *)&entry->entry_arr[1], IP_ADDR_MASKf,
    252                              tnl_info->sip6_mask, SOC_MEM_IP6_UPPER_ONLY);
    253         /* DIP MASK [0-63] */
    254         soc_mem_ip6_addr_set(unit, mem,
    255                              (uint32 *)&entry->entry_arr[2], IP_ADDR_MASKf,
    256                              tnl_info->dip6_mask, SOC_MEM_IP6_LOWER_ONLY);
    257         /* DIP MASK [64-127] */
    258         soc_mem_ip6_addr_set(unit, mem,
    259                              (uint32 *)&entry->entry_arr[3], IP_ADDR_MASKf,
    260                              tnl_info->dip6_mask, SOC_MEM_IP6_UPPER_ONLY);
    261     }  else if (tnl_type.tnl_outer_hdr_ipv6 == 0) {
    262         tnl_info->sip &= tnl_info->sip_mask;
    263 
    264         /* Set destination ip. */
    265         soc_mem_field32_set(unit, mem, entry_ptr, DIPf, tnl_info->dip);
    266 
    267         /* Set source ip. */
    268         soc_mem_field32_set(unit, mem, entry_ptr, SIPf, tnl_info->sip);
    269 
    270         /* Set destination subnet mask. */
    271         soc_mem_field32_set(unit, mem, entry_ptr, DIP_MASKf,
    272                                    tnl_info->dip_mask);
    273 
    274         /* Set source subnet mask. */
    275         soc_mem_field32_set(unit, mem, entry_ptr, SIP_MASKf,
    276                                    tnl_info->sip_mask);
    277     }
    278     /* Resolve number of entries hw entry occupies. */
    279     idx_max = (tnl_type.tnl_outer_hdr_ipv6 == 1) ? SOC_TNL_TERM_IPV6_ENTRY_WIDTH : \
    280               (tnl_type.tnl_outer_hdr_ipv6 == 0) ? SOC_TNL_TERM_IPV4_ENTRY_WIDTH : 0; 
    281 
    282     for (idx = 0; idx < idx_max; idx++) {
    283         entry_ptr = (uint32 *)&entry->entry_arr[idx];
    284 
    285         /* Set valid bit. */
    286         valid_bit = 1 <<  soc_mem_field_length(unit,mem,VALIDf);
    287         valid_bit -= 1;
    288         soc_mem_field32_set(unit, mem, entry_ptr, VALIDf, valid_bit);
    289 
    290         /* Set tunnel subtype. */
    291         soc_mem_field32_set(unit, mem, entry_ptr, SUB_TUNNEL_TYPEf,
    292                                    tnl_type.tnl_sub_type);
    293 
    294         /* Set tunnel type. */
    295         soc_mem_field32_set(unit, mem, entry_ptr, TUNNEL_TYPEf,
    296                                    tnl_type.tnl_auto);
    297 
    298         /* Set entry mode. */
    299 
    300     if (SOC_MEM_FIELD_VALID(unit, mem, MODEf)) {
    301         soc_mem_field32_set(unit, mem, entry_ptr, MODEf,
    302                                    tnl_type.tnl_outer_hdr_ipv6);
    303         soc_mem_field32_set(unit, mem, entry_ptr, MODE_MASKf, 1);
    304     } else if (SOC_MEM_FIELD_VALID(unit, mem, KEY_TYPEf)) {
    305         soc_mem_field32_set(unit, mem, entry_ptr, KEY_TYPEf,
    306                 tnl_type.tnl_outer_hdr_ipv6);
    307         soc_mem_field32_set(unit, mem, entry_ptr, KEY_TYPE_MASKf, 1);
    308     }
    309 
    310         if (0 == idx) {
    311             /* Set the PROTOCOL field */
    312             if ((tnl_info->type == bcmTunnelTypeIpAnyIn4) || 
    313                 (tnl_info->type == bcmTunnelTypeIpAnyIn6))
    314             {
    315               /* Set PROTOCOL and PROTOCOL_MASK field to zero for IpAnyInx tunnel type*/
    316                soc_mem_field32_set(unit, mem, entry_ptr, PROTOCOLf, 0x0);
    317                soc_mem_field32_set(unit, mem, entry_ptr, PROTOCOL_MASKf, 0x0);
    318             } else {            
    319                 soc_mem_field32_set(unit, mem, entry_ptr, PROTOCOLf,
    320                                            tnl_type.tnl_protocol);
    321                 soc_mem_field32_set(unit, mem, entry_ptr,
    322                                            PROTOCOL_MASKf, 0xff);
    323             }
    324         }
    325         
    326         if (SOC_MEM_FIELD_VALID(unit, mem, BFD_ENABLEf)) {
    327             soc_mem_field32_set(unit, mem, entry_ptr, BFD_ENABLEf, 0);
    328         }
    329 
    330         if ((tnl_info->type == bcmTunnelTypeWlanWtpToAc) ||
    331             (tnl_info->type == bcmTunnelTypeWlanAcToAc) ||
    332             (tnl_info->type == bcmTunnelTypeWlanWtpToAc6) ||
    333             (tnl_info->type == bcmTunnelTypeWlanAcToAc6)) { 
    334 
    335             /* Set the L4 ports - WLAN/AMT tunnels */
    336             if (0 == idx) {
    337                 soc_mem_field32_set(unit, mem, entry_ptr, L4_DEST_PORTf,
    338                                            tnl_info->udp_dst_port);
    339 
    340                 soc_mem_field32_set(unit, mem, entry_ptr,
    341                                            L4_DEST_PORT_MASKf, 0xffff);
    342 
    343                 soc_mem_field32_set(unit, mem, entry_ptr, L4_SRC_PORTf,
    344                                            tnl_info->udp_src_port);
    345     
    346                 soc_mem_field32_set(unit, mem, entry_ptr,
    347                                            L4_SRC_PORT_MASKf, 0xffff);
    348             }
    349 
    350             /* Set UDP tunnel type. */
    351             if (soc_mem_field_valid(unit, mem, UDP_TUNNEL_TYPEf)) {
    352                 soc_mem_field32_set(unit, mem, entry_ptr, UDP_TUNNEL_TYPEf,
    353                                            tnl_type.tnl_udp_type);
    354             }
    355             /* Ignore UDP checksum */
    356             if (soc_mem_field_valid(unit, mem, IGNORE_UDP_CHECKSUMf)) {
    357                 soc_mem_field32_set(unit, mem, entry_ptr, IGNORE_UDP_CHECKSUMf, 0x1);
    358             }
    359         } else if (tnl_info->type == bcmTunnelTypeAutoMulticast) {
    360 
    361             /* Set UDP tunnel type. */
    362             if (soc_mem_field_valid(unit, mem, UDP_TUNNEL_TYPEf)) {
    363                 soc_mem_field32_set(unit, mem, entry_ptr, UDP_TUNNEL_TYPEf,
    364                                            tnl_type.tnl_udp_type);
    365             }
    366 
    367             if (soc_mem_field_valid(unit, mem, IGNORE_UDP_CHECKSUMf)) {
    368                 soc_mem_field32_set(unit, mem, entry_ptr, IGNORE_UDP_CHECKSUMf, 0x1);
    369             }
    370 
    371             if (soc_mem_field_valid(unit, mem, CTRL_PKTS_TO_CPUf)) {
    372                 soc_mem_field32_set(unit, mem, entry_ptr, CTRL_PKTS_TO_CPUf, 0x1);
    373             }
    374         } else if (tnl_info->type == bcmTunnelTypeAutoMulticast6) {
    375 
    376             /* Set UDP tunnel type. */
    377             if (soc_mem_field_valid(unit, mem, UDP_TUNNEL_TYPEf)) {
    378                 soc_mem_field32_set(unit, mem, entry_ptr, UDP_TUNNEL_TYPEf,
    379                                            tnl_type.tnl_udp_type);
    380             }
    381 
    382             if (soc_mem_field_valid(unit, mem, IGNORE_UDP_CHECKSUMf)) {
    383                 soc_mem_field32_set(unit, mem, entry_ptr, IGNORE_UDP_CHECKSUMf, 0x1);
    384             }
    385 
    386             if (soc_mem_field_valid(unit, mem, CTRL_PKTS_TO_CPUf)) {
    387                 soc_mem_field32_set(unit, mem, entry_ptr, CTRL_PKTS_TO_CPUf, 0x1);
    388             }
    389         }
    390 
    391         /* Save vlan id for ipmc lookup.*/
    392         if((tnl_info->vlan) && SOC_MEM_FIELD_VALID(unit, mem, L3_IIFf)) {
    393             soc_mem_field32_set(unit, mem, entry_ptr, L3_IIFf, tnl_info->vlan);
    394         }
    395 
    396         /* Set GRE payload */
    397         if (tnl_type.tnl_gre) {
    398             /* GRE IPv6 payload is allowed. */
    399             soc_mem_field32_set(unit, mem, entry_ptr, GRE_PAYLOAD_IPV6f,
    400                                        tnl_type.tnl_gre_v6_payload);
    401 
    402             /* GRE IPv6 payload is allowed. */
    403             soc_mem_field32_set(unit, mem, entry_ptr, GRE_PAYLOAD_IPV4f,
    404                                        tnl_type.tnl_gre_v4_payload);
    405         }
    406     }
    407     return (BCM_E_NONE);
    408 }
    409 
    410 /*
    411  * Function:
    412  *      _bcm_tr2_l3_tnl_term_entry_parse
    413  * Purpose:
    414  *      Parse tunnel terminator entry portion.
    415  * Parameters:
    416  *      unit     - (IN)  BCM device number. 
    417  *      entry    - (IN)  SOC buffer with tunne information.  
    418  *      tnl_info - (OUT) BCM buffer with tunnel info.
    419  * Returns:
    420  *      BCM_E_XXX
    421  */
    422 int
    423 _bcm_tr2_l3_tnl_term_entry_parse(int unit, soc_tunnel_term_t *entry,
    424                                   bcm_tunnel_terminator_t *tnl_info)
    425 {
    426     _bcm_tnl_term_type_t tnl_type;     /* Tunnel type information.   */
    427     uint32 *entry_ptr;                 /* Filled entry pointer.      */
    428     int tunnel_id;                     /* Tunnel ID */
    429     int remote_port;                   /* Remote port */
    430     bcm_module_t mod, mod_out, my_mod; /* Module IDs */
    431     bcm_port_t port, port_out;         /* Physical ports */
    432     soc_mem_t mem = L3_TUNNELm;
    433     /* Input parameters check. */
    434     if ((NULL == tnl_info) || (NULL == entry)) {
    435         return (BCM_E_PARAM);
    436     }
    437 
    438     /* Reset destination structure. */
    439     bcm_tunnel_terminator_t_init(tnl_info);
    440     sal_memset(&tnl_type, 0, sizeof(_bcm_tnl_term_type_t));
    441 
    442     if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
    443         mem = L3_TUNNEL_DOUBLEm;
    444     }
    445 
    446     entry_ptr = (uint32 *)&entry->entry_arr[0];
    447 
    448     /* Get valid bit. */
    449     if (!soc_mem_field32_get(unit, mem, entry_ptr, VALIDf)) {
    450         return (BCM_E_NOT_FOUND);
    451     }
    452 
    453     if (SOC_MEM_FIELD_VALID(unit, mem, MODEf)) {
    454         tnl_type.tnl_outer_hdr_ipv6 =
    455             soc_mem_field32_get(unit, mem, entry_ptr, MODEf);
    456     } else if (SOC_MEM_FIELD_VALID(unit, mem, KEY_TYPEf)) {
    457         tnl_type.tnl_outer_hdr_ipv6 =
    458             soc_mem_field32_get(unit, mem, entry_ptr, KEY_TYPEf);
    459 
    460     }
    461      
    462     /* Get Destination/Source pair. */
    463     if (tnl_type.tnl_outer_hdr_ipv6 == 1) {
    464         /* SIP [0-63] */
    465         soc_mem_ip6_addr_get(unit, mem,
    466                              (uint32 *)&entry->entry_arr[0], IP_ADDRf,
    467                              tnl_info->sip6, SOC_MEM_IP6_LOWER_ONLY);
    468         /* SIP [64-127] */
    469         soc_mem_ip6_addr_get(unit, mem,
    470                              (uint32 *)&entry->entry_arr[1], IP_ADDRf,
    471                              tnl_info->sip6, SOC_MEM_IP6_UPPER_ONLY);
    472         /* DIP [0-63] */
    473         soc_mem_ip6_addr_get(unit, mem,
    474                              (uint32 *)&entry->entry_arr[2], IP_ADDRf,
    475                              tnl_info->dip6, SOC_MEM_IP6_LOWER_ONLY);
    476         /* DIP [64-127] */
    477         soc_mem_ip6_addr_get(unit, mem,
    478                              (uint32 *)&entry->entry_arr[3], IP_ADDRf,
    479                              tnl_info->dip6, SOC_MEM_IP6_UPPER_ONLY);
    480 
    481         /* SIP MASK [0-63] */
    482         soc_mem_ip6_addr_get(unit, mem,
    483                              (uint32 *)&entry->entry_arr[0], IP_ADDR_MASKf,
    484                              tnl_info->sip6_mask, SOC_MEM_IP6_LOWER_ONLY);
    485         /* SIP MASK [64-127] */
    486         soc_mem_ip6_addr_get(unit, mem,
    487                              (uint32 *)&entry->entry_arr[1], IP_ADDR_MASKf,
    488                              tnl_info->sip6_mask, SOC_MEM_IP6_UPPER_ONLY);
    489         /* DIP MASK [0-63] */
    490         soc_mem_ip6_addr_get(unit, mem,
    491                              (uint32 *)&entry->entry_arr[2], IP_ADDR_MASKf,
    492                              tnl_info->dip6_mask, SOC_MEM_IP6_LOWER_ONLY);
    493         /* DIP MASK [64-127] */
    494         soc_mem_ip6_addr_get(unit, mem,
    495                              (uint32 *)&entry->entry_arr[3], IP_ADDR_MASKf,
    496                              tnl_info->dip6_mask, SOC_MEM_IP6_UPPER_ONLY);
    497 
    498     }  else if (tnl_type.tnl_outer_hdr_ipv6 == 0) {
    499         /* Get destination ip. */
    500         tnl_info->dip = soc_mem_field32_get(unit, mem, entry_ptr, DIPf);
    501 
    502         /* Get source ip. */
    503         tnl_info->sip = soc_mem_field32_get(unit, mem, entry_ptr, SIPf);
    504 
    505         /* Destination subnet mask. */
    506         tnl_info->dip_mask = BCM_XGS3_L3_IP4_FULL_MASK;
    507 
    508         /* Source subnet mask. */
    509         tnl_info->sip_mask = soc_mem_field32_get(unit, mem, entry_ptr,
    510                                                         SIP_MASKf);
    511     }
    512 
    513     /* Get tunnel subtype. */
    514     tnl_type.tnl_sub_type =
    515         soc_mem_field32_get(unit, mem, entry_ptr, SUB_TUNNEL_TYPEf);
    516 
    517     /* Get UDP tunnel type. */
    518     if (soc_mem_field_valid(unit, mem, UDP_TUNNEL_TYPEf)) {
    519         tnl_type.tnl_udp_type =
    520             soc_mem_field32_get(unit, mem, entry_ptr, UDP_TUNNEL_TYPEf);
    521     }
    522 
    523     /* Get tunnel type. */
    524     tnl_type.tnl_auto =
    525         soc_mem_field32_get(unit, mem, entry_ptr, TUNNEL_TYPEf);
    526 
    527     /* Copy DSCP from outer header flag. */
    528     if (soc_mem_field32_get(unit, mem, entry_ptr, USE_OUTER_HDR_DSCPf)) {
    529         tnl_info->flags |= BCM_TUNNEL_TERM_USE_OUTER_DSCP;
    530     }
    531     /* Copy TTL from outer header flag. */
    532     if (soc_mem_field32_get(unit, mem, entry_ptr, USE_OUTER_HDR_TTLf)) {
    533         tnl_info->flags |= BCM_TUNNEL_TERM_USE_OUTER_TTL;
    534     }
    535     /* Keep inner header DSCP flag. */
    536     if (soc_mem_field32_get(unit, mem, entry_ptr,
    537                                    DONOT_CHANGE_INNER_HDR_DSCPf)) {
    538         tnl_info->flags |= BCM_TUNNEL_TERM_KEEP_INNER_DSCP;
    539     }
    540 
    541     soc_mem_pbmp_field_get(unit, mem, entry_ptr, ALLOWED_PORT_BITMAPf,
    542                            &tnl_info->pbmp);
    543 
    544     /* Tunnel or IPMC lookup vlan id */
    545     tnl_info->vlan = soc_mem_field32_get(unit, mem, entry_ptr, IINTFf);
    546 
    547     /*  Get trust dscp per tunnel */ 
    548     if (soc_mem_field32_get(unit, mem, entry_ptr, USE_OUTER_HDR_DSCPf)) {
    549         tnl_info->flags |= BCM_TUNNEL_TERM_DSCP_TRUST;
    550     }
    551     
    552     /* Get Tunnel class id for VFP match */
    553     if(SOC_MEM_FIELD_VALID(unit, mem, TUNNEL_CLASS_IDf)) {
    554         tnl_info->tunnel_class = soc_mem_field32_get(unit, mem, entry_ptr,
    555                                     TUNNEL_CLASS_IDf);
    556     }
    557 
    558     /* Get the protocol field and make some decisions */
    559     tnl_type.tnl_protocol = soc_mem_field32_get(unit, mem, entry_ptr,
    560                                                        PROTOCOLf);
    561     switch (tnl_type.tnl_protocol) {
    562         case 0x2F:
    563             tnl_type.tnl_gre = 1;
    564             break;
    565         case 0x67:
    566             tnl_type.tnl_pim_sm = 1;
    567         default:
    568             break;
    569     }
    570     /* Get gre IPv4 payload allowed. */
    571     tnl_type.tnl_gre_v4_payload = 
    572         soc_mem_field32_get(unit, mem, entry_ptr, GRE_PAYLOAD_IPV4f);
    573 
    574     /* Get gre IPv6 payload allowed. */
    575     tnl_type.tnl_gre_v6_payload = 
    576         soc_mem_field32_get(unit, mem, entry_ptr, GRE_PAYLOAD_IPV6f);
    577 
    578     /* Get the L4 data */
    579     if (soc_mem_field_valid (unit, mem, L4_SRC_PORTf)) {
    580         tnl_info->udp_src_port = soc_mem_field32_get(unit, mem, entry_ptr,
    581                                                         L4_SRC_PORTf);
    582     }
    583     if (soc_mem_field_valid (unit, mem, L4_DEST_PORTf)) {
    584         tnl_info->udp_dst_port = soc_mem_field32_get(unit, mem, entry_ptr,
    585                                                         L4_DEST_PORTf);
    586     }
    587     /* Get the tunnel ID */
    588     if (SOC_MEM_FIELD_VALID(unit, mem, TUNNEL_IDf)) {
    589         tunnel_id = soc_mem_field32_get(unit, mem, entry_ptr, TUNNEL_IDf);
    590         if (tunnel_id) {
    591             BCM_GPORT_TUNNEL_ID_SET(tnl_info->tunnel_id, tunnel_id);
    592             tnl_info->flags |= BCM_TUNNEL_TERM_TUNNEL_WITH_ID;
    593         }
    594     }
    595 
    596     /* Get tunnel type, sub_type and protocol. */
    597     BCM_IF_ERROR_RETURN
    598         (_bcm_xgs3_l3_get_tnl_term_type(unit, tnl_info, &tnl_type));
    599     /* Get the remote port member */
    600     if (SOC_MEM_FIELD_VALID(unit, mem, REMOTE_TERM_GPPf)) {
    601         remote_port = soc_mem_field32_get(unit, mem, entry_ptr,
    602                                              REMOTE_TERM_GPPf);
    603         mod = (remote_port >> 6) & 0x7F;
    604         port = remote_port & 0x3F;
    605         BCM_IF_ERROR_RETURN
    606             (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
    607                                     mod, port, &mod_out, &port_out));
    608         BCM_GPORT_MODPORT_SET(tnl_info->remote_port, mod_out, port_out);
    609         BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &my_mod));
    610         if (mod != my_mod) {
    611             if ((tnl_info->type == bcmTunnelTypeWlanWtpToAc) ||
    612                 (tnl_info->type == bcmTunnelTypeWlanAcToAc) ||
    613                 (tnl_info->type == bcmTunnelTypeWlanWtpToAc6) ||
    614                 (tnl_info->type == bcmTunnelTypeWlanAcToAc6)) {
    615                 tnl_info->flags |= BCM_TUNNEL_TERM_WLAN_REMOTE_TERMINATE;
    616             }
    617         }
    618     }
    619     /* Get IIF if l3 ingress mode is not set */
    620     if (!BCM_XGS3_L3_INGRESS_MODE_ISSET(unit) &&
    621         BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) && (tnl_info->vlan > BCM_VLAN_MAX)) {
    622         _bcm_l3_ingress_intf_t iif;
    623         sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t));
    624         iif.intf_id = tnl_info->vlan;
    625         BCM_IF_ERROR_RETURN(_bcm_tr_l3_ingress_interface_get(unit, NULL, &iif));
    626 
    627         tnl_info->vrf = iif.vrf;
    628         tnl_info->if_class = iif.if_class;
    629         tnl_info->qos_map_id = iif.qos_map_id;
    630 #ifdef BCM_TOMAHAWK_SUPPORT        
    631         if (SOC_IS_TOMAHAWKX(unit) && soc_feature(unit, soc_feature_ecn_wred)) {
    632             if (bcmi_xgs5_ecn_map_used_get(unit, iif.tunnel_term_ecn_map_id,
    633                                            _bcmEcnmapTypeTunnelTerm)) {
    634                 tnl_info->tunnel_term_ecn_map_id = iif.tunnel_term_ecn_map_id |
    635                     _BCM_XGS5_ECN_MAP_TYPE_TUNNEL_TERM;
    636                 tnl_info->flags |= BCM_TUNNEL_TERM_ECN_MAP;
    637             }
    638         }
    639 #endif        
    640     }
    641 #ifdef BCM_TRIDENT3_SUPPORT
    642     if (SOC_MEM_FIELD_VALID(unit, mem, DEFAULT_VLAN_PROFILE_INDEXf)) {
    643         int vlan_profile_idx = soc_mem_field32_get(unit, mem, entry_ptr,
    644                                              DEFAULT_VLAN_PROFILE_INDEXf);
    645         if (vlan_profile_idx) {
    646             /* Get the forwarding VLAN ID */
    647             tunnel_default_vlan_profile_entry_t tunnel_default_vlan_profile_entry;
    648 
    649             BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_TUNNEL_DEFAULT_VLAN_PROFILEm,
    650                                  MEM_BLOCK_ANY, vlan_profile_idx,
    651                                  &tunnel_default_vlan_profile_entry));
    652 
    653             tnl_info->fwd_vlan = soc_mem_field32_get(unit, L3_TUNNEL_DEFAULT_VLAN_PROFILEm,
    654                                      (uint32 *)&tunnel_default_vlan_profile_entry, OUTER_VLAN_TAGf);
    655         }
    656     }
    657 #endif
    658 
    659     return (BCM_E_NONE);
    660 }
    661 
    662 /*
    663  * Function:
    664  *      _bcm_tr2_l3_ecmp_grp_get
    665  * Purpose:
    666  *      Get ecmp group next hop members by index.
    667  * Parameters:
    668  *      unit       - (IN)SOC unit number.
    669  *      ecmp_grp - (IN)Ecmp group id to read. 
    670  *      ecmp_count - (IN)Maximum number of entries to read.
    671  *      nh_idx     - (OUT)Next hop indexes. 
    672  * Returns:
    673  *      BCM_E_XXX
    674  */
    675 int
    676 _bcm_tr2_l3_ecmp_grp_get(int unit, int ecmp_grp, int ecmp_group_size, int *nh_idx)
    677 {
    678     int idx;                                /* Iteration index.              */
    679     int max_ent_count;                      /* Number of entries to read.    */
    680     uint32 hw_buf[SOC_MAX_MEM_FIELD_WORDS]; /* Buffer to read hw entry.      */
    681     int one_entry_grp = TRUE;               /* Single next hop entry group.  */ 
    682     int rv = BCM_E_UNAVAIL;                 /* Operation return status.      */
    683     int ecmp_idx;
    684 
    685     /* Input parameters sanity check. */
    686     if ((NULL == nh_idx) || (ecmp_group_size < 1)) {
    687         return (BCM_E_PARAM);
    688     }
    689 
    690     /* Zero all next hop indexes first. */
    691     sal_memset(nh_idx, 0, ecmp_group_size * sizeof(int));
    692     sal_memset(hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
    693 
    694     /* Get group base pointer. */
    695     BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMP_COUNTm,
    696                                           MEM_BLOCK_ANY, ecmp_grp, hw_buf));
    697     ecmp_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, hw_buf, BASE_PTRf);
    698 
    699     /* Read zero based ecmp count. */
    700     rv = soc_mem_read(unit, L3_ECMP_COUNTm, MEM_BLOCK_ANY, ecmp_grp, hw_buf);
    701     if (BCM_FAILURE(rv)) {
    702         return rv;
    703     }
    704 
    705     max_ent_count = soc_mem_field32_get(unit, L3_ECMP_COUNTm, hw_buf, COUNTf);
    706     max_ent_count++; /* Count is zero based. */ 
    707 
    708     /* Read all the indexes from hw. */
    709     for (idx = 0; idx < max_ent_count; idx++) {
    710 
    711         /* Read next hop index. */
    712         rv = soc_mem_read(unit, L3_ECMPm, MEM_BLOCK_ANY, 
    713                           (ecmp_idx + idx), hw_buf);
    714         if (rv < 0) {
    715             break;
    716         }
    717         nh_idx[idx] = soc_mem_field32_get(unit, L3_ECMPm, 
    718                                           hw_buf, NEXT_HOP_INDEXf);
    719         /* Check if group contains . */ 
    720         if (idx && (nh_idx[idx] != nh_idx[0])) { 
    721             one_entry_grp = FALSE;
    722         }
    723 
    724         if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
    725             /* Next hops popuplated in cycle,stop once you read first entry again */
    726             if (idx && (FALSE == one_entry_grp) && (nh_idx[idx] == nh_idx[0])) {
    727                 nh_idx[idx] = 0;
    728                 break;
    729             }
    730         } else {
    731              one_entry_grp = FALSE;
    732         }
    733     }
    734     /* Reset rest of the group if only 1 next hop is present. */
    735     if (one_entry_grp) {
    736        sal_memset(nh_idx + 1, 0, (ecmp_group_size - 1) * sizeof(int)); 
    737     }
    738     return rv;
    739 }
    740 
    741 /*
    742  * Function:
    743  *      _bcm_tr2_l3_ecmp_grp_add
    744  * Purpose:
    745  *      Add ecmp group next hop members, or reset ecmp group entry.  
    746  *      NOTE: Function always writes all the entries in ecmp group.
    747  *            If there is not enough nh indexes - next hops written
    748  *            in cycle. 
    749  * Parameters:
    750  *      unit       - (IN)SOC unit number.
    751  *      ecmp_grp   - (IN)ecmp group id to write.
    752  *      buf        - (IN)Next hop indexes or NULL for entry reset.
    753  *      info       - (IN)ECMP additional info
    754  * Returns:
    755  *      BCM_E_XXX
    756  */
    757 int
    758 _bcm_tr2_l3_ecmp_grp_add(int unit, int ecmp_grp, void *buf, void *info)
    759 {
    760     uint32 l3_ecmp[SOC_MAX_MEM_FIELD_WORDS];        /* l3_ecmp buf             */
    761     uint32 l3_ecmp_count[SOC_MAX_MEM_FIELD_WORDS];  /* l3_ecmp_count buf       */
    762     uint32 hw_buf[SOC_MAX_MEM_FIELD_WORDS];         /* l3_ecmp_count buf       */
    763     int ecmp_idx;                                   /* Ecmp table entry index. */
    764     int *nh_idx;                                    /* Ecmp group nh indexes.  */
    765     int nh_cycle_idx;
    766     int entry_type;
    767     uint32 reg_val, value;
    768     ing_l3_next_hop_entry_t ing_nh;
    769     _bcm_l3_tbl_op_t data;
    770     int max_grp_size = 0;                           /* Maximum ecmp group size.*/
    771     int idx = 0;                                    /* Iteration index.        */
    772     int rv = BCM_E_UNAVAIL;                         /* Operation return value. */
    773     int l3_ecmp_oif_flds[8] = {  L3_OIF_0f, 
    774                              L3_OIF_1f, 
    775                              L3_OIF_2f, 
    776                              L3_OIF_3f, 
    777                              L3_OIF_4f, 
    778                              L3_OIF_5f, 
    779                              L3_OIF_6f, 
    780                              L3_OIF_7f }; 
    781     int l3_ecmp_oif_type_flds[8] = {  L3_OIF_0_TYPEf, 
    782                              L3_OIF_1_TYPEf, 
    783                              L3_OIF_2_TYPEf, 
    784                              L3_OIF_3_TYPEf, 
    785                              L3_OIF_4_TYPEf, 
    786                              L3_OIF_5_TYPEf, 
    787                              L3_OIF_6_TYPEf, 
    788                              L3_OIF_7_TYPEf };
    789     _bcm_l3_ecmp_group_info_t *ecmp_info = info;
    790     _bcm_l3_ecmp_group_buffer_t *ecmp_buffer = buf;
    791 
    792     /* Input parameters check. */
    793     if (NULL == ecmp_buffer || NULL == ecmp_info ||
    794         NULL == ecmp_buffer->group_buffer) {
    795         return (BCM_E_PARAM);
    796     }
    797 
    798     /* Cast input buffer. */
    799     nh_idx = ecmp_buffer->group_buffer;
    800     max_grp_size = ecmp_info->max_paths;
    801 
    802     if (BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit,
    803                                 ecmp_grp), ecmp_grp)) {
    804         /* Group has already exists, get base ptr from group table */ 
    805         sal_memset (hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
    806         BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMP_COUNTm,
    807                             MEM_BLOCK_ANY, ecmp_grp, hw_buf));
    808         ecmp_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, hw_buf, BASE_PTRf);
    809     } else {  
    810         /* Get index to the first slot in the ECMP table
    811          * that can accomodate max_grp_size */
    812         data.width = ecmp_info->max_paths;
    813         data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 
    814         data.oper_flags = _BCM_L3_SHR_TABLE_TRAVERSE_CONTROL; 
    815         data.entry_index = -1;
    816         rv = _bcm_xgs3_tbl_free_idx_get(unit, &data);
    817         if (BCM_FAILURE(rv)) {
    818             if (rv == BCM_E_FULL) {
    819                 /* Defragment ECMP table */
    820                 BCM_IF_ERROR_RETURN(bcm_tr2_l3_ecmp_defragment_no_lock(unit, 0));
    821     
    822                 /* Attempt to get free index again */
    823                 BCM_IF_ERROR_RETURN(_bcm_xgs3_tbl_free_idx_get(unit, &data));
    824             } else {
    825                 return rv;
    826             }
    827         }
    828         ecmp_idx = data.entry_index;
    829         BCM_XGS3_L3_ENT_REF_CNT_INC(data.tbl_ptr, data.entry_index, max_grp_size);
    830     }
    831 
    832     if (ecmp_idx >= BCM_XGS3_L3_ECMP_TBL_SIZE(unit)) {
    833         return BCM_E_FULL;
    834     }
    835 
    836     sal_memset (hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
    837 
    838     /* Write all the indexes to hw. */
    839     for (idx = 0, nh_cycle_idx = 0; idx < max_grp_size; idx++, nh_cycle_idx++) {
    840 
    841         /* Set next hop index. */
    842         sal_memset (l3_ecmp, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
    843 
    844         /* If this is the last nhop then program black-hole. */
    845         if ( (!idx) && (!nh_idx[nh_cycle_idx]) ) {
    846               nh_cycle_idx = 0;
    847         } else  if (!nh_idx[nh_cycle_idx]) {
    848             break;
    849         }
    850 
    851         soc_mem_field32_set(unit, L3_ECMPm, l3_ecmp, NEXT_HOP_INDEXf,
    852                             nh_idx[nh_cycle_idx]);
    853 
    854         /* Write buffer to hw L3_ECMPm table. */
    855         rv = soc_mem_write(unit, L3_ECMPm, MEM_BLOCK_ALL, 
    856                            (ecmp_idx + idx), l3_ecmp);
    857         if (BCM_FAILURE(rv)) {
    858             break;
    859         }
    860 
    861         /* Write buffer to hw INITIAL_L3_ECMPm table. */
    862         rv = soc_mem_write(unit, INITIAL_L3_ECMPm, MEM_BLOCK_ALL, 
    863                                     (ecmp_idx + idx), l3_ecmp);
    864         if (BCM_FAILURE(rv)) {
    865             break;
    866         }
    867         
    868         if (soc_feature(unit, soc_feature_urpf)) {
    869             /* Check if URPF is enabled on device */
    870             BCM_IF_ERROR_RETURN(
    871                  READ_L3_DEFIP_RPF_CONTROLr(unit, &reg_val));
    872             if (reg_val) {
    873                 if (idx < 8) {
    874                     BCM_IF_ERROR_RETURN (soc_mem_read(unit, 
    875                        ING_L3_NEXT_HOPm, MEM_BLOCK_ANY, 
    876                        nh_idx[idx], &ing_nh));
    877 
    878                     entry_type = soc_ING_L3_NEXT_HOPm_field32_get(unit, 
    879                                               &ing_nh, ENTRY_TYPEf);
    880 
    881                     if (entry_type == 0x0) {
    882                         value = soc_ING_L3_NEXT_HOPm_field32_get(unit, 
    883                                       &ing_nh, VLAN_IDf);
    884                         if (soc_mem_field_valid(unit, 
    885                                 L3_ECMP_COUNTm, l3_ecmp_oif_type_flds[idx])) {
    886                             soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, 
    887                                       l3_ecmp_oif_type_flds[idx], entry_type);
    888                         }
    889                         soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, 
    890                                       l3_ecmp_oif_flds[idx], value);
    891                     } else if (entry_type == 0x1) {
    892                         value  = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, L3_OIFf);
    893                         if (soc_mem_field_valid(unit, 
    894                                 L3_ECMP_COUNTm, l3_ecmp_oif_type_flds[idx])) {
    895                             soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, 
    896                                       l3_ecmp_oif_type_flds[idx], entry_type);
    897                         }
    898                         soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, 
    899                                         l3_ecmp_oif_flds[idx], value);
    900                     }
    901                     soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, URPF_COUNTf, idx);
    902                 } else {
    903                     /* Inorder to avoid TRAP_TO_CPU, urpf_mode on L3_IIF/PORT must be set 
    904                      *  to STRICT_MODE / LOOSE_MODE */
    905                     soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, ECMP_GT8f , 1);
    906                 }
    907             }
    908         }
    909     }
    910 
    911     if (BCM_SUCCESS(rv)) {
    912         /* mode 0 = 512 ecmp groups */
    913         if (!BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 
    914             /* Set Max Group Size. */
    915             sal_memset (l3_ecmp_count, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
    916             soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, COUNTf, max_grp_size - 1);
    917 
    918             rv = soc_mem_write(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL, 
    919                                (ecmp_grp+1), l3_ecmp_count);
    920             BCM_IF_ERROR_RETURN(rv);
    921         }
    922         /* Set zero based ecmp count. */
    923         if (!idx) {
    924             soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, COUNTf, idx);
    925         } else {
    926             soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, COUNTf, idx - 1);
    927         }
    928 
    929         /* Set group base pointer. */
    930         soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf, 
    931                             BASE_PTRf, ecmp_idx);
    932 
    933         rv = soc_mem_write(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL, 
    934                            ecmp_grp, hw_buf);
    935 
    936         BCM_IF_ERROR_RETURN(rv);
    937 
    938         rv = soc_mem_write(unit, INITIAL_L3_ECMP_COUNTm,
    939                            MEM_BLOCK_ALL, ecmp_grp, hw_buf);
    940         /* mode 1 = max possible ecmp groups */
    941         if (BCM_XGS3_L3_MAX_ECMP_MODE(unit)) {
    942             /* Save the max possible paths for this ECMP group in s/w */ 
    943             BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[ecmp_grp] = ecmp_info->max_paths;
    944         }
    945     }
    946     return rv;
    947 }
    948 
    949 /*
    950  * Function:
    951  *      _bcm_tr2_l3_ecmp_grp_del
    952  * Purpose:
    953  *      Reset ecmp group next hop members
    954  * Parameters:
    955  *      unit       - (IN)SOC unit number.
    956  *      ecmp_grp   - (IN)ecmp group id to write.
    957  *      info       - (IN)ECMP additional info
    958  * Returns:
    959  *      BCM_E_XXX
    960  */
    961 int
    962 _bcm_tr2_l3_ecmp_grp_del(int unit, int ecmp_grp, void *info)
    963 {
    964     uint32 hw_buf[SOC_MAX_MEM_FIELD_WORDS]; /* Buffer to write hw entry.*/
    965     ecmp_count_entry_t ecmp_count_entry;
    966     int ecmp_idx;               /* Ecmp table entry index. */
    967     int idx;                    /* Iteration index.        */
    968     int rv = BCM_E_UNAVAIL;     /* Operation return value. */
    969     _bcm_l3_tbl_op_t data;
    970     data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 
    971 
    972     if (NULL == info) {
    973         return BCM_E_INTERNAL;
    974     }
    975 
    976     /* Initialize ecmp entry. */
    977     sal_memset (hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
    978 
    979     /* Calculate table index. */
    980     BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMP_COUNTm,
    981                 MEM_BLOCK_ANY, ecmp_grp, &ecmp_count_entry));
    982     ecmp_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, &ecmp_count_entry,
    983             BASE_PTRf);
    984 
    985     /* Write all the indexes to hw. */
    986     for (idx = 0; idx < ((_bcm_l3_ecmp_group_info_t*)info)->max_paths; idx++) {
    987         /* Write buffer to hw. */
    988         rv = soc_mem_write(unit, L3_ECMPm, MEM_BLOCK_ALL, 
    989                            (ecmp_idx + idx), hw_buf);
    990 
    991         if (BCM_FAILURE(rv)) {
    992             return rv;
    993         }
    994 
    995         /* Write initial ecmp table. */
    996         if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMPm)) {
    997             /* Write buffer to hw. */
    998             rv = soc_mem_write(unit, INITIAL_L3_ECMPm, MEM_BLOCK_ALL, 
    999                            (ecmp_idx + idx), hw_buf);
   1000             if (BCM_FAILURE(rv)) {
   1001                 return rv;
   1002             }
   1003         }
   1004     }
   1005 
   1006     /* Decrement ref count for the entries in ecmp table
   1007      * Ref count for ecmp_group table is decremented in common table del func. */
   1008     BCM_XGS3_L3_ENT_REF_CNT_DEC(data.tbl_ptr, ecmp_idx,
   1009                         ((_bcm_l3_ecmp_group_info_t*)info)->max_paths);
   1010 
   1011     /* Set group base pointer. */
   1012     ecmp_idx = ecmp_grp;
   1013 
   1014     rv = soc_mem_write(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL, 
   1015                        ecmp_idx, hw_buf);
   1016     BCM_IF_ERROR_RETURN(rv);
   1017 
   1018     if (!BCM_XGS3_L3_MAX_ECMP_MODE(unit)) {
   1019         rv = soc_mem_write(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL, 
   1020                 (ecmp_idx+1), hw_buf);
   1021         BCM_IF_ERROR_RETURN(rv);
   1022     }
   1023 
   1024     rv = soc_mem_write(unit, INITIAL_L3_ECMP_COUNTm, MEM_BLOCK_ALL, 
   1025                        ecmp_idx, hw_buf);
   1026     
   1027     if (BCM_XGS3_L3_MAX_ECMP_MODE(unit)) {
   1028         /* Reset the max paths of the deleted group */
   1029         BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[ecmp_grp] = 0;
   1030     }
   1031 
   1032     return rv;
   1033 }
   1034 
   1035 /*
   1036  * Function:
   1037  *      _bcm_tr2_l3_intf_urpf_default_route_set
   1038  * Purpose:
   1039  *      Set urpf_default_route enable flag for the L3 interface. 
   1040  * Parameters:
   1041  *      unit      - (IN)SOC unit number.
   1042  *      vid       - (IN)Vlan id. 
   1043  *      enable    - (IN)Enable. 
   1044  * Returns:
   1045  *      BCM_E_XXX.
   1046  */
   1047 int
   1048 _bcm_tr2_l3_intf_urpf_default_route_set(int unit, bcm_vlan_t vid, int enable)  
   1049 {
   1050     _bcm_l3_ingress_intf_t iif; /* Ingress interface config.*/
   1051     int ret_val;                /* Operation return value.  */
   1052 
   1053     /* Input parameters sanity check. */
   1054     if ((vid > soc_mem_index_max(unit, L3_IIFm)) || 
   1055         (vid < soc_mem_index_min(unit, L3_IIFm))) {
   1056         return (BCM_E_PARAM);
   1057     }
   1058 
   1059     iif.intf_id = vid;
   1060     soc_mem_lock(unit, L3_IIFm);
   1061 
   1062     ret_val = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif);
   1063     if (BCM_FAILURE(ret_val)) {
   1064         soc_mem_unlock(unit, L3_IIFm);
   1065         return (ret_val);
   1066     }
   1067 
   1068     if (enable) {
   1069        iif.flags |= BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK;
   1070     } else {
   1071        iif.flags &= ~BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK;
   1072     }
   1073 
   1074     ret_val = _bcm_tr_l3_ingress_interface_set(unit, &iif, NULL, NULL);
   1075 
   1076     soc_mem_unlock(unit, L3_IIFm);
   1077 
   1078     return (ret_val);
   1079 }
   1080 
   1081 /*
   1082  * Function:
   1083  *      _bcm_tr2_l3_intf_urpf_default_route_get
   1084  * Purpose:
   1085  *      Get the urpf_default_route_check enable flag for the specified L3 interface
   1086  * Parameters:
   1087  *      unit      - (IN)SOC unit number.
   1088  *      vid       - (IN)Vlan id. 
   1089  *      enable    - (OUT)enable. 
   1090  * Returns:
   1091  *      BCM_E_XXX.
   1092  */
   1093 int
   1094 _bcm_tr2_l3_intf_urpf_default_route_get (int unit, bcm_vlan_t vid, int *enable)
   1095 {
   1096     _bcm_l3_ingress_intf_t iif; /* Ingress interface config.*/
   1097 
   1098     /* Input parameters sanity check. */
   1099     if ((vid > soc_mem_index_max(unit, L3_IIFm)) || 
   1100         (vid < soc_mem_index_min(unit, L3_IIFm))) {
   1101         return (BCM_E_PARAM);
   1102     }
   1103 
   1104     iif.intf_id = vid;
   1105 
   1106     BCM_IF_ERROR_RETURN(_bcm_tr_l3_ingress_interface_get(unit, NULL, &iif));
   1107 
   1108     *enable = (iif.flags & BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK) ? 1 : 0;
   1109     return (BCM_E_NONE);
   1110 }
   1111 /*
   1112  * Function:
   1113  *      _bcm_tr2_l3_intf_urpf_mode_set
   1114  * Purpose:
   1115  *      Set the urpf_mode info for the specified L3 interface
   1116  * Parameters:
   1117  *      unit      - (IN)SOC unit number.
   1118  *      vid       - (IN)Vlan id. 
   1119  *      urpf_mode       - (IN)urpf_mode. 
   1120  * Returns:
   1121  *      BCM_E_XXX.
   1122  */
   1123 int
   1124 _bcm_tr2_l3_intf_urpf_mode_set(int unit, bcm_vlan_t vid, bcm_vlan_urpf_mode_t urpf_mode)  
   1125 {
   1126     _bcm_l3_ingress_intf_t iif; /* Ingress interface config.*/
   1127     int ret_val;                /* Operation return value.  */
   1128 
   1129     /* Input parameters sanity check. */
   1130     if ((vid > soc_mem_index_max(unit, L3_IIFm)) || 
   1131         (vid < soc_mem_index_min(unit, L3_IIFm))) {
   1132         return (BCM_E_PARAM);
   1133     }
   1134    
   1135     iif.intf_id = vid;
   1136     soc_mem_lock(unit, L3_IIFm);
   1137 
   1138     ret_val = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif);
   1139     if (BCM_FAILURE(ret_val)) {
   1140         soc_mem_unlock(unit, L3_IIFm);
   1141         return (ret_val);
   1142     }
   1143 
   1144     iif.urpf_mode = urpf_mode;
   1145 
   1146     ret_val = _bcm_tr_l3_ingress_interface_set(unit, &iif, NULL, NULL);
   1147 
   1148     soc_mem_unlock(unit, L3_IIFm);
   1149 
   1150     return (ret_val);
   1151 }
   1152 
   1153 /*
   1154  * Function:
   1155  *      _bcm_tr2_l3_intf_urpf_mode_get
   1156  * Purpose:
   1157  *      Get the urpf_mode info for the specified L3 interface
   1158  * Parameters:
   1159  *      unit      - (IN)SOC unit number.
   1160  *      vid       - (IN)Vlan id. 
   1161  *      urpf_mode       - (OUT) urpf_mode
   1162  * Returns:
   1163  *      BCM_E_XXX.
   1164  */
   1165 int
   1166 _bcm_tr2_l3_intf_urpf_mode_get(int unit, bcm_vlan_t vid, bcm_vlan_urpf_mode_t *urpf_mode)
   1167 {
   1168     _bcm_l3_ingress_intf_t iif; /* Ingress interface config.*/
   1169 
   1170     /* Input parameters sanity check. */
   1171     if ((vid > soc_mem_index_max(unit, L3_IIFm)) || 
   1172         (vid < soc_mem_index_min(unit, L3_IIFm))) {
   1173         return (BCM_E_PARAM);
   1174     }
   1175 
   1176     iif.intf_id = vid;
   1177 
   1178     BCM_IF_ERROR_RETURN(_bcm_tr_l3_ingress_interface_get(unit, NULL, &iif));
   1179 
   1180     *urpf_mode = iif.urpf_mode;
   1181     return (BCM_E_NONE);
   1182 }
   1183 
   1184 /*
   1185  * Function:
   1186  *      bcm_tr2_l3_ecmp_defragment_buffer_init
   1187  * Purpose:
   1188  *      Initialize L3 ECMP table defragmentation buffer.
   1189  * Parameters:
   1190  *      unit - (IN) SOC unit number.
   1191  * Returns:
   1192  *      BCM_E_XXX.
   1193  */
   1194 int
   1195 bcm_tr2_l3_ecmp_defragment_buffer_init(int unit)
   1196 {
   1197     if (NULL == _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]) {
   1198         _bcm_tr2_l3_ecmp_defragment_buffer_info[unit] =
   1199             sal_alloc(sizeof(_bcm_tr2_l3_ecmp_defragment_buffer_t),
   1200                     "l3 ecmp defragmentation buffer info");
   1201         if (NULL == _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]) {
   1202             return BCM_E_MEMORY;
   1203         }
   1204     }
   1205     sal_memset(_bcm_tr2_l3_ecmp_defragment_buffer_info[unit], 0,
   1206             sizeof(_bcm_tr2_l3_ecmp_defragment_buffer_t));
   1207 
   1208     return BCM_E_NONE;
   1209 }
   1210 
   1211 /*
   1212  * Function:
   1213  *      bcm_tr2_l3_ecmp_defragment_buffer_deinit
   1214  * Purpose:
   1215  *      De-initialize L3 ECMP table defragmentation buffer.
   1216  * Parameters:
   1217  *      unit - (IN) SOC unit number.
   1218  * Returns:
   1219  *      None.
   1220  */
   1221 void
   1222 bcm_tr2_l3_ecmp_defragment_buffer_deinit(int unit)
   1223 {
   1224     if (NULL != _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]) {
   1225         sal_free(_bcm_tr2_l3_ecmp_defragment_buffer_info[unit]);
   1226         _bcm_tr2_l3_ecmp_defragment_buffer_info[unit] = NULL;
   1227     }
   1228 }
   1229 
   1230 /*
   1231  * Function:
   1232  *      bcm_tr2_l3_ecmp_defragment_buffer_set
   1233  * Purpose:
   1234  *      Set L3 ECMP table defragmentation buffer.
   1235  * Parameters:
   1236  *      unit - (IN) SOC unit number.
   1237  *      size - (IN) Defragmentation buffer size.
   1238  * Returns:
   1239  *      BCM_E_XXX.
   1240  */
   1241 int
   1242 bcm_tr2_l3_ecmp_defragment_buffer_set(int unit, int size)
   1243 {
   1244     _bcm_l3_tbl_t *tbl_ptr;
   1245     int old_base_ptr, old_size;
   1246     int base_ptr;
   1247     int i, j;
   1248     int buffer_found;
   1249 
   1250     if (!soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf) &&
   1251         !soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) {
   1252         return BCM_E_UNAVAIL;
   1253     }
   1254 
   1255     L3_LOCK(unit);
   1256 
   1257     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 
   1258 
   1259     /* Free old defragmentation buffer */
   1260     old_base_ptr = _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->base_ptr;
   1261     old_size = _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->size;
   1262     if (old_size > 0) {
   1263         BCM_XGS3_L3_ENT_REF_CNT_DEC(tbl_ptr, old_base_ptr, old_size);
   1264     }
   1265 
   1266     /* Fist, attempt to find new defragmentation buffer at end of ECMP table.
   1267      * Such a buffer introduces less fragmentation than a buffer that's
   1268      * located in the middle of the ECMP table.
   1269      */
   1270     for (i = tbl_ptr->idx_max + 1 - size; i < (tbl_ptr->idx_max + 1); i++) {
   1271         if (BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, i)) {
   1272             break;
   1273         }
   1274     }
   1275 
   1276     if (i == (tbl_ptr->idx_max + 1)) {
   1277         /* An available buffer is found at end of ECMP table */
   1278         base_ptr = tbl_ptr->idx_max + 1 - size;
   1279     } else {
   1280         /* Attempt to find new defragmentation buffer in ECMP table */
   1281         buffer_found = FALSE;
   1282         for (i = tbl_ptr->idx_min; i < (tbl_ptr->idx_max + 1 - size); i++) {
   1283             for (j = i; j < (i + size); j++) {
   1284                 if (BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, j)) {
   1285                     break;
   1286                 }
   1287             }
   1288             if (j == (i + size)) {
   1289                 buffer_found = TRUE;
   1290                 break;
   1291             }
   1292         }
   1293 
   1294         if (buffer_found) {
   1295             base_ptr = i;
   1296         } else {
   1297             /* A free buffer of the requested size cannot be found.
   1298              * Restore the old buffer.
   1299              */
   1300             if (old_size > 0) {
   1301                 BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_ptr, old_base_ptr, old_size);
   1302             }
   1303 
   1304             L3_UNLOCK(unit);
   1305             return BCM_E_RESOURCE;
   1306         }
   1307     }
   1308 
   1309     BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_ptr, base_ptr, size);
   1310     _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->base_ptr = base_ptr;
   1311     _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->size = size;
   1312 
   1313     L3_UNLOCK(unit);
   1314     return BCM_E_NONE;
   1315 }
   1316 
   1317 /*
   1318  * Function:
   1319  *      bcm_tr2_l3_ecmp_defragment_buffer_get
   1320  * Purpose:
   1321  *      Get L3 ECMP table defragmentation buffer size.
   1322  * Parameters:
   1323  *      unit - (IN)  SOC unit number.
   1324  *      size - (OUT) Defragmentation buffer size.
   1325  * Returns:
   1326  *      BCM_E_XXX.
   1327  */
   1328 int
   1329 bcm_tr2_l3_ecmp_defragment_buffer_get(int unit, int *size)
   1330 {
   1331     if (!soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf) &&
   1332         !soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) {
   1333         return BCM_E_UNAVAIL;
   1334     }
   1335 
   1336     (*size) = _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->size;
   1337 
   1338     return BCM_E_NONE;
   1339 }
   1340 
   1341 /*
   1342  * Function:
   1343  *      _bcm_tr2_l3_ecmp_member_copy
   1344  * Purpose:
   1345  *      Copy ECMP table entry.
   1346  * Parameters:
   1347  *      unit - (IN)  SOC unit number.
   1348  *      src_index - (IN) Index of the entry to be copied.
   1349  *      dst_index - (IN) Destination index.
   1350  * Returns:
   1351  *      BCM_E_XXX.
   1352  */
   1353 int
   1354 _bcm_tr2_l3_ecmp_member_copy(int unit, int src_index, int dst_index)
   1355 {
   1356     ecmp_entry_t ecmp_entry;
   1357     initial_l3_ecmp_entry_t initial_ecmp_entry;
   1358 
   1359     if (src_index < 0 || src_index > soc_mem_index_max(unit, L3_ECMPm)) {
   1360         return BCM_E_PARAM;
   1361     }
   1362     if (dst_index < 0 || dst_index > soc_mem_index_max(unit, L3_ECMPm)) {
   1363         return BCM_E_PARAM;
   1364     }
   1365 
   1366     SOC_IF_ERROR_RETURN
   1367         (READ_L3_ECMPm(unit, MEM_BLOCK_ANY, src_index, &ecmp_entry));
   1368     SOC_IF_ERROR_RETURN
   1369         (WRITE_L3_ECMPm(unit, MEM_BLOCK_ALL, dst_index, &ecmp_entry));
   1370 
   1371     if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMPm)) {
   1372         SOC_IF_ERROR_RETURN
   1373             (READ_INITIAL_L3_ECMPm(unit, MEM_BLOCK_ANY, src_index,
   1374                                    &initial_ecmp_entry));
   1375         SOC_IF_ERROR_RETURN
   1376             (WRITE_INITIAL_L3_ECMPm(unit, MEM_BLOCK_ALL, dst_index,
   1377                                     &initial_ecmp_entry));
   1378     }
   1379     /* Increment reference count for ECMP table entry at dst_index */
   1380     BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ecmp), dst_index, 1);
   1381 
   1382     return BCM_E_NONE;
   1383 }
   1384 
   1385 /*
   1386  * Function:
   1387  *      _bcm_tr2_l3_ecmp_member_clear
   1388  * Purpose:
   1389  *      Clear an ECMP table entry.
   1390  * Parameters:
   1391  *      unit  - (IN)  SOC unit number.
   1392  *      index - (IN) Index of the entry to be cleared.
   1393  * Returns:
   1394  *      BCM_E_XXX.
   1395  */
   1396 int
   1397 _bcm_tr2_l3_ecmp_member_clear(int unit, int index)
   1398 {
   1399     if (index < 0 || index > soc_mem_index_max(unit, L3_ECMPm)) {
   1400         return BCM_E_PARAM;
   1401     }
   1402 
   1403     SOC_IF_ERROR_RETURN(WRITE_L3_ECMPm(unit, MEM_BLOCK_ALL, index,
   1404                 soc_mem_entry_null(unit, L3_ECMPm)));
   1405     if (!soc_feature(unit, soc_feature_post_ifp_single_stage_ecmp)) {
   1406         SOC_IF_ERROR_RETURN(WRITE_INITIAL_L3_ECMPm(unit, MEM_BLOCK_ALL, index,
   1407                     soc_mem_entry_null(unit, INITIAL_L3_ECMPm)));
   1408     }
   1409 
   1410     /* Decrement reference count for the just cleared ECMP table entry */
   1411     BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ecmp), index, 1);
   1412 
   1413     return BCM_E_NONE;
   1414 }
   1415 
   1416 /*
   1417  * Function:
   1418  *      _bcm_tr2_l3_ecmp_group_base_ptr_update
   1419  * Purpose:
   1420  *      Update the base pointer field of the given ECMP group.
   1421  * Parameters:
   1422  *      unit     - (IN) SOC unit number.
   1423  *      group    - (IN) ECMP group.
   1424  *      base_ptr - (IN) New base pointer.
   1425  * Returns:
   1426  *      BCM_E_XXX.
   1427  */
   1428 int
   1429 _bcm_tr2_l3_ecmp_group_base_ptr_update(int unit, int group, int base_ptr)
   1430 {
   1431     ecmp_count_entry_t ecmp_group_entry;
   1432     uint32 initial_ecmp_group_entry[SOC_MAX_MEM_FIELD_WORDS];
   1433     soc_mem_t initial_ecmp_group_mem;
   1434     soc_field_t base_ptr_f = INVALIDf;
   1435 
   1436     if (group < 0 || group > soc_mem_index_max(unit, L3_ECMP_COUNTm)) {
   1437         return BCM_E_PARAM;
   1438     }
   1439 
   1440     /* Read L3 ECMP group table */
   1441     SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, group,
   1442                 &ecmp_group_entry));
   1443     
   1444     /* Choose correct base pointer field */
   1445     if (soc_feature(unit, soc_feature_l3_ecmp_1k_groups)) {
   1446         uint32 ing_config_2;
   1447         uint8 ecmp_hash_16bits = 1;
   1448         if (SOC_REG_IS_VALID(unit, ING_CONFIG_2r)) {
   1449             SOC_IF_ERROR_RETURN(
   1450                 READ_ING_CONFIG_2r(unit, &ing_config_2));
   1451             ecmp_hash_16bits =
   1452                 soc_reg_field_get(unit, ING_CONFIG_2r, ing_config_2,
   1453                                   ECMP_HASH_16BITSf);
   1454         }
   1455 
   1456         if (ecmp_hash_16bits && 
   1457             soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf)) {
   1458             base_ptr_f = BASE_PTRf;
   1459         } else if (soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) {
   1460             base_ptr_f = BASE_PTR_0f;
   1461         }
   1462     } else if (soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) {
   1463         base_ptr_f = BASE_PTR_0f;
   1464     } else {
   1465         base_ptr_f = BASE_PTRf;
   1466     }
   1467 
   1468     /* Modify base pointer */
   1469     if (base_ptr_f == BASE_PTRf) {
   1470         soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_group_entry,
   1471                 BASE_PTRf, base_ptr);
   1472     } else {
   1473         soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_group_entry,
   1474                 BASE_PTR_0f, base_ptr);
   1475         soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_group_entry,
   1476                 BASE_PTR_1f, base_ptr);
   1477         soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_group_entry,
   1478                 BASE_PTR_2f, base_ptr);
   1479         soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_group_entry,
   1480                 BASE_PTR_3f, base_ptr);
   1481     }
   1482 
   1483     /* Write L3 ECMP group table */
   1484     SOC_IF_ERROR_RETURN(WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL, group,
   1485                 &ecmp_group_entry));
   1486 
   1487 #ifdef BCM_TOMAHAWK3_SUPPORT
   1488     if (soc_feature(unit, soc_feature_post_ifp_single_stage_ecmp)) {
   1489         return BCM_E_NONE;
   1490     }
   1491 #endif
   1492 
   1493     /* Read Initial L3 ECMP group table */
   1494     if (soc_mem_is_valid(unit, INITIAL_L3_ECMP_COUNTm)) {
   1495         initial_ecmp_group_mem = INITIAL_L3_ECMP_COUNTm;
   1496     } else if (soc_mem_is_valid(unit, INITIAL_L3_ECMP_GROUPm)) {
   1497         initial_ecmp_group_mem = INITIAL_L3_ECMP_GROUPm;
   1498     } else {
   1499         return BCM_E_INTERNAL;
   1500     }
   1501     SOC_IF_ERROR_RETURN(soc_mem_read(unit, initial_ecmp_group_mem,
   1502                 MEM_BLOCK_ANY, group, &initial_ecmp_group_entry));
   1503 
   1504     /* Modify base pointer */
   1505     if (base_ptr_f == BASE_PTRf) {
   1506         soc_mem_field32_set(unit, initial_ecmp_group_mem,
   1507                 &initial_ecmp_group_entry, BASE_PTRf, base_ptr);
   1508     } else {
   1509         soc_mem_field32_set(unit, initial_ecmp_group_mem,
   1510                 &initial_ecmp_group_entry, BASE_PTR_0f, base_ptr);
   1511         soc_mem_field32_set(unit, initial_ecmp_group_mem,
   1512                 &initial_ecmp_group_entry, BASE_PTR_1f, base_ptr);
   1513         soc_mem_field32_set(unit, initial_ecmp_group_mem,
   1514                 &initial_ecmp_group_entry, BASE_PTR_2f, base_ptr);
   1515         soc_mem_field32_set(unit, initial_ecmp_group_mem,
   1516                 &initial_ecmp_group_entry, BASE_PTR_3f, base_ptr);
   1517     }
   1518 
   1519     /* Write Initial L3 ECMP group table */
   1520     SOC_IF_ERROR_RETURN(soc_mem_write(unit, initial_ecmp_group_mem,
   1521                 MEM_BLOCK_ALL, group, &initial_ecmp_group_entry));
   1522 
   1523     return BCM_E_NONE;
   1524 }
   1525 
   1526 /*
   1527  * Function:
   1528  *      bcm_tr2_l3_ecmp_defragment_no_lock
   1529  * Purpose:
   1530  *      Defragment L3 ECMP table. This procedure does not obtain
   1531  *      L3 lock. It's assumed that L3 lock was obtained before
   1532  *      invoking this procedure. 
   1533  * Parameters:
   1534  *      unit - (IN)  SOC unit number.
   1535  *      ecmp_level - (IN) Ecmp Level
   1536  *                   Default value is 0, entire ECMP table is de-fragmented
   1537  *                   ecmp_level 1 and 2 is applicable to Hierarchical Ecmp feature,
   1538  *                   only level 1 or level 2 Ecmp table is defragmented
   1539  * Returns:
   1540  *      BCM_E_XXX.
   1541  */
   1542 int
   1543 bcm_tr2_l3_ecmp_defragment_no_lock(int unit, int ecmp_level)
   1544 {
   1545     _bcm_l3_tbl_t *ecmp_group_tbl_ptr;
   1546     soc_defragment_block_t *block_array;
   1547     soc_defragment_block_t reserved_block;
   1548     soc_defragment_member_op_t member_op;
   1549     soc_defragment_group_op_t group_op;
   1550     int block_count;
   1551     int i, ecmp_group_idx_increment;
   1552     int rv;
   1553     int max_paths;
   1554     soc_field_t base_ptr_f;
   1555     int base_ptr = 0;
   1556     ecmp_count_entry_t ecmp_group_entry;
   1557     int min_idx = 0;
   1558     int max_idx = 0;
   1559     int ecmp_tbl_size = 0;
   1560     int free_base_ptr = 0;
   1561 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_RIOT_SUPPORT) || \
   1562     defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   1563     int vp_lag_base_idx = 0;
   1564 #endif
   1565 #if defined(BCM_TOMAHAWK_SUPPORT)
   1566     int hecmp_enable = 0;
   1567     int ecmp_min_idx = 0;
   1568     int ecmp_max_idx = 0;
   1569 #endif
   1570 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   1571     _bcm_l3_tbl_t *ecmp_tbl_ptr;
   1572 #endif
   1573 
   1574     if (!soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf) &&
   1575         !soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) {
   1576         return BCM_E_UNAVAIL;
   1577     }
   1578 
   1579 #if defined(BCM_TOMAHAWK_SUPPORT)
   1580     if (soc_feature(unit, soc_feature_hierarchical_ecmp) &&
   1581        (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == ecmp_mode_hierarchical)) {
   1582         hecmp_enable = 1;
   1583     }
   1584 #endif
   1585 
   1586     ecmp_group_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
   1587 
   1588     if (ecmp_level == 1) {
   1589 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   1590         if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) {
   1591             block_array = sal_alloc(sizeof(soc_defragment_block_t) *
   1592                  (ecmp_group_tbl_ptr->idx_maxused -
   1593                   ecmp_group_tbl_ptr->split_idx + 1),
   1594                  "defragment block array");
   1595         } else
   1596 #endif
   1597         {
   1598             /*
   1599              * Allocate block array of size equal to size of overlay table
   1600              * since we do not keep track of the highest used index at Level 1
   1601              */
   1602             block_array = sal_alloc(sizeof(soc_defragment_block_t) *
   1603                  (ecmp_group_tbl_ptr->idx_max + 1), "defragment block array");
   1604         }
   1605     } else if (ecmp_level == 2) {
   1606 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   1607         if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) {
   1608             block_array = sal_alloc(sizeof(soc_defragment_block_t) *
   1609                  (ecmp_group_tbl_ptr->split_maxused + 1),
   1610                  "defragment block array");
   1611         } else
   1612 #endif
   1613 #if defined(BCM_TOMAHAWK_SUPPORT)
   1614         if (hecmp_enable) {
   1615             block_array = sal_alloc(sizeof(soc_defragment_block_t) *
   1616                                     (ecmp_group_tbl_ptr->idx_maxused + 1),
   1617                                     "defragment block array");
   1618         } else
   1619 #endif /* BCM_TOMAHAWK_SUPPORT */
   1620         {
   1621             /* Allocate block array of size equal to number of used entries at level 2 */
   1622             block_array = sal_alloc(sizeof(soc_defragment_block_t) *
   1623                  (ecmp_group_tbl_ptr->idx_maxused -
   1624                   ecmp_group_tbl_ptr->idx_min + 1),
   1625                  "defragment block array");
   1626         }
   1627     } else {
   1628         block_array = sal_alloc(sizeof(soc_defragment_block_t) *
   1629              (ecmp_group_tbl_ptr->idx_maxused + 1), "defragment block array");
   1630     }
   1631 
   1632     /* Get the ECMP table base_ptr and max group size of all the active
   1633      * ECMP groups
   1634      */
   1635     block_count = 0;
   1636     if (SOC_IS_TRIUMPH3(unit) || BCM_XGS3_L3_MAX_ECMP_MODE(unit)) {
   1637         ecmp_group_idx_increment = _BCM_SINGLE_WIDE;
   1638     } else {
   1639         ecmp_group_idx_increment = _BCM_DOUBLE_WIDE;
   1640     }
   1641 
   1642     if (soc_feature(unit, soc_feature_l3_ecmp_1k_groups)) {
   1643         uint32 ing_config_2;
   1644         uint8 ecmp_hash_16bits = 1;
   1645         if (SOC_REG_IS_VALID(unit, ING_CONFIG_2r)) {
   1646             rv = READ_ING_CONFIG_2r(unit, &ing_config_2);
   1647             if (SOC_FAILURE(rv)) {
   1648                 sal_free(block_array);
   1649                 return rv;
   1650             }
   1651             ecmp_hash_16bits =
   1652                 soc_reg_field_get(unit, ING_CONFIG_2r, ing_config_2,
   1653                                   ECMP_HASH_16BITSf);
   1654         }
   1655 
   1656         if (ecmp_hash_16bits && 
   1657             soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf)) {
   1658             base_ptr_f = BASE_PTRf;
   1659         } else {
   1660             base_ptr_f = BASE_PTR_0f;
   1661         }
   1662     } else if (soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) {
   1663         base_ptr_f = BASE_PTR_0f;
   1664     } else {
   1665         base_ptr_f = BASE_PTRf;
   1666     }
   1667     
   1668     if (ecmp_level == 2) {
   1669         min_idx = ecmp_group_tbl_ptr->idx_min;
   1670         max_idx = ecmp_group_tbl_ptr->idx_maxused;
   1671         free_base_ptr = min_idx;
   1672 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   1673         if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) {
   1674             max_idx = ecmp_group_tbl_ptr->split_maxused;
   1675         } else 
   1676 #endif
   1677 #if defined(BCM_TOMAHAWK_SUPPORT)
   1678         if (hecmp_enable) {
   1679             min_idx = soc_mem_index_min(unit, L3_ECMP_COUNTm);
   1680             max_idx = ecmp_group_tbl_ptr->idx_maxused;
   1681             ecmp_min_idx = soc_mem_index_count(unit, L3_ECMPm)/2;
   1682             ecmp_max_idx = soc_mem_index_count(unit, L3_ECMPm);
   1683             free_base_ptr = ecmp_min_idx;
   1684         } else 
   1685 #endif /* BCM_TOMAHAWK_SUPPORT */
   1686         {
   1687             free_base_ptr = soc_mem_index_count(unit, L3_ECMPm)/2;
   1688         }
   1689         ecmp_tbl_size = soc_mem_index_count(unit, L3_ECMPm)/2;
   1690     } else if (ecmp_level == 1) {
   1691 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   1692         if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) {
   1693             min_idx = ecmp_group_tbl_ptr->split_idx;
   1694             max_idx = ecmp_group_tbl_ptr->idx_maxused;
   1695             ecmp_tbl_size = soc_mem_index_count(unit, L3_ECMPm);
   1696             if (soc_feature(unit, soc_feature_td3_style_riot)) {
   1697                 ecmp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp);
   1698                 free_base_ptr = ecmp_tbl_ptr->split_idx;
   1699             } else {
   1700                 free_base_ptr = soc_mem_index_count(unit, L3_ECMPm)/2;
   1701             }
   1702             vp_lag_base_idx = min_idx;
   1703         } else 
   1704 #endif
   1705 #if defined(BCM_TOMAHAWK_SUPPORT)
   1706         if (hecmp_enable) {
   1707             min_idx = ecmp_group_tbl_ptr->idx_min;
   1708             max_idx = ecmp_group_tbl_ptr->idx_max;
   1709             ecmp_min_idx = 0;
   1710             ecmp_max_idx = soc_mem_index_max(unit, L3_ECMPm)/2;
   1711             free_base_ptr = ecmp_min_idx;
   1712             ecmp_tbl_size = soc_mem_index_count(unit, L3_ECMPm)/2;
   1713         } else
   1714 #endif /* BCM_TOMAHAWK_SUPPORT */
   1715         {
   1716             min_idx = ecmp_group_tbl_ptr->idx_min;
   1717             /*
   1718              * Using table max index since we do not keep track of highest
   1719              * index used at this level 1
   1720              */
   1721             max_idx = ecmp_group_tbl_ptr->idx_max;
   1722             free_base_ptr = 0;
   1723             ecmp_tbl_size = soc_mem_index_count(unit, L3_ECMPm)/2;
   1724         }
   1725     } else {
   1726         min_idx = ecmp_group_tbl_ptr->idx_min;
   1727         max_idx = ecmp_group_tbl_ptr->idx_maxused;
   1728         ecmp_tbl_size = soc_mem_index_count(unit, L3_ECMPm);
   1729         free_base_ptr = 0;
   1730     }
   1731 
   1732     for (i = min_idx; i <= max_idx; i += ecmp_group_idx_increment) {
   1733 
   1734 #ifdef BCM_TRIDENT2_SUPPORT
   1735         /* Skip vp_lag checks at level 2 as vp lag entries are only at level 1 */
   1736         if (soc_feature(unit, soc_feature_vp_lag) && (ecmp_level != 2)) {
   1737             int is_vp_lag, is_used, has_member;
   1738             rv = bcm_td2_vp_lag_status_get(unit, i - vp_lag_base_idx,
   1739                     &is_vp_lag, &is_used, &has_member);
   1740             if (BCM_FAILURE(rv)) {
   1741                 sal_free(block_array);
   1742                 return rv;
   1743             }
   1744             if (is_vp_lag) {
   1745                 /* Skip VP LAG entries */
   1746                 continue;
   1747             }
   1748         }
   1749 #endif /* BCM_TRIDENT2_SUPPORT */
   1750 
   1751         if (!BCM_XGS3_L3_ENT_REF_CNT(ecmp_group_tbl_ptr, i)) {
   1752             continue;
   1753         }
   1754 
   1755         rv = READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, i, &ecmp_group_entry);
   1756         if (SOC_FAILURE(rv)) {
   1757             sal_free(block_array);
   1758             return rv;
   1759         }
   1760         base_ptr =
   1761             soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_group_entry, base_ptr_f);
   1762         rv = bcm_xgs3_l3_egress_ecmp_max_paths_get(unit,
   1763                 i + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit), NULL, &max_paths);
   1764         if (BCM_FAILURE(rv)) {
   1765             sal_free(block_array);
   1766             return rv;
   1767         }
   1768 
   1769 #if defined(BCM_TOMAHAWK_SUPPORT)
   1770         /* In HECMP mode, there are 3 kinds of ECMP_GROUP, and they can be
   1771          * coexisted, so we need to handle mixed ecmp group case;
   1772          *   ecmp_group_flags:
   1773          *       0       : ecmp_index  [0  ~ 16K-1]  nh-hop
   1774          *       OVERLAY : ecmp_index  [0  ~ 8K-1]   ecmp_grp_ptr, Level 1
   1775          *       UNDERLAY: ecmp_index  [8K ~ 16K-1]  nh-hop
   1776          *   ecmp_index range between [8K ~ 16K-1] can't be ecmp_grp_ptr.
   1777          *
   1778          * So for a given ecmp_index in range [8K ~ 16K-1], the ecmp can
   1779          * be either level 1 group or level 2 group.
   1780  */
   1781         if (hecmp_enable) {
   1782             /* Adjust free_base_ptr when group member across the boundaries */
   1783             if (ecmp_min_idx > 0 &&
   1784                 base_ptr < ecmp_min_idx &&
   1785                 (base_ptr + max_paths) > ecmp_min_idx) {
   1786                 free_base_ptr = (base_ptr + max_paths);
   1787                 continue;
   1788             }
   1789 
   1790             /* Ignore out of range groups */
   1791             if (base_ptr < ecmp_min_idx || base_ptr > ecmp_max_idx) {
   1792                 continue;
   1793             }
   1794 
   1795             if ((base_ptr + max_paths) > ecmp_max_idx) {
   1796                 continue;
   1797             }
   1798         }
   1799 #endif
   1800 
   1801         block_array[block_count].base_ptr = base_ptr;
   1802         block_array[block_count].size = max_paths;
   1803         block_array[block_count].group = i;
   1804         block_count++;
   1805     }
   1806 
   1807 #ifdef BCM_TRIDENT2_SUPPORT
   1808     /* In Trident2, the VP LAG and ECMP features share the same group and
   1809      * member tables. Defragmentation of the member table also requires
   1810      * the group base_ptr and group size of all the active VP LAGs.
   1811      */
   1812     if (soc_feature(unit, soc_feature_vp_lag)) {
   1813         int vp_id_min = -1, vp_id_max = -1;
   1814         int min_vp_lag_id, max_vp_lag_id;
   1815         int is_vp_lag, is_used, has_member;
   1816 
   1817         rv = _bcm_esw_trunk_chip_info_vp_resource_get(unit, &vp_id_min,
   1818                                                       &vp_id_max, NULL);
   1819         if (BCM_FAILURE(rv)) {
   1820             sal_free(block_array);
   1821             return rv;
   1822         }
   1823         if (vp_id_min != -1 && vp_id_max != -1) {
   1824             min_vp_lag_id = 0;
   1825             max_vp_lag_id = vp_id_max - vp_id_min;
   1826             for (i = min_vp_lag_id; i <= max_vp_lag_id; i++) {
   1827                 rv = bcm_td2_vp_lag_status_get(unit, i, &is_vp_lag, &is_used,
   1828                         &has_member);
   1829                 if (BCM_FAILURE(rv)) {
   1830                     sal_free(block_array);
   1831                     return rv;
   1832                 }
   1833                 if (!is_vp_lag) {
   1834                     sal_free(block_array);
   1835                     return BCM_E_INTERNAL;
   1836                 }
   1837                 if (!is_used) {
   1838                     continue;
   1839                 }
   1840                 if (!has_member) {
   1841                     continue;
   1842                 }
   1843 
   1844                 rv = READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, i + vp_lag_base_idx,
   1845                         &ecmp_group_entry);
   1846                 if (SOC_FAILURE(rv)) {
   1847                     sal_free(block_array);
   1848                     return rv;
   1849                 }
   1850                 block_array[block_count].base_ptr =
   1851                     soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_group_entry,
   1852                             BASE_PTRf);
   1853                 block_array[block_count].size = 1 +
   1854                     soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_group_entry,
   1855                             COUNTf);
   1856                 block_array[block_count].group = i + vp_lag_base_idx;
   1857                 block_count++;
   1858             }
   1859         }
   1860     }
   1861 #endif /* BCM_TRIDENT2_SUPPORT */
   1862 
   1863     /* Get the defragmentation buffer base_ptr and size */
   1864     reserved_block.base_ptr =
   1865         _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->base_ptr;
   1866     reserved_block.size =
   1867         _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->size;
   1868     reserved_block.group = -1;
   1869 
   1870     /* Set functions to copy and clear ECMP member entries */
   1871     member_op.member_copy = _bcm_tr2_l3_ecmp_member_copy;
   1872     member_op.member_clear = _bcm_tr2_l3_ecmp_member_clear;
   1873 
   1874     /* Set function to update ECMP group's base_ptr */
   1875     group_op.group_base_ptr_update = _bcm_tr2_l3_ecmp_group_base_ptr_update;
   1876 
   1877     /* Call defragmentation routine */
   1878     rv = soc_defragment(unit, block_count, block_array, &reserved_block,
   1879             ecmp_tbl_size, &member_op, &group_op, free_base_ptr);
   1880     if (SOC_FAILURE(rv)) {
   1881         sal_free(block_array);
   1882         return rv;
   1883     }
   1884 
   1885     sal_free(block_array);
   1886     return BCM_E_NONE;
   1887 }
   1888 
   1889 /*
   1890  * Function:
   1891  *      bcm_tr2_l3_ecmp_defragment
   1892  * Purpose:
   1893  *      Defragment L3 ECMP table.
   1894  * Parameters:
   1895  *      unit - (IN)  SOC unit number.
   1896  * Returns:
   1897  *      BCM_E_XXX.
   1898  */
   1899 int
   1900 bcm_tr2_l3_ecmp_defragment(int unit)
   1901 {
   1902     int rv;
   1903 
   1904     L3_LOCK(unit);
   1905 
   1906 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   1907     if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) {
   1908         rv = bcm_tr2_l3_ecmp_defragment_no_lock(unit, 2);
   1909 
   1910         if (BCM_FAILURE(rv)){
   1911             L3_UNLOCK(unit);
   1912             return rv;
   1913         }
   1914         rv = bcm_tr2_l3_ecmp_defragment_no_lock(unit, 1);
   1915         if (BCM_FAILURE(rv)){
   1916             L3_UNLOCK(unit);
   1917             return rv;
   1918         }
   1919 
   1920     } else
   1921 #endif
   1922     {
   1923         rv = bcm_tr2_l3_ecmp_defragment_no_lock(unit, 0);
   1924     }
   1925 
   1926     L3_UNLOCK(unit);
   1927 
   1928     return rv;
   1929 }
   1930 
   1931 #ifdef BCM_WARM_BOOT_SUPPORT
   1932 
   1933 /*
   1934  * Function:
   1935  *      bcm_tr2_l3_ecmp_defragment_buffer_wb_alloc_size_get
   1936  * Purpose:
   1937  *      Get level 2 warm boot scache size for ECMP defragmentation
   1938  *      buffer parameters.
   1939  * Parameters:
   1940  *      unit - (IN) SOC unit number.
   1941  *      size - (OUT) Allocation size.
   1942  * Returns:
   1943  *      BCM_E_XXX
   1944  */
   1945 int
   1946 bcm_tr2_l3_ecmp_defragment_buffer_wb_alloc_size_get(int unit, int *size) 
   1947 {
   1948     *size = 0;
   1949 
   1950     /* Allocate for buffer base_ptr */
   1951     *size += sizeof(int);
   1952 
   1953     /* Allocate for buffer size */
   1954     *size += sizeof(int);
   1955 
   1956     return BCM_E_NONE;
   1957 }
   1958 
   1959 /*
   1960  * Function:
   1961  *      bcm_tr2_l3_ecmp_defragment_buffer_sync
   1962  * Purpose:
   1963  *      Store ECMP defragmentation buffer parameters into scache.
   1964  * Parameters:
   1965  *      unit - (IN) SOC unit number.
   1966  *      scache_ptr - (IN/OUT) Scache pointer
   1967  * Returns:
   1968  *      BCM_E_XXX
   1969  */
   1970 int
   1971 bcm_tr2_l3_ecmp_defragment_buffer_sync(int unit, uint8 **scache_ptr) 
   1972 {
   1973     int value;
   1974 
   1975     /* Store buffer base_ptr */
   1976     value = _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->base_ptr;
   1977     sal_memcpy((*scache_ptr), &value, sizeof(int));
   1978     (*scache_ptr) += sizeof(int);
   1979 
   1980     /* Store buffer base_ptr */
   1981     value = _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->size;
   1982     sal_memcpy((*scache_ptr), &value, sizeof(int));
   1983     (*scache_ptr) += sizeof(int);
   1984 
   1985     return BCM_E_NONE;
   1986 }
   1987 
   1988 /*
   1989  * Function:
   1990  *      bcm_tr2_l3_ecmp_defragment_buffer_recover
   1991  * Purpose:
   1992  *      Recover ECMP defragment buffer parameters from scache.
   1993  * Parameters:
   1994  *      unit - (IN) SOC unit number.
   1995  *      scache_ptr - (IN/OUT) Scache pointer
   1996  * Returns:
   1997  *      BCM_E_XXX
   1998  */
   1999 int
   2000 bcm_tr2_l3_ecmp_defragment_buffer_recover(int unit, uint8 **scache_ptr) 
   2001 {
   2002     int value;
   2003 
   2004     /* Recover defragmentation buffer base_ptr */
   2005     sal_memcpy(&value, (*scache_ptr), sizeof(int));
   2006     _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->base_ptr = value;
   2007     (*scache_ptr) += sizeof(int);
   2008 
   2009     /* Recover defragmentation buffer size */
   2010     sal_memcpy(&value, (*scache_ptr), sizeof(int));
   2011     _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->size = value;
   2012     (*scache_ptr) += sizeof(int);
   2013 
   2014     return BCM_E_NONE;
   2015 }
   2016 
   2017 #endif /* BCM_WARM_BOOT_SUPPORT */
   2018 
   2019 #ifndef BCM_SW_STATE_DUMP_DISABLE
   2020 /*
   2021  * Function:
   2022  *     bcm_tr2_l3_ecmp_defragment_buffer_sw_dump
   2023  * Purpose:
   2024  *     Displays ECMP defragmentation buffer information maintained by software.
   2025  * Parameters:
   2026  *     unit - Device unit number
   2027  * Returns:
   2028  *     None
   2029  */
   2030 void
   2031 bcm_tr2_l3_ecmp_defragment_buffer_sw_dump(int unit)
   2032 {
   2033     LOG_CLI((BSL_META_U(unit,
   2034                         "  ECMP Defragment Buffer: base_ptr = %d, size = %d\n"),
   2035              _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->base_ptr,
   2036              _bcm_tr2_l3_ecmp_defragment_buffer_info[unit]->size));
   2037     return;
   2038 }
   2039 #endif /* BCM_SW_STATE_DUMP_DISABLE */
   2040 
   2041 #else /* BCM_TRIUMPH2_SUPPORT && INCLUDE_L3 */
   2042 int bcm_esw_triumph2_l3_not_empty;
   2043 #endif /* BCM_TRIUMPH2_SUPPORT && INCLUDE_L3 */
   2044