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


      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:     Firebolt L3 function implementations
      9  */
     10 #include <shared/bsl.h>
     11 
     12 #include <soc/defs.h>
     13 #ifdef INCLUDE_L3
     14 
     15 #include <assert.h>
     16 #include <sal/core/libc.h>
     17 #include <shared/util.h>
     18 #if defined(BCM_FIREBOLT_SUPPORT)
     19 #include <soc/cm.h>
     20 #include <soc/drv.h>
     21 #include <soc/scache.h>
     22 #include <soc/register.h>
     23 #include <soc/memory.h>
     24 #include <soc/l3x.h>
     25 #include <soc/lpm.h>
     26 #include <soc/defragment.h>
     27 #include <soc/mcm/memregs.h>
     28 #include <soc/format.h>
     29 
     30 #ifdef ALPM_ENABLE
     31 #include <soc/alpm.h>
     32 #include <soc/esw/alpm_int.h>
     33 #endif /* ALPM_ENABLE */
     34 #include <soc/tnl_term.h>
     35 
     36 #include <bcm/l3.h>
     37 #include <bcm/error.h>
     38 
     39 #include <bcm_int/esw/mbcm.h>
     40 #include <bcm_int/esw/firebolt.h>
     41 #if defined(BCM_TRX_SUPPORT)
     42 #include <bcm_int/esw/trx.h>
     43 #include <bcm_int/esw/virtual.h>
     44 #endif /* BCM_TRX_SUPPORT */
     45 #ifdef BCM_TRIUMPH_SUPPORT
     46 #include <bcm_int/esw/triumph.h>
     47 #include <bcm_int/esw/mpls.h>
     48 #endif /* BCM_TRIUMPH_SUPPORT*/
     49 #ifdef BCM_SCORPION_SUPPORT
     50 #include <bcm_int/esw/scorpion.h>
     51 #endif /* BCM_SCORPION_SUPPORT*/
     52 #if defined(BCM_TRIUMPH2_SUPPORT)
     53 #include <bcm_int/esw/triumph2.h>
     54 #endif /* BCM_TRIUMPH2_SUPPORT */
     55 #if defined(BCM_TRIUMPH3_SUPPORT)
     56 #include <bcm_int/esw/triumph3.h>
     57 #endif /* BCM_TRIUMPH2_SUPPORT */
     58 #if defined(BCM_HURRICANE_SUPPORT) || defined(BCM_HURRICANE2_SUPPORT)
     59 #include <bcm_int/esw/hurricane.h>
     60 #endif /* BCM_HURRICANE_SUPPORT*/
     61 #if defined(BCM_HURRICANE2_SUPPORT)
     62 #include <soc/hurricane2.h>
     63 #include <bcm_int/esw/hurricane2.h>
     64 #endif /* BCM_HURRICANE2_SUPPORT*/
     65 #if defined(BCM_TRIDENT_SUPPORT)
     66 #include <bcm_int/esw/trident.h>
     67 #endif /* BCM_TRIDENT_SUPPORT*/
     68 #if defined(BCM_TRIDENT2_SUPPORT)
     69 #include <soc/trident2.h>
     70 #include <soc/mem.h>
     71 #include <bcm_int/esw/trident2.h>
     72 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
     73 #include <bcm_int/esw/trident3.h>
     74 #endif
     75 #if defined(BCM_TRIDENT3_SUPPORT)
     76 #include <bcm_int/esw/flow.h>
     77 #include <soc/esw/flow_db.h>
     78 #endif /* BCM_TRIDENT3_SUPPORT*/
     79 #include <bcm_int/esw/nat.h>
     80 #include <bcm_int/esw/qos.h>
     81 #endif /* BCM_TRIDENT_SUPPORT*/
     82 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
     83 #include <soc/esw/ecmp.h>
     84 #endif /*  SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
     85 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
     86 #include <bcm_int/esw/trident2plus.h>
     87 #endif /* BCM_TRIDENT2PLUS_SUPPORT*/
     88 #if defined(BCM_TRIUMPH3_SUPPORT)
     89 #include <bcm_int/esw/triumph3.h>
     90 #endif /* BCM_TRIUMPH3_SUPPORT*/
     91 #if defined(BCM_KATANA_SUPPORT)
     92 #include <bcm_int/esw/katana.h>
     93 #endif /* BCM_KATANA_SUPPORT */
     94 #if defined(BCM_KATANA2_SUPPORT)
     95 #include <bcm_int/esw/katana2.h>
     96 #endif
     97 #if defined(BCM_SABER2_SUPPORT)
     98 #include <bcm_int/esw/saber2.h>
     99 #endif
    100 #if defined(BCM_TOMAHAWK_SUPPORT)
    101 #include <bcm_int/esw/tomahawk.h>
    102 #endif /* BCM_TOMAHAWK_SUPPORT */
    103 #if defined(BCM_HURRICANE3_SUPPORT)
    104 #include <bcm_int/esw/hurricane3.h>
    105 #endif /* BCM_HURRICANE3_SUPPORT */
    106 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
    107 #include <soc/trident2.h>
    108 #include <bcm_int/esw/xgs5.h>
    109 #endif /* BCM_TRIDENT2PLUS_SUPPORT */
    110 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
    111 #include <bcm_int/esw/tomahawk2.h>
    112 #endif /* BCM_TOMAHAWK2_SUPPORT */
    113 #if defined(BCM_TOMAHAWK3_SUPPORT)
    114 #include <soc/tomahawk3.h>
    115 #include <bcm_int/esw/tomahawk3.h>
    116 #include <bcm_int/esw/alpm_th3_acc.h>
    117 #endif /* BCM_TOMAHAWK3_SUPPORT */
    118 #if defined(BCM_GREYHOUND2_SUPPORT)
    119 #include <bcm_int/esw/greyhound2.h>
    120 #endif /* BCM_GREYHOUND2_SUPPORT */
    121 
    122 #include <bcm_int/esw/l3.h>
    123 #ifdef ALPM_ENABLE
    124 #include <bcm_int/esw/alpm.h>
    125 #include <bcm_int/esw/alpm_util.h>
    126 #endif
    127 #include <bcm_int/esw/xgs3.h>
    128 #include <bcm_int/esw/stack.h>
    129 #include <soc/lpm.h>
    130 #ifdef BCM_WARM_BOOT_SUPPORT
    131 #include <bcm_int/esw/switch.h>
    132 #if defined(BCM_TRX_SUPPORT)
    133 #include <bcm_int/esw/field.h>
    134 #endif /* BCM_TRX_SUPPORT */
    135 #endif /* BCM_WARM_BOOT_SUPPORT */
    136 #include <bcm_int/common/multicast.h>
    137 #include <bcm_int/esw_dispatch.h>
    138 #include <bcm_int/esw/failover.h>
    139 
    140 #include <bcm_int/esw/lpmv6.h>
    141 #include <bcm_int/esw/ecn.h>
    142 #include <bcm_int/esw/ipmc.h>
    143 
    144 #if defined(BCM_KATANA_SUPPORT)
    145 #define   EH_TAG_TYPE_NONE             0
    146 #define   EH_TAG_TYPE_EXPLICT_QUEUE    1
    147 #define   EH_TAG_TYPE_ING_QUEUE_MAP    2
    148 #endif
    149 
    150 /* 16 internal prio * 4 internal colors */
    151 #define _BCM_TNL_DSCP_MAP_TBL_SIZE 64
    152 
    153 #define L3_IF_ERROR_CLEANUP_ELSE_RETURN(op) \
    154     do {if ((err_code = (op)) < 0) {goto cleanup;} \
    155 	else {return err_code;} } while(0)
    156 
    157 #define L3_IF_ERROR_CLEANUP(op) \
    158     do {if ((err_code = (op)) < 0) {goto cleanup;} } while(0)
    159 
    160 #define L3_ING_IF_MIN(_unit_, _idx_)\
    161     if (soc_feature(unit, soc_feature_l3_iif_under_4k)) {\
    162         /* L3_IIFm unable to reserved first 4K for mapping to 4K VLAN. */\
    163         if (soc_feature(unit, soc_feature_l3_iif_zero_invalid)) {\
    164             _idx_ = 1;\
    165         } else {\
    166             _idx_ = 0;\
    167         }\
    168     } else {\
    169         if (!BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(_unit_)) {\
    170             _idx_ = BCM_VLAN_MAX + 1;\
    171         } else {\
    172             if (soc_feature(unit, soc_feature_l3_iif_zero_invalid)) {\
    173                 _idx_ = 1;\
    174             } else {\
    175                 _idx_ = 0;\
    176             }\
    177         }\
    178     }    
    179 
    180 
    181 typedef uint32 l3_max_entry_t[SOC_MAX_MEM_WORDS];
    182 
    183 _bcm_l3_module_data_t *l3_module_data[BCM_MAX_NUM_UNITS] = { 0 };
    184 #define L3_INFO(_unit_)   (&_bcm_l3_bk_info[_unit_])
    185 
    186 extern int ecmp_mode_hierarchical;
    187 extern int ecmp_mode_single;
    188 /* per ecmp group enhanced hashing enabled info  */
    189 #ifdef BCM_TRIDENT3_SUPPORT
    190 uint8  ecmp_grp_enhanced_hashing[BCM_MAX_NUM_UNITS][4096];
    191 #endif
    192 
    193 #if defined(BCM_TRIDENT3_SUPPORT) && defined(BCM_WARM_BOOT_SUPPORT)
    194 extern int _bcm_td3_l2_change_fields_reinit(int unit);
    195 #endif
    196 
    197 /* Functions prototypes. */
    198 STATIC int _bcm_xgs3_l3_hw_op_init(int unit);
    199 STATIC int _bcm_xgs3_tnl_init_hash_calc(int unit, void *buf, uint16 *hash);
    200 STATIC int _bcm_th3_lpm_key_init(int unit, _bcm_defip_cfg_t *lpm_cfg,
    201                      uint32 *lpm_entry);
    202 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \
    203     defined(BCM_HAWKEYE_SUPPORT)
    204 STATIC int _bcm_rp_l3_deinit(int unit);
    205 STATIC int _bcm_rp_l3_init(int unit);
    206 #ifdef BCM_WARM_BOOT_SUPPORT
    207 static int _bcm_rp_l3_group_reload(int unit, bcm_field_group_t group,
    208     void *user_data);
    209 #endif
    210 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */
    211 #ifdef BCM_FIREBOLT_SUPPORT
    212 STATIC int _bcm_fb_nh_intf_is_tnl_update(int unit, bcm_if_t intf, int
    213                                          tunnel_id);
    214 STATIC void _bcm_fb_l3_ipmc_ent_init(int unit, uint32 *buf_p,
    215                                      _bcm_l3_cfg_t *l3cfg);
    216 #ifdef BCM_TRIDENT2_SUPPORT
    217 STATIC int _bcm_fb_l3_intf_nat_realm_id_set(int unit,
    218                                             _bcm_l3_intf_cfg_t *intf_info);
    219 STATIC int _bcm_fb_l3_intf_nat_realm_id_get(int unit,
    220                                             _bcm_l3_intf_cfg_t *intf_info);
    221 #endif /* BCM_TRIDENT2_SUPPORT */
    222 #endif /* BCM_FIREBOLT_SUPPORT */
    223 
    224 /* Forward declarations (defined below) */
    225 int _bcm_xgs3_l3_ingress_interface_add(int unit, _bcm_l3_ingress_intf_t *iif) ;
    226 int _bcm_xgs3_l3_ingress_interface_delete(int unit, int intf_id) ;
    227 int _bcm_xgs3_l3_ingress_interface_get(int unit, _bcm_l3_ingress_intf_t *iif);
    228 STATIC void _bcm_fb_mem_ip6_defip_lwr_set(int unit, void *lpm_key,
    229                                           _bcm_defip_cfg_t *lpm_cfg);
    230 STATIC int _bcm_fb_lpm_upr_ent_init(int unit, _bcm_defip_cfg_t *lpm_cfg,
    231                                     uint32 *lpm_entry);
    232 
    233 #ifdef BCM_WARM_BOOT_SUPPORT
    234 STATIC int _bcm_xgs3_l3_ecmp_reinit(int unit, int ecmp_max_paths, int *ecmp_grp_refcnt);
    235 #endif /*BCM_WARM_BOOT_SUPPORT*/
    236 STATIC int _bcm_xgs3_l3_tnl_term_entry_parse(int unit, soc_tunnel_term_t *entry,
    237                                              bcm_tunnel_terminator_t *tnl_info);
    238 
    239 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \
    240     defined(BCM_HAWKEYE_SUPPORT)
    241 /* Forward declaration for rule shift. */
    242 STATIC int _bcm_rp_lpm_entry_remove(int unit, int rule_idx);
    243 #endif
    244 #ifdef BCM_TRIDENT3_SUPPORT
    245 STATIC int _bcmi_l3_intf_overlay_valid(int unit, _bcm_l3_intf_cfg_t *intf_info);
    246 #endif
    247 
    248 soc_field_t nh_entry_type_field[SOC_MAX_NUM_DEVICES];
    249 extern soc_field_t defip_mode0_bit[];
    250 extern soc_field_t defip_mode1_bit[];
    251 extern soc_field_t defip_mode_mask0_bit[];
    252 extern soc_field_t defip_mode_mask1_bit[];
    253 
    254 #if defined(ALPM_ENABLE)
    255 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT)
    256 extern int _bcm_th_alpm_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data);
    257 extern int _bcm_th_alpm_find(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_idx);
    258 
    259 #endif
    260 #endif
    261 
    262 #if defined(BCM_TRIDENT3_SUPPORT)
    263 static soc_profile_mem_t *_bcm_td3_tunnel_default_vlan_profile[BCM_MAX_NUM_UNITS];
    264 
    265 int
    266 _bcm_td3_tunnel_default_vlan_profile_init(int unit)
    267 {
    268     int i;
    269     soc_mem_t mem;
    270     int entry_words[1];
    271     void *entries[1];
    272     uint32 temp_index = 0;
    273     uint32 ent_sz;
    274     tunnel_default_vlan_profile_entry_t l3_tunnel_default_vlan_profile;
    275     soc_mem_t tunnel_mem = L3_TUNNELm;
    276 
    277     /* Create profile table cache (or re-init if it already exists) */
    278     mem = L3_TUNNEL_DEFAULT_VLAN_PROFILEm;
    279     ent_sz = sizeof(tunnel_default_vlan_profile_entry_t);
    280 
    281     if (_bcm_td3_tunnel_default_vlan_profile[unit] == NULL) {
    282         _bcm_td3_tunnel_default_vlan_profile[unit] = sal_alloc(sizeof(soc_profile_mem_t),
    283                                              "L3 TUNNEL DEFAULT VLAN Profile Mem");
    284         if (_bcm_td3_tunnel_default_vlan_profile[unit] == NULL) {
    285             return BCM_E_MEMORY;
    286         }
    287         soc_profile_mem_t_init(_bcm_td3_tunnel_default_vlan_profile[unit]);
    288     }
    289 
    290     /* Create profile table cache (or re-init if it already exists) */
    291     entry_words[0] = ent_sz / sizeof(uint32);
    292     SOC_IF_ERROR_RETURN
    293         (soc_profile_mem_create(unit, &mem, entry_words, 1,
    294                            _bcm_td3_tunnel_default_vlan_profile[unit]));
    295 
    296     /* Reserve index 0 in L3_TUNNEL_DEFAULT_VLAN_PROFILE */
    297     sal_memset(&l3_tunnel_default_vlan_profile, 0, ent_sz);
    298     entries[0] = &l3_tunnel_default_vlan_profile;
    299     SOC_IF_ERROR_RETURN
    300         (soc_profile_mem_add(unit, _bcm_td3_tunnel_default_vlan_profile[unit],
    301                              (void *) &entries, 1, &temp_index));
    302     SOC_PROFILE_MEM_REFERENCE(unit, _bcm_td3_tunnel_default_vlan_profile[unit], 0, 1);
    303 
    304     /* Recover ref-counts of L3_TUNNEL_DEFAULT_VLAN_PROFILE from L3_TUNNEL */
    305     if (SOC_WARM_BOOT(unit)) {
    306         for (i = 0; i < soc_mem_index_count(unit, tunnel_mem); i++) {
    307             uint32 idx;
    308             uint32 entry_ptr[SOC_MAX_MEM_WORDS];
    309 
    310             BCM_IF_ERROR_RETURN(
    311                 soc_mem_read(unit, tunnel_mem, MEM_BLOCK_ANY, i, entry_ptr));
    312 
    313             idx = soc_mem_field32_get(unit, tunnel_mem,
    314                                       entry_ptr, DEFAULT_VLAN_PROFILE_INDEXf);
    315             if (idx) {
    316                 SOC_PROFILE_MEM_REFERENCE(unit, _bcm_td3_tunnel_default_vlan_profile[unit],
    317                                           idx, soc_mem_index_count(unit, 1));
    318             }
    319         }
    320     }
    321     return BCM_E_NONE;
    322 }
    323 #endif
    324 
    325 /*
    326  * Function:
    327  *      bcm_xgs3_l3_mask6_apply
    328  * Purpose:
    329  *      Apply IPv6 mask on address
    330  * Parameters:
    331  *      unit     -  (IN)SOC unit number.
    332  *      mask     -  (IN)IPv6 Mask
    333  *      addr     -  (IN/OUT)Address to apply the mask
    334  * Returns:
    335  *      BCM_X_XXX
    336  */
    337 int
    338 bcm_xgs3_l3_mask6_apply(bcm_ip6_t mask, bcm_ip6_t addr)
    339 {
    340     uint8 *mask_iter;         /* Mask bytes iterator.      */
    341     uint8 *addr_iter;         /* Mask bytes iterator.      */
    342     int idx;                  /* IPv6 addresses iterator.  */
    343 
    344     mask_iter = (uint8 *)mask;
    345     addr_iter = (uint8 *)addr;
    346 
    347     for (idx = 0; idx < 16; idx++) {
    348         (*addr_iter) &= (*mask_iter);
    349         addr_iter++;
    350         mask_iter++;
    351     }
    352     return (BCM_E_NONE);
    353 }
    354 
    355 /*
    356  * Function:
    357  *      bcm_xgs3_l3_egress_mode_set
    358  * Purpose:
    359  *      Set unit l3 egress switching mode.
    360  * Parameters:
    361  *      unit     -  (IN)SOC unit number.
    362  *      mode     -  (IN)Egress switching mode.
    363  * Returns:
    364  *      BCM_X_XXX
    365  */
    366 int
    367 bcm_xgs3_l3_egress_mode_set(int unit, int mode)
    368 {
    369     /*  Make sure module was initialized. */
    370     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
    371         return (BCM_E_INIT);
    372     }
    373 
    374     /* Set mode flag. */
    375     switch(mode) {
    376       case 0:
    377           BCM_XGS3_L3_FLAGS(unit) &= ~_BCM_L3_SHR_EGRESS_MODE;
    378           break;
    379       case 1:
    380           BCM_XGS3_L3_FLAGS(unit) |= _BCM_L3_SHR_EGRESS_MODE;
    381           break;
    382       default:
    383           return (BCM_E_PARAM);
    384     }
    385 
    386 #ifdef BCM_WARM_BOOT_SUPPORT
    387     SOC_CONTROL_LOCK(unit);
    388     SOC_CONTROL(unit)->scache_dirty = 1;
    389     SOC_CONTROL_UNLOCK(unit);
    390 #endif
    391 
    392     return (BCM_E_NONE);
    393 }
    394 
    395 
    396 /*
    397  * Function:
    398  *      bcm_xgs3_l3_egress_mode_get
    399  * Purpose:
    400  *      Get unit l3 egress switching mode.
    401  * Parameters:
    402  *      unit     -  (IN)SOC unit number.
    403  *      mode     -  (IN)Egress switching mode.
    404  * Returns:
    405  *      BCM_X_XXX
    406  */
    407 int
    408 bcm_xgs3_l3_egress_mode_get(int unit, int *mode)
    409 {
    410     /*  Make sure module was initialized. */
    411     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
    412         return (BCM_E_INIT);
    413     }
    414 
    415     /* Input parameters check */
    416     if (NULL == mode) {
    417         return (BCM_E_PARAM);
    418     }
    419 
    420     *mode = (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) ? 1 : 0;
    421     return (BCM_E_NONE);
    422 }
    423 
    424 
    425 /*
    426  * Function:
    427  *      bcm_xgs3_l3_host_as_route_return_set
    428  * Purpose:
    429  *      Set mode for bcmSwitchL3HostAsRouteReturnValue
    430  *      Application controls the return value setting for bcm_l3_host_add API
    431  *      with BCM_L3_HOST_AS_ROUTE flag. If prefix gets added to HOST table,
    432  *      then return value=0. If prefix gets added to DEFIP table,
    433  *      then return value = ret_val
    434  * Parameters:
    435  *      unit     -  (IN)SOC unit number.
    436  *      ret_val     -  (IN) Return Value
    437  * Returns:
    438  *      BCM_X_XXX
    439  */
    440 
    441 int
    442 bcm_xgs3_l3_host_as_route_return_set(int unit, int ret_val)
    443 {
    444     ing_l3_next_hop_entry_t in_entry;   /* Buffer for ingress nh entry. */
    445 
    446     /* Make sure module was initialized. */
    447     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
    448          return (BCM_E_INIT);
    449     }
    450 
    451     /* Set mode */
    452     if (soc_mem_is_valid(unit, ING_L3_NEXT_HOPm)) {
    453          if (ret_val == 0) {
    454               BCM_XGS3_L3_FLAGS(unit) &= ~_BCM_L3_SHR_HOST_ADD_MODE;
    455          } else if ((ret_val > 0) && (ret_val <= 0xFF)) {
    456              BCM_XGS3_L3_FLAGS(unit) |= _BCM_L3_SHR_HOST_ADD_MODE;
    457              /* Zero buffers. */
    458              sal_memset(&in_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, nh));
    459              /* Read entry of ingress Black-Hole Next-Hop. */
    460              BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit,
    461                              ING_L3_NEXT_HOPm, 0, &in_entry));
    462              /* Store RETURN_VALUE within unused field of Black-Hole Next-Hop */
    463              soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &in_entry,
    464                              VLAN_IDf, ret_val);
    465              /* Write ingress next hop entry. */
    466              BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_WRITE(unit,
    467                              ING_L3_NEXT_HOPm, 0, &in_entry));
    468          } else {
    469              return (BCM_E_PARAM);
    470          }
    471 
    472 #ifdef BCM_WARM_BOOT_SUPPORT
    473 SOC_CONTROL_LOCK(unit);
    474 SOC_CONTROL(unit)->scache_dirty = 1;
    475 SOC_CONTROL_UNLOCK(unit);
    476 #endif
    477     }
    478 
    479 return (BCM_E_NONE);
    480 
    481 }
    482 
    483 /*
    484  * Function:
    485  *      bcm_xgs3_l3_host_as_route_return_get
    486  * Purpose:
    487  *      Get mode for bcmSwitchL3HostAsRouteReturnValue
    488  * Parameters:
    489  *      unit     -  (IN)SOC unit number.
    490  *      ret_val     -  (IN)Return Value
    491  * Returns:
    492  *      BCM_X_XXX
    493  */
    494 int
    495 bcm_xgs3_l3_host_as_route_return_get(int unit, int *ret_val)
    496 {
    497     int state;
    498     ing_l3_next_hop_entry_t in_entry;   /* Buffer for ingress nh entry. */
    499 
    500     /*  Make sure module was initialized. */
    501     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
    502         return (BCM_E_INIT);
    503     }
    504 
    505     /* Input parameters check */
    506     if (NULL == ret_val) {
    507         return (BCM_E_PARAM);
    508     }
    509 
    510     if (soc_mem_is_valid(unit, ING_L3_NEXT_HOPm)) {
    511          state = (BCM_XGS3_L3_HOST_AS_ROUTE_MODE_ISSET(unit));
    512          if (state == 0) {
    513              *ret_val = 0;
    514          } else {
    515              /* Zero buffers. */
    516              sal_memset(&in_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, nh));
    517              /* Read ingress next hop entry. */
    518              BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit,
    519                              ING_L3_NEXT_HOPm, 0, &in_entry));
    520              /* Obtain RETURN_VALUE within unused field of Black-Hole Next-Hop */
    521              *ret_val = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm,
    522                              &in_entry, VLAN_IDf);
    523          }
    524     } else {
    525          *ret_val = 0;
    526     }
    527 
    528     return (BCM_E_NONE);
    529 }
    530 
    531 #if defined(BCM_TRIUMPH_SUPPORT)
    532 /*
    533  * Function:
    534  *      bcm_xgs3_l3_ingress_mode_set
    535  * Purpose:
    536  *      Set unit l3 ingress switching mode.
    537  * Parameters:
    538  *      unit     -  (IN)SOC unit number.
    539  *      mode     -  (IN)Ingress switching mode.
    540  * Returns:
    541  *      BCM_X_XXX
    542  */
    543 int
    544 bcm_xgs3_l3_ingress_mode_set(int unit, int mode)
    545 {
    546     /*  Make sure module was initialized. */
    547     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
    548         return (BCM_E_INIT);
    549     }
    550 
    551     /* Set mode flag. */
    552     switch(mode) {
    553       case 0:
    554           BCM_XGS3_L3_FLAGS(unit) &= ~_BCM_L3_SHR_INGRESS_MODE;
    555           break;
    556       case 1:
    557           BCM_XGS3_L3_FLAGS(unit) |= _BCM_L3_SHR_INGRESS_MODE;
    558           break;
    559       default:
    560           return (BCM_E_PARAM);
    561     }
    562 
    563 #ifdef BCM_WARM_BOOT_SUPPORT
    564     SOC_CONTROL_LOCK(unit);
    565     SOC_CONTROL(unit)->scache_dirty = 1;
    566     SOC_CONTROL_UNLOCK(unit);
    567 #endif
    568 
    569     return (BCM_E_NONE);
    570 }
    571 
    572 
    573 /*
    574  * Function:
    575  *      bcm_xgs3_l3_ingress_mode_get
    576  * Purpose:
    577  *      Get unit l3 ingress switching mode.
    578  * Parameters:
    579  *      unit     -  (IN)SOC unit number.
    580  *      mode     -  (OUT)Ingress switching mode.
    581  * Returns:
    582  *      BCM_X_XXX
    583  */
    584 int
    585 bcm_xgs3_l3_ingress_mode_get(int unit, int *mode)
    586 {
    587 
    588     /* Input parameters check */
    589     if (NULL == mode) {
    590         return (BCM_E_PARAM);
    591     }
    592 
    593     *mode = (BCM_XGS3_L3_INGRESS_MODE_ISSET(unit)) ? 1 : 0;
    594     return (BCM_E_NONE);
    595 }
    596 
    597 /*
    598  * Function:
    599  *      bcm_xgs3_l3_ingress_intf_map_set
    600  * Purpose:
    601  *      Set unit l3 ingress interface map mode
    602  * Parameters:
    603  *      unit     -  (IN)SOC unit number.
    604  *      mode     -  (IN)ingress interface map mode
    605  * Returns:
    606  *      BCM_X_XXX
    607  */
    608 int
    609 bcm_xgs3_l3_ingress_intf_map_set(int unit, int mode)
    610 {
    611 
    612     if (soc_feature(unit, soc_feature_l3_iif_under_4k)) {
    613         /* Chip with this feature means table size of L3_IIFm under 4096
    614          * - can never support mode=0 for VLAN_ID 1:1 mapping to L3_IIFm.
    615          * - This SW info flag will be set during L3 init. 
    616          */
    617         if (mode == 0){
    618             return BCM_E_UNAVAIL;
    619         }
    620     } else {
    621         /*  Make sure module was initialized. */
    622         if (!BCM_XGS3_L3_INITIALIZED(unit)) {
    623             return (BCM_E_INIT);
    624         }
    625     }
    626 
    627 
    628     /* Set mode flag. */
    629     switch(mode) {
    630       case 0:
    631           BCM_XGS3_L3_FLAGS(unit) &= ~_BCM_L3_SHR_INGRESS_INTF_MAP;
    632           break;
    633       case 1:
    634           BCM_XGS3_L3_FLAGS(unit) |= _BCM_L3_SHR_INGRESS_INTF_MAP;
    635           break;
    636       default:
    637           return (BCM_E_PARAM);
    638     }
    639 
    640 #ifdef BCM_WARM_BOOT_SUPPORT
    641     SOC_CONTROL_LOCK(unit);
    642     SOC_CONTROL(unit)->scache_dirty = 1;
    643     SOC_CONTROL_UNLOCK(unit);
    644 #endif
    645 
    646     return (BCM_E_NONE);
    647 }
    648 
    649 
    650 /*
    651  * Function:
    652  *      bcm_xgs3_l3_ingress_intf_map_get
    653  * Purpose:
    654  *      Get unit ll3 ingress interface map mode
    655  * Parameters:
    656  *      unit     -  (IN)SOC unit number.
    657  *      mode     -  (OUT))ingress interface map mode
    658  * Returns:
    659  *      BCM_X_XXX
    660  */
    661 int
    662 bcm_xgs3_l3_ingress_intf_map_get(int unit, int *mode)
    663 {
    664     /* Do not fail if uninitialized as this function is used by VLAN module */
    665     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
    666         *mode = 0;
    667         return (BCM_E_NONE);
    668     }
    669 
    670     /* Input parameters check */
    671     if (NULL == mode) {
    672         return (BCM_E_PARAM);
    673     }
    674 
    675     *mode = (BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit)) ? 1 : 0;
    676     return (BCM_E_NONE);
    677 }
    678 #endif /* BCM_TRIUMPH_SUPPORT */
    679 
    680 /*
    681  * Function:
    682  *      _bcm_xgs3_l3_ecmp_group_alloc
    683  * Purpose:
    684  *      Allocate l3 ecmp group members array.
    685  * Parameters:
    686  *      unit    -  (IN) BCM device number.
    687  *      ptr     -  (IN) Allocated group pointer
    688  * Returns:
    689  *      BCM_X_XXX
    690  */
    691 STATIC int
    692 _bcm_xgs3_l3_ecmp_group_alloc(int unit, int **ptr)
    693 {
    694     int alloc_size;
    695 
    696     /*  Make sure module was initialized. */
    697     if (NULL == ptr) {
    698         return (BCM_E_NONE);
    699     }
    700 
    701 
    702     alloc_size = sizeof(int) * BCM_XGS3_L3_ECMP_MAX(unit);
    703 
    704     *ptr = NULL;
    705     BCM_XGS3_L3_ALLOC((*ptr), alloc_size, "ecmp group next hops array");
    706 
    707     /* Input parameters check */
    708     if (NULL == *ptr) {
    709         return (BCM_E_MEMORY);
    710     }
    711     return (BCM_E_NONE);
    712 }
    713 
    714 /*
    715  * Function:
    716  *      _bcm_xgs3_nh_hash_calc
    717  * Purpose:
    718  *      Calculate next hop entry hash(signature).
    719  * Parameters:
    720  *      unit     -  (IN)SOC unit number.
    721  *      buf      -  (IN)Next hop entry information.
    722  *      hash     -  (OUT) Hash(signature) calculated value.
    723  * Returns:
    724  *      BCM_X_XXX
    725  */
    726 STATIC int
    727 _bcm_xgs3_nh_hash_calc(int unit, void *buf, uint16 *hash)
    728 {
    729     uint32 sw_buf[10];
    730     bcm_l3_egress_t *nh_entry;
    731     uint32 mac_field[2];
    732 
    733     /* Input parameters check. */
    734     if ((NULL == buf) || (NULL == hash)) {
    735         return (BCM_E_PARAM);
    736     }
    737     sal_memset (sw_buf, 0, 10 * sizeof(uint32));
    738     nh_entry = (bcm_l3_egress_t *) buf;
    739 
    740     /*
    741      * Copy entry information to a temporary buffer, so we can
    742      * mask some fields we don't want to include in hash calculation.
    743      */
    744      sw_buf[0] = nh_entry->intf;
    745      SAL_MAC_ADDR_TO_UINT32(nh_entry->mac_addr, mac_field);
    746      sw_buf[1] = mac_field[0];
    747      /* 
    748       * NH entry is overlayed on VLAN_ID and L3_OIF fields.
    749       * The VLAN_ID is the default active field by default.
    750       * Once the L3_INTF_VLAN_SPLIT_EGRESS_MODE been set through config 
    751       * file with "l3_intf_vlan_split_egress=1", the active field is 
    752       * L3_OIF. And nh_entry->vlan should not be the key to built 
    753       * NH entry hash while VLAN_ID is not the active field.
    754       */
    755      if (!BCM_XGS3_L3_INTF_VLAN_SPLIT_EGRESS_MODE_ISSET(unit)) { 
    756         sw_buf[2] = ((mac_field[1] << 16) | nh_entry->vlan);
    757      }
    758      sw_buf[3] = nh_entry->module;
    759      sw_buf[4] = nh_entry->port;
    760      sw_buf[5] = nh_entry->trunk;
    761 #ifdef BCM_MPLS_SUPPORT
    762      if (soc_feature(unit, soc_feature_mpls) &&
    763          !(nh_entry->flags2 & BCM_L3_MPLS_GRE_LABEL)) {
    764          /* Include mpls info only if label is valid. */
    765          if (BCM_XGS3_L3_MPLS_LBL_VALID(nh_entry->mpls_label)) {
    766              sw_buf[6] = nh_entry->mpls_label;
    767              sw_buf[7] = nh_entry->mpls_qos_map_id;
    768              sw_buf[8] = nh_entry->mpls_ttl;
    769          }
    770      }
    771 #endif /* BCM_MPLS_SUPPORT */
    772      sw_buf[9] = nh_entry->encap_id;
    773 
    774     *hash = _shr_crc16(0, (uint8 *)&sw_buf[0], sizeof(uint32)*10);
    775 
    776     return (BCM_E_NONE);
    777 }
    778 
    779 /*
    780  * Function:
    781  *      _bcm_xgs3_cmp_int
    782  * Purpose:
    783  *      Compare two integers.
    784  * Parameters:
    785  *      b - first compared integer
    786  *      a - second compared integer
    787  * Returns:
    788  *      a<=>b
    789  */
    790 static INLINE int
    791 _bcm_xgs3_cmp_int(void *a, void *b)
    792 {
    793     int first;                  /* First compared integer. */
    794     int second;                 /* Second compared integer. */
    795 
    796     first = *(int *)a;
    797     second = *(int *)b;
    798 
    799     if (first < second) {
    800         return (BCM_L3_CMP_LESS);
    801     } else if (first > second) {
    802         return (BCM_L3_CMP_GREATER);
    803     }
    804     return (BCM_L3_CMP_EQUAL);
    805 }
    806 
    807 /*
    808  * Function:
    809  *      _bcm_xgs3_cmp_ecmp_member
    810  * Purpose:
    811  *      Compare two integers of ecmp member.
    812  * Parameters:
    813  *      b - first compared ecmp member
    814  *      a - second compared ecmp member
    815  * Returns:
    816  *      a<=>b
    817  */
    818 static INLINE int
    819 _bcm_xgs3_cmp_ecmp_member(void *a, void *b)
    820 {
    821     bcm_l3_ecmp_member_t first;      /* First compared ecmp member. */
    822     bcm_l3_ecmp_member_t second;     /* Second compared ecmp member. */
    823 
    824     first = *(bcm_l3_ecmp_member_t *)a;
    825     second = *(bcm_l3_ecmp_member_t *)b;
    826 
    827     /* Compare egress_if of ecmp member. */
    828     return _bcm_xgs3_cmp_int(&first.egress_if, &second.egress_if);
    829 }
    830 
    831 
    832 /*
    833  * Function:
    834  *      _bcm_xgs3_nh_map_hw_data_to_api
    835  * Purpose:
    836  *      Convert HW space nh entry format to API space nh entry.
    837  *      Currently service routine used to map hw port/trunk info
    838  *      to next hop entry port_tgid/modid format.
    839  * Parameters:
    840  *      unit     - (IN) SOC unit number.
    841  *      port     - (IN) Port/Trunk.
    842  *      module   - (IN) Module id.
    843  *      nh_entry - (IN/OUT) Updated next hop entry.
    844  * Returns:
    845  *      BCM_E_XXX
    846  */
    847 STATIC int
    848 _bcm_xgs3_nh_map_hw_data_to_api(int unit, int port,
    849                                 int mod, bcm_l3_egress_t *nh_entry)
    850 {
    851     int port_out;               /* Calculated port value */
    852     int modid_out;              /* Calculated module id. */
    853 
    854     if (nh_entry->flags2 & BCM_L3_FLAGS2_MC_GROUP) {
    855         return (BCM_E_NONE);
    856     }
    857 
    858     if (nh_entry->flags & BCM_L3_TGID) {
    859         /* Port is trunk. */
    860         nh_entry->module = 0;
    861 #ifdef BCM_TRX_SUPPORT
    862         if (soc_feature(unit, soc_feature_trunk_group_overlay)) {
    863             nh_entry->trunk = port;
    864         } else
    865 #endif /* BCM_TRIUMPH_SUPPORT */
    866         {
    867             nh_entry->trunk = BCM_MODIDf_TGIDf_TO_TRUNK(unit, mod, port);
    868         }
    869     } else
    870 #ifdef BCM_RIOT_SUPPORT
    871     if (_bcm_vp_is_vfi_type(unit, nh_entry->port)) {
    872         /* Send back the vp as it is. */
    873         nh_entry->port = port;
    874     } else 
    875 #endif
    876     {
    877         /* Regular port. */
    878         BCM_IF_ERROR_RETURN
    879             (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
    880                                     mod, port, &modid_out, &port_out));
    881 
    882         nh_entry->module = modid_out;
    883         nh_entry->port = port_out;
    884     }
    885     return (BCM_E_NONE);
    886 }
    887 
    888 /*
    889  * Function:
    890  *      _bcm_xgs3_nh_map_api_data_to_hw
    891  * Purpose:
    892  *      Convert API space nh entry format to HW space nh entry.
    893  * Parameters:
    894  *      unit      - (IN)SOC unit number.
    895  *      nh_entry  - (IN/OUT)Next hop entry data.
    896  * Returns:
    897  *    BCM_E_XXX
    898  */
    899 STATIC int
    900 _bcm_xgs3_nh_map_api_data_to_hw(int unit, bcm_l3_egress_t *nh_entry)
    901 {
    902     int port_out;               /* Calculated port value */
    903     int modid_out;              /* Calculated module id. */
    904 
    905     if (NULL == nh_entry)
    906         return (BCM_E_PARAM);
    907 
    908     if (nh_entry->flags2 & BCM_L3_FLAGS2_MC_GROUP) {
    909         return (BCM_E_NONE);
    910     }
    911 
    912     /* convert API space numbers to HW space numbers */
    913     if ((nh_entry->flags & BCM_L3_TGID) == 0) {
    914 #ifdef BCM_RIOT_SUPPORT
    915         if (_bcm_vp_is_vfi_type(unit, nh_entry->port)) {
    916             return BCM_E_NONE;
    917         }
    918 #endif
    919         BCM_IF_ERROR_RETURN
    920             (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET,
    921                                     nh_entry->module, nh_entry->port,
    922                                     &modid_out, &port_out));
    923         if (!SOC_MODID_ADDRESSABLE(unit, modid_out)) {
    924             return (BCM_E_BADID);
    925         }
    926         if (!SOC_PORT_ADDRESSABLE(unit, port_out)) {
    927             return (BCM_E_PORT);
    928         }
    929     } else {
    930 #ifdef BCM_TRX_SUPPORT
    931         if (soc_feature(unit, soc_feature_trunk_group_overlay)) {
    932             modid_out = 0;
    933             port_out = nh_entry->trunk;
    934         } else
    935 #endif /* BCM_TRX_SUPPORT */
    936         {
    937             /* Map trunk id to mod/port pair */
    938             modid_out = BCM_TRUNK_TO_MODIDf(unit, nh_entry->trunk);
    939             port_out = BCM_TRUNK_TO_TGIDf(unit, nh_entry->trunk);
    940         }
    941     }
    942     /* Preserve converted values in the structure. */
    943     /* NOTE: HW has a single field for port/trunk  */
    944     /*       hence port only used for hw calls.    */
    945     nh_entry->trunk  = 0;
    946     nh_entry->port   = port_out;
    947     nh_entry->module = modid_out;
    948 
    949     return (BCM_E_NONE);
    950 }
    951 
    952 /*
    953  * Function:
    954  *      bcm_xgs3_l3_enable
    955  * Purpose:
    956  *      Enable/disable L3 function.
    957  * Parameters:
    958  *      unit -   (IN)SOC PCI unit number.
    959  *      enable - (IN)TRUE: enable L3 support.
    960  *                   FALSE: disable L3 support.
    961  * Returns:
    962  *      BCM_E_XXX
    963  */
    964 int
    965 bcm_xgs3_l3_enable(int unit, int enable)
    966 {
    967     int port;                   /* Port iterator.  */
    968     bcm_pbmp_t port_pbmp;
    969 
    970     /*  Make sure module was initialized. */
    971     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
    972         return (BCM_E_INIT);
    973     }
    974 
    975     BCM_PBMP_CLEAR(port_pbmp);
    976     BCM_PBMP_ASSIGN(port_pbmp, PBMP_PORT_ALL(unit));
    977 
    978 #ifdef BCM_KATANA2_SUPPORT
    979     if (SOC_IS_KATANA2(unit) && soc_feature(unit, soc_feature_flex_port)) {
    980         BCM_IF_ERROR_RETURN(_bcm_kt2_flexio_pbmp_update(unit, &port_pbmp));
    981     }
    982     if (soc_feature(unit, soc_feature_linkphy_coe) ||
    983         soc_feature(unit, soc_feature_subtag_coe)) {
    984         _bcm_kt2_subport_pbmp_update(unit, &port_pbmp);
    985     }
    986 #endif
    987 #if defined(BCM_SABER2_SUPPORT)
    988     if(SOC_IS_SABER2(unit)){
    989         int oamp_enable;
    990         (void)bcm_sb2_sat_oamp_enable_get(unit, &oamp_enable);
    991         /* Skip OAMP port for saber2 device */
    992         if(oamp_enable) {
    993             SOC_PBMP_PORT_REMOVE(port_pbmp,
    994                     _BCM_SB2_SAT_OAMP_PHY_PORT_NUMBER);
    995         }
    996     }
    997 #endif
    998 
    999 
   1000     /* Iterate over all the ports. */
   1001     PBMP_ITER(port_pbmp, port) {
   1002         /* Set l3 enable to the hw. */
   1003         /*
   1004          * In general, we enable this controls for all ports.
   1005          * But there may be some ports which does not
   1006          * support this setting. these ports may return errors
   1007          * Therefore leaving it unchecked.
   1008          */
   1009 
   1010         /* coverity[check_return : FALSE] */
   1011         bcm_esw_port_control_set(unit, port, bcmPortControlIP4, enable);
   1012         /* coverity[check_return : FALSE] */
   1013         bcm_esw_port_control_set(unit, port, bcmPortControlIP6, enable);
   1014     }
   1015     return (BCM_E_NONE);
   1016 }
   1017 
   1018 
   1019 /*
   1020  * Function:
   1021  *      bcm_xgs3_l3_tbl_dma
   1022  * Purpose:
   1023  *
   1024  * Parameters:
   1025  *      unit         -(IN)SOC unit number.
   1026  *      tbl_mem      -(IN)Table memory.
   1027  *      tbl_entry_sz -(IN)Table entry size.
   1028  *      descr        -(IN)Table descriptor.
   1029  *      res_ptr      -(OUT) Allocated pointer filled with table info
   1030  *      entry_count  -(OUT) Table entry count.
   1031  * Returns:
   1032  *      BCM_E_XXX
   1033  */
   1034 int
   1035 bcm_xgs3_l3_tbl_dma(int unit, soc_mem_t tbl_mem, uint16 tbl_entry_sz,
   1036                      const char *descr, char **res_ptr, int *entry_count)
   1037 {
   1038     int alloc_size;             /* Allocation size.          */
   1039     char *buffer;               /* Buffer to read the table. */
   1040     int tbl_size;               /* HW table size.            */
   1041     /* Input parameters sanity check. */
   1042     if ((NULL == res_ptr) || (NULL == descr)) {
   1043         return (BCM_E_PARAM);
   1044     }
   1045 
   1046     /* If entry size is not deterministic. reject. */
   1047     if (tbl_entry_sz == BCM_XGS3_L3_INVALID_ENT_SZ) {
   1048         return (BCM_E_UNAVAIL);
   1049     }
   1050 
   1051     if (INVALIDm == tbl_mem) {
   1052         return (BCM_E_NOT_FOUND);
   1053     }
   1054 
   1055     /* Calculate table size. */
   1056     tbl_size =  soc_mem_index_count(unit, tbl_mem);
   1057     if (!tbl_size) {
   1058         return (BCM_E_NOT_FOUND);
   1059     } else if (NULL != entry_count) {
   1060         *entry_count = tbl_size;
   1061     }
   1062     alloc_size = tbl_entry_sz * tbl_size;
   1063 
   1064     /* Allocate memory buffer. */
   1065     buffer = soc_cm_salloc(unit, alloc_size, descr);
   1066     if (buffer == NULL) {
   1067         return (BCM_E_MEMORY);
   1068     }
   1069 
   1070     /* Reset allocated buffer. */
   1071     sal_memset(buffer, 0, alloc_size);
   1072 
   1073     /* Read table to the buffer. */
   1074     if (soc_mem_read_range(unit, tbl_mem, MEM_BLOCK_ANY,
   1075                            soc_mem_index_min(unit, tbl_mem),
   1076                            soc_mem_index_max(unit, tbl_mem), buffer) < 0) {
   1077         soc_cm_sfree(unit, buffer);
   1078         return (BCM_E_INTERNAL);
   1079     }
   1080 
   1081     *res_ptr = buffer;
   1082     return (BCM_E_NONE);
   1083 }
   1084 /*
   1085  * Function:
   1086  *      _bcm_xgs3_l3_intf_init
   1087  * Purpose:
   1088  *      Initialize L3 tables.
   1089  * Parameters:
   1090  *      unit     - (IN)SOC unit number.
   1091  * Returns:
   1092  *      BCM_E_XXX
   1093  */
   1094 STATIC int
   1095 _bcm_xgs3_l3_intf_init(int unit)
   1096 {
   1097     int mem_sz;   /* Allocated memory size.     */
   1098     _bcm_l3_tbl_t *tbl_ptr; /* L3 egress intf table pointer. */
   1099 
   1100     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, intf);
   1101     /* Get first egr intf index.  */
   1102     if (soc_feature(unit, soc_feature_l3_egr_intf_zero_invalid)) {
   1103         tbl_ptr->idx_min = soc_mem_index_min(unit,
   1104                 BCM_XGS3_L3_MEM(unit, intf)) + 1;
   1105     } else {
   1106         tbl_ptr->idx_min = soc_mem_index_min(unit,
   1107                 BCM_XGS3_L3_MEM(unit, intf));
   1108     }
   1109     /* Get last egr intf index. */
   1110     tbl_ptr->idx_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, intf));
   1111     /* Set egr intf max used to first entry.(table empty) */
   1112     tbl_ptr->idx_maxused = tbl_ptr->idx_min;
   1113 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   1114     /* Set up split table limits */
   1115     tbl_ptr->split_idx      = 0;
   1116     tbl_ptr->split_maxused  = 0;
   1117 #endif
   1118 
   1119     BCM_XGS3_L3_IF_TBL_SIZE(unit) = tbl_ptr->idx_max + 1;
   1120 
   1121     /* Keep track of L3 interfaces */
   1122     mem_sz = SHR_BITALLOCSIZE(BCM_XGS3_L3_IF_TBL_SIZE(unit));
   1123     BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_IF_INUSE(unit), mem_sz, "l3_intf");
   1124     if (NULL == BCM_XGS3_L3_IF_INUSE(unit)) {
   1125         return (BCM_E_MEMORY);
   1126     }
   1127 
   1128     /*
   1129      * Keep track of L3 interfaces that were ever set on the Next-Hop table.
   1130      * This is used to skip the Next Hop table search in
   1131      * _bcm_fb_nh_intf_is_tnl_update().
   1132       */
   1133     BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_INTF_USED_NH(unit), mem_sz, "l3_intf_nh");
   1134     if (NULL == BCM_XGS3_L3_INTF_USED_NH(unit)) {
   1135         return (BCM_E_MEMORY);
   1136     }
   1137 
   1138     /* Keep track of L3 interfaces */
   1139     BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_IF_ADD2ARL(unit), mem_sz, "l3_intf_arl");
   1140     if (NULL == BCM_XGS3_L3_IF_ADD2ARL(unit)) {
   1141         return (BCM_E_MEMORY);
   1142     }
   1143 
   1144     return (BCM_E_NONE);
   1145 }
   1146 /*
   1147  * Function:
   1148  *      _bcm_xgs3_l3_ing_intf_init
   1149  * Purpose:
   1150  *      Initialize ingress l3 interface table .
   1151  * Parameters:
   1152  *      unit     - (IN)SOC unit number.
   1153  * Returns:
   1154  *      BCM_E_XXX
   1155  */
   1156 STATIC int
   1157 _bcm_xgs3_l3_ing_intf_init(int unit)
   1158 {
   1159     int mem_sz;                  /* Allocated memory size.               */
   1160     int idx;                     /* Reserved interfaces iteration index. */
   1161 #if defined(BCM_TRIUMPH_SUPPORT) 
   1162     _bcm_l3_ingress_intf_t iif;  /* Ipmc interfaces identity map.        */
   1163     int rv;                      /* Operation return status.             */
   1164 #endif /* BCM_TRIUMPH_SUPPORT */
   1165 
   1166 #if defined(BCM_TRIDENT2_SUPPORT)
   1167     char *iif_tbl_ptr = NULL;
   1168     iif_entry_t write_entry;
   1169     iif_entry_t *hw_entry;
   1170     int start_idx, end_idx;
   1171     soc_mem_t mem;
   1172 #endif /* BCM_TRIDENT2_SUPPORT */
   1173 
   1174 #if defined(BCM_TRIUMPH_SUPPORT)
   1175     sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t));
   1176 #endif /* BCM_TRIUMPH_SUPPORT */
   1177 
   1178     /*
   1179      * Keep track of VLAN VRF Ref count in l3_ing_intf table
   1180      */
   1181     mem_sz = BCM_VLAN_COUNT * sizeof(_bcm_l3_tbl_ext_t);
   1182     BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_TBL(unit, ing_intf).ext_arr, mem_sz, "l3_ing_intf");
   1183     if (NULL == BCM_XGS3_L3_TBL(unit, ing_intf).ext_arr) {
   1184         return (BCM_E_MEMORY);
   1185     }
   1186 
   1187     if (INVALIDm != BCM_XGS3_L3_MEM(unit, ing_intf)) { 
   1188         BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) = 
   1189             soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, ing_intf));
   1190         if (BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) == 0){
   1191             /* Wolfhoud2(HR3 family) support partial L3 feature.
   1192              *  - L3_IIFm is valid in this chip but size=0 due to no support.
   1193              */
   1194             return (BCM_E_NONE);
   1195         }
   1196     } else {
   1197         BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) = 0;
   1198         return (BCM_E_NONE);
   1199     }
   1200 
   1201     /* Keep track of L3 interfaces */
   1202     mem_sz = SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit));
   1203     BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_ING_IF_INUSE(unit), mem_sz, "l3_iif");
   1204     if (NULL == BCM_XGS3_L3_ING_IF_INUSE(unit)) {
   1205         return (BCM_E_MEMORY);
   1206     }
   1207 
   1208 #if defined(BCM_WARM_BOOT_SUPPORT) && defined(BCM_TRIDENT2_SUPPORT)
   1209     if (SOC_WARM_BOOT(unit)) {
   1210         int stable_size = 0;
   1211         SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
   1212         if (stable_size > 0) {
   1213          /*
   1214           * The L3 ingress interface inuse bitmaps are recovered from scahe, and
   1215           * there is no need to set HW tables during warmboot.
   1216           */
   1217             return (BCM_E_NONE);
   1218         }
   1219     }
   1220 #endif
   1221 
   1222 #ifdef BCM_TRIUMPH_SUPPORT
   1223     if (soc_feature(unit, soc_feature_l3_iif_under_4k)) {
   1224         /* means no enough L3_IIFm entries for 1:1 mapped by VLAN_ID. */
   1225 
   1226         /* in this feature, L3 ingress interface map mode can only be 1 always */
   1227         BCM_IF_ERROR_RETURN(bcm_xgs3_l3_ingress_intf_map_set(unit, 1));
   1228 
   1229         /* the entry0 in such L3_IIFm is default entry for VLANm.L3_IIFf 
   1230          * - flag of BCM_L3_INGRESS_DSCP_TRUST must be unset for this 
   1231          *  L3_IIF default entry.
   1232          */
   1233         idx = 0;
   1234         SHR_BITSET(BCM_XGS3_L3_ING_IF_INUSE(unit), idx);
   1235         iif.intf_id = idx;
   1236         iif.flags &= ~BCM_L3_INGRESS_DSCP_TRUST;
   1237         iif.flags &= ~BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK;
   1238         rv = _bcm_tr_l3_ingress_interface_set(unit, &iif, NULL, NULL);
   1239         BCM_IF_ERROR_RETURN(rv);
   1240     }
   1241 #endif
   1242 
   1243     /* First 4K interfaces are reserved for per vlan interface use. */
   1244    if (!(BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit))) {
   1245 #if defined(BCM_TRIDENT2_SUPPORT)
   1246        if (soc_feature(unit, soc_feature_l3_iif_profile)) {
   1247 
   1248            mem       = BCM_XGS3_L3_MEM(unit, ing_intf);
   1249            start_idx = soc_mem_index_min(unit, L3_IIFm);
   1250            end_idx   = BCM_VLAN_MAX;
   1251 
   1252            /* DMA L3_IIF table to software copy */
   1253            rv = bcm_xgs3_l3_tbl_range_dma(unit,
   1254                        mem, BCM_XGS3_L3_ENT_SZ(unit, ing_intf), "l3_iif_tbl",
   1255                        start_idx, end_idx, &iif_tbl_ptr);
   1256 
   1257            if (BCM_FAILURE(rv)) {
   1258                 LOG_ERROR(BSL_LS_BCM_L3,
   1259                     (BSL_META_U(unit, "DMA Read Failed for mem=(%s)\n"),
   1260                     SOC_MEM_NAME(unit, mem)));
   1261                return rv;
   1262            }
   1263 
   1264            /* Setup iif structure */
   1265            iif.flags |= BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK;
   1266            iif.flags |= BCM_L3_INGRESS_GLOBAL_ROUTE;
   1267 
   1268            for (idx = 0; idx < BCM_VLAN_INVALID; idx++) {
   1269                iif.intf_id = idx;
   1270                iif.ipmc_intf_id = idx;
   1271 
   1272                hw_entry = soc_mem_table_idx_to_pointer(unit,
   1273                                          mem, iif_entry_t *, iif_tbl_ptr, idx);
   1274 
   1275                rv = _bcm_tr_l3_ingress_interface_set(unit, &iif,
   1276                                          hw_entry, &write_entry);
   1277                if (BCM_FAILURE(rv)) {
   1278                     LOG_ERROR(BSL_LS_BCM_L3,
   1279                         (BSL_META_U(unit,
   1280                         "Failed to set l3 ingress interface for index=(%d)\n"),
   1281                          idx));
   1282                    soc_cm_sfree(unit, iif_tbl_ptr);
   1283                    return rv;
   1284                }
   1285                SHR_BITSET(BCM_XGS3_L3_ING_IF_INUSE(unit), idx);
   1286                /* Update the entry copy in the DMAed buffer with the 
   1287                 * new contents. of write_entry modified by interface_set
   1288                 */
   1289                sal_memcpy(hw_entry, &write_entry, soc_mem_entry_bytes(unit, mem));
   1290            }
   1291 
   1292            /* Write back modified contents */
   1293            rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ALL,
   1294                                  start_idx, end_idx, iif_tbl_ptr);
   1295            if (SOC_FAILURE(rv)) {
   1296                 LOG_ERROR(BSL_LS_BCM_L3,
   1297                     (BSL_META_U(unit, "DMA Write Failed for mem=(%s)\n"),
   1298                     SOC_MEM_NAME(unit, mem)));
   1299            }
   1300            if (iif_tbl_ptr != NULL) {
   1301                soc_cm_sfree(unit, iif_tbl_ptr);
   1302            }
   1303        } else
   1304 #endif /* BCM_TRIDENT2_SUPPORT */
   1305        {
   1306            for (idx = 0; idx < BCM_VLAN_INVALID; idx++) {
   1307                SHR_BITSET(BCM_XGS3_L3_ING_IF_INUSE(unit), idx);
   1308 #if defined(BCM_TRIUMPH_SUPPORT)
   1309                if (SOC_IS_TR_VL(unit)) {
   1310                    iif.intf_id = idx;
   1311                    iif.ipmc_intf_id = idx;
   1312                    rv = _bcm_tr_l3_ingress_interface_set(unit, &iif,
   1313                            NULL, NULL);
   1314                    BCM_IF_ERROR_RETURN(rv);
   1315                }
   1316 #endif /* BCM_TRIUMPH_SUPPORT */
   1317            }
   1318        }
   1319     }
   1320 
   1321     return (BCM_E_NONE);
   1322 }
   1323 
   1324 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   1325 /*
   1326  * Function:
   1327  *      bcmi_xgs3_l3_nh_tbl_split_range_init
   1328  * Purpose:
   1329  *      Initialize split indexes in L3next hop table.
   1330  * Parameters:
   1331  *      unit     - (IN)SOC unit number.
   1332  * Returns:
   1333  *      BCM_E_XXX.
   1334  */
   1335 
   1336 STATIC void 
   1337 bcmi_xgs3_l3_nh_tbl_split_range_init(int unit)
   1338 {
   1339     _bcm_l3_tbl_t *tbl_ptr;     /* Next hop table pointer. */
   1340 #if defined(BCM_RIOT_SUPPORT)
   1341     _bcm_l3_bookkeeping_t *l3_bk_info = L3_INFO(unit);
   1342 #endif
   1343 
   1344     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop);
   1345     if (NULL == tbl_ptr) {
   1346         return;
   1347     }
   1348 
   1349     /* Set up split table limits */
   1350 #if defined(BCM_RIOT_SUPPORT)
   1351     if (BCMI_L3_NH_OVERLAY_VALID(unit)) {
   1352         if (l3_bk_info->l3_nh_overlay_alloc_mode > 0) {
   1353             tbl_ptr->split_idx     = tbl_ptr->idx_max -
   1354                 l3_bk_info->l3_nh_overlay_entries + 1;
   1355         } else {
   1356             tbl_ptr->split_idx     = l3_bk_info->l3_nh_overlay_entries;
   1357 #if defined(BCM_TRIDENT2_SUPPORT)
   1358             if (l3_bk_info->l3_nh_reserve_for_ecmp) {
   1359                 tbl_ptr->split_idx += BCM_XGS3_L3_ECMP_MAX_GROUPS(unit);
   1360             }
   1361 #endif
   1362         }
   1363         tbl_ptr->idx_maxused   = tbl_ptr->split_idx;
   1364         tbl_ptr->split_maxused = tbl_ptr->idx_min;
   1365     } else
   1366 #endif /* BCM_RIOT_SUPPORT */
   1367     {
   1368         tbl_ptr->split_idx     = 0;
   1369         tbl_ptr->split_maxused = 0;
   1370     }
   1371     return; 
   1372 }
   1373 #endif /* defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) */
   1374 
   1375 /*
   1376  * Function:
   1377  *      _bcm_xgs3_l3_nh_init
   1378  * Purpose:
   1379  *      Initialize L3next hop table.
   1380  * Parameters:
   1381  *      unit     - (IN)SOC unit number.
   1382  * Returns:
   1383  *      Number of L3 entries.
   1384  */
   1385 STATIC int
   1386 _bcm_xgs3_l3_nh_init(int unit)
   1387 {
   1388     int mem_sz;                 /* Allocation memory size. */
   1389     _bcm_l3_tbl_t *tbl_ptr;     /* Next hop table pointer.       */
   1390 
   1391     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop);
   1392     /* Get first next hop index.  */
   1393     /* NOTE: First next hop index is reserved for LPM/HOST lookup failure. */
   1394     tbl_ptr->idx_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, nh)) + 1;
   1395     /* Get last next hop index. */
   1396     tbl_ptr->idx_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, nh));
   1397     /* Set next hop max used to first next hop entry.(table empty) */
   1398     tbl_ptr->idx_maxused = tbl_ptr->idx_min;
   1399 
   1400 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   1401     bcmi_xgs3_l3_nh_tbl_split_range_init(unit);
   1402 #endif
   1403 
   1404     /* Return next hop table size. */
   1405     BCM_XGS3_L3_NH_TBL_SIZE(unit) =
   1406         soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, nh));
   1407 
   1408     /*
   1409      * Keep track of Next Hop table usage.
   1410      */
   1411     mem_sz = BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(_bcm_l3_tbl_ext_t);
   1412     BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_TBL(unit, next_hop).ext_arr, mem_sz, "l3_nh");
   1413     if (NULL == BCM_XGS3_L3_TBL(unit, next_hop).ext_arr) {
   1414         return (BCM_E_MEMORY);
   1415     }
   1416 
   1417     /*
   1418      * Keep track of Next Hop table usage.
   1419      */
   1420     if (soc_feature(unit, soc_feature_hierarchical_protection)) {
   1421         mem_sz = BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(int);
   1422         BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_NH_MULTI_COUNT(unit), mem_sz,
   1423             "l3_nh_multi_count");
   1424         if (NULL == BCM_XGS3_L3_NH_MULTI_COUNT(unit)) {
   1425             return (BCM_E_MEMORY);
   1426         }
   1427     }
   1428 
   1429 
   1430     return (BCM_E_NONE);
   1431 }
   1432 
   1433 #ifdef BCM_WARM_BOOT_SUPPORT
   1434 #define BCM_WB_VERSION_1_17               SOC_SCACHE_VERSION(1,17)
   1435 #define BCM_WB_VERSION_1_16               SOC_SCACHE_VERSION(1,16)
   1436 #define BCM_WB_VERSION_1_15               SOC_SCACHE_VERSION(1,15)
   1437 #define BCM_WB_VERSION_1_14               SOC_SCACHE_VERSION(1,14)
   1438 #define BCM_WB_VERSION_1_13               SOC_SCACHE_VERSION(1,13)
   1439 #define BCM_WB_VERSION_1_12               SOC_SCACHE_VERSION(1,12)
   1440 #define BCM_WB_VERSION_1_11               SOC_SCACHE_VERSION(1,11)
   1441 #define BCM_WB_VERSION_1_10               SOC_SCACHE_VERSION(1,10)
   1442 #define BCM_WB_VERSION_1_9                SOC_SCACHE_VERSION(1,9)
   1443 #define BCM_WB_VERSION_1_8                SOC_SCACHE_VERSION(1,8)
   1444 #define BCM_WB_VERSION_1_7                SOC_SCACHE_VERSION(1,7)
   1445 #define BCM_WB_VERSION_1_6                SOC_SCACHE_VERSION(1,6)
   1446 #define BCM_WB_VERSION_1_5                SOC_SCACHE_VERSION(1,5)
   1447 #define BCM_WB_VERSION_1_4                SOC_SCACHE_VERSION(1,4)
   1448 #define BCM_WB_VERSION_1_3                SOC_SCACHE_VERSION(1,3)
   1449 #define BCM_WB_VERSION_1_2                SOC_SCACHE_VERSION(1,2)
   1450 #define BCM_WB_VERSION_1_1                SOC_SCACHE_VERSION(1,1)
   1451 #define BCM_WB_VERSION_1_0                SOC_SCACHE_VERSION(1,0)
   1452 #define BCM_WB_DEFAULT_VERSION            BCM_WB_VERSION_1_17
   1453 
   1454 /*
   1455  * _bcm_xgs3_l3_l3table_reinit
   1456  *
   1457  * Updates l3_v4mc_added and l3_v6mc_added counts
   1458  */
   1459 STATIC int
   1460 _bcm_xgs3_l3_l3table_reinit(int unit)
   1461 {
   1462     int i;                        /* Iteration index.              */
   1463     int index_min;                /* First entry index.            */
   1464     int index_max;                /* Last  entry index.            */
   1465     int rv;                       /* Operation return value.       */
   1466     char *l3_tbl_ptr = NULL;      /* Table dma pointer.            */
   1467     _bcm_l3_cfg_t l3_cfg;         /* Extracted IPMC entry 	   */
   1468 #if defined(BCM_HAWKEYE_SUPPORT)
   1469     if (SOC_IS_HAWKEYE(unit)) {
   1470         return BCM_E_NONE;
   1471     }
   1472 #endif
   1473     /* Make sure hw call pointer was initialized. */
   1474     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_get_by_idx)) {
   1475         return (BCM_E_UNAVAIL);
   1476     }
   1477 
   1478     /* First do IPv4MC table */
   1479     if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, ipmc_v4))) {
   1480         index_max = soc_mem_index_max(unit,  BCM_XGS3_L3_MEM(unit, ipmc_v4));
   1481         index_min = soc_mem_index_min(unit,  BCM_XGS3_L3_MEM(unit, ipmc_v4));
   1482         rv = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, ipmc_v4),
   1483                                  BCM_XGS3_L3_ENT_SZ(unit, ipmc_v4),
   1484                                  "l3_tbl", &l3_tbl_ptr, NULL);
   1485         if (BCM_FAILURE(rv)) {
   1486             l3_tbl_ptr = NULL;
   1487         }
   1488 
   1489         for (i = index_min; i <= index_max; i++) {
   1490             l3_cfg.l3c_flags = 0;
   1491             BCM_XGS3_L3_MODULE_LOCK(unit);
   1492             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_get_by_idx)(
   1493                      unit, l3_tbl_ptr,
   1494                      i, &l3_cfg);
   1495             BCM_XGS3_L3_MODULE_UNLOCK(unit);
   1496 
   1497             if (rv == BCM_E_NOT_FOUND) {
   1498                 continue;
   1499             } else if (BCM_FAILURE(rv)) {
   1500                 goto cleanup;
   1501             }
   1502             BCM_XGS3_L3_IP4_IPMC_CNT(unit)++;
   1503         }
   1504         if (l3_tbl_ptr) {
   1505             soc_cm_sfree(unit, l3_tbl_ptr);
   1506             l3_tbl_ptr = NULL;
   1507         }
   1508     }
   1509 
   1510     /* Now IPv6MC table */
   1511     if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, ipmc_v6))) {
   1512         index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, ipmc_v6));
   1513         index_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, ipmc_v6));
   1514         rv = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, ipmc_v6),
   1515                                  BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6),
   1516                                  "l3_tbl", &l3_tbl_ptr, NULL);
   1517         if (BCM_FAILURE(rv)) {
   1518             l3_tbl_ptr = NULL;
   1519         }
   1520 
   1521         for (i = index_min; i <= index_max; i++) {
   1522             l3_cfg.l3c_flags = BCM_L3_IP6;
   1523             BCM_XGS3_L3_MODULE_LOCK(unit);
   1524             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_get_by_idx)(
   1525                     unit, l3_tbl_ptr,
   1526                     i, &l3_cfg);
   1527             BCM_XGS3_L3_MODULE_UNLOCK(unit);
   1528             if (rv == BCM_E_NOT_FOUND) {
   1529                continue;
   1530             } else if (BCM_FAILURE(rv)) {
   1531                 goto cleanup;
   1532             }
   1533             BCM_XGS3_L3_IP6_IPMC_CNT(unit)++;
   1534         }
   1535     }
   1536     rv = BCM_E_NONE;
   1537 
   1538 cleanup:
   1539     if (l3_tbl_ptr) {
   1540         soc_cm_sfree(unit, l3_tbl_ptr);
   1541     }
   1542     return rv;
   1543 }
   1544 
   1545 STATIC int
   1546 _bcm_xgs3_l3_nh_reinit(int unit, int egressMode)
   1547 {
   1548     int idx;                      /* Iteration index.              */
   1549     int index_min;                /* First interface entry index.  */
   1550     int index_max;                /* Last interface entry index.   */
   1551     int ret_val;                  /* Operation return value.       */
   1552     int nh_idx;                   /* Next hop index from L3        */
   1553     int flex_v4_entry;            /* IPv4 flex view entry          */
   1554     bcm_l3_egress_t nh_info;      /* Next hop (egress) info        */
   1555     bcm_l3_egress_t nh_null;      /* Next hop (egress) info null entry */
   1556     char *l3_tbl_ptr     = NULL;  /* Table dma pointer.             */
   1557     char *egr_nh_tbl_ptr = NULL;  /* Egr NH Table dma pointer.      */
   1558 #ifdef BCM_TOMAHAWK3_SUPPORT
   1559     char *egr_nh2_tbl_ptr = NULL; /* Egr NH_2 Table dma pointer.    */
   1560 #endif
   1561     _bcm_l3_tbl_t *tbl_ptr;       /* Next hop table pointer.       */
   1562     _bcm_l3_cfg_t l3_cfg;	  /* Extracted L3 entry            */
   1563 #if defined(BCM_HAWKEYE_SUPPORT)
   1564     _bcm_rp_l3_data_t *rp_tbl_ptr;
   1565 #endif
   1566 
   1567 #ifdef BCM_TRIDENT3_SUPPORT
   1568     if (soc_feature(unit, soc_feature_flex_flow)) {
   1569         BCM_IF_ERROR_RETURN(_bcm_td3_l3_repl_l3_intf_recover(unit));
   1570     }
   1571 #endif
   1572 
   1573     /* Make sure hw call pointer was initialized. */
   1574     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, nh_get)) {
   1575         return (BCM_E_UNAVAIL);
   1576     }
   1577 
   1578     /* Get next hop table start & end index. */
   1579     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop);
   1580     tbl_ptr->idx_min = index_min =
   1581         soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, nh)) + 1;
   1582     tbl_ptr->idx_max = index_max =
   1583         soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, nh));
   1584     tbl_ptr->idx_maxused = 0;
   1585 
   1586 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   1587     bcmi_xgs3_l3_nh_tbl_split_range_init(unit);
   1588 #endif
   1589 
   1590 /*    BCM_XGS3_L3_NH_TBL_SIZE(unit) = index_max - index_min + 1;*/
   1591     BCM_XGS3_L3_NH_TBL_SIZE(unit) =
   1592         soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, nh));
   1593 
   1594    bcm_l3_egress_t_init(&nh_null);
   1595     ret_val = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, nh),
   1596                                   BCM_XGS3_L3_ENT_SZ(unit, nh),
   1597                                   "l3_tbl", &l3_tbl_ptr, NULL);
   1598     if (BCM_FAILURE(ret_val)) {
   1599         l3_tbl_ptr = NULL;
   1600     }
   1601 
   1602     if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOPm)) {
   1603         ret_val = bcm_xgs3_l3_tbl_dma(unit, EGR_L3_NEXT_HOPm,
   1604                                       sizeof(egr_l3_next_hop_entry_t),
   1605                                       "egr_nh_tbl", &egr_nh_tbl_ptr, NULL);
   1606         if (BCM_FAILURE(ret_val)) {
   1607             egr_nh_tbl_ptr = NULL;
   1608         }
   1609     }
   1610 #ifdef BCM_TOMAHAWK3_SUPPORT
   1611     if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) {
   1612         ret_val = bcm_xgs3_l3_tbl_dma(unit, EGR_L3_NEXT_HOP_2m,
   1613                                       sizeof(egr_l3_next_hop_2_entry_t),
   1614                                       "egr_nh2_tbl", &egr_nh2_tbl_ptr, NULL);
   1615         if (BCM_FAILURE(ret_val)) {
   1616             egr_nh2_tbl_ptr = NULL;
   1617             goto cleanup;
   1618         }
   1619     }
   1620 #endif
   1621     /* Loop over all valid next hop entries. */
   1622     for (idx = index_min; idx <= index_max; idx++) {
   1623         uint8 nh_ent_type = -1;         /* Next hop Entry type */
   1624         bcm_l3_egress_t_init(&nh_info);
   1625         if ((NULL == l3_tbl_ptr) || (NULL == egr_nh_tbl_ptr)) {
   1626             BCM_XGS3_L3_MODULE_LOCK(unit);
   1627             ret_val = BCM_XGS3_L3_HWCALL_EXEC(unit, nh_get)(unit, idx,
   1628                                                             &nh_info);
   1629             BCM_XGS3_L3_MODULE_UNLOCK(unit);
   1630             if (BCM_FAILURE(ret_val)) {
   1631                 goto cleanup;
   1632             }
   1633         } else {
   1634             uint32                   *ing_entry_ptr = NULL;
   1635             uint32                   *egr_entry_ptr = NULL;
   1636             uint32                   *egr_entry_2_ptr = NULL;
   1637             ing_l3_next_hop_entry_t  ing_entry_null;
   1638             egr_l3_next_hop_entry_t  egr_entry_null;
   1639 
   1640             sal_memcpy(&ing_entry_null,
   1641                        soc_mem_entry_null(unit,
   1642                                           BCM_XGS3_L3_MEM(unit, nh)),
   1643                        sizeof(ing_l3_next_hop_entry_t));
   1644             sal_memcpy(&egr_entry_null,
   1645                        soc_mem_entry_null(unit, EGR_L3_NEXT_HOPm),
   1646                        sizeof(egr_l3_next_hop_entry_t));
   1647 
   1648             ing_entry_ptr =
   1649                 soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, nh),
   1650                                              uint32 *, l3_tbl_ptr, idx);
   1651 
   1652             egr_entry_ptr =
   1653                 soc_mem_table_idx_to_pointer(unit, EGR_L3_NEXT_HOPm, uint32 *,
   1654                                              egr_nh_tbl_ptr, idx);
   1655 
   1656 #ifdef BCM_TOMAHAWK3_SUPPORT
   1657             if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) {
   1658                 egr_entry_2_ptr =
   1659                     soc_mem_table_idx_to_pointer(unit, EGR_L3_NEXT_HOP_2m, uint32 *,
   1660                                                  egr_nh2_tbl_ptr, idx);
   1661             }
   1662 #endif
   1663 
   1664             if (sal_memcmp(ing_entry_ptr, &ing_entry_null,
   1665                            BCM_XGS3_L3_ENT_SZ(unit, nh)) ||
   1666                 sal_memcmp(egr_entry_ptr, &egr_entry_null,
   1667                            soc_mem_entry_bytes(unit, EGR_L3_NEXT_HOPm))) {
   1668                 (void)_bcm_xgs3_nh_entry_parse(unit, ing_entry_ptr,
   1669                                                egr_entry_ptr, egr_entry_2_ptr, idx, &nh_info, &nh_ent_type);
   1670             }
   1671         }
   1672         /* If only L3 Intf(L3 Intf 0) is programmed , checking whther the entry type is valid or not */
   1673         if (!sal_memcmp(&nh_info, &nh_null, sizeof(bcm_l3_egress_t)) && (6 != nh_ent_type)) {
   1674             continue;
   1675         }
   1676         if (idx == index_min) {
   1677             /* This corresponds to the CPU */
   1678             BCM_XGS3_L3_ENT_HASH(tbl_ptr, idx) = 0;
   1679         } else {
   1680             /* Compute hash normally */
   1681             _bcm_xgs3_nh_map_api_data_to_hw(unit, &nh_info);
   1682             _bcm_xgs3_nh_hash_calc(unit, &nh_info,
   1683                                    &BCM_XGS3_L3_ENT_HASH(tbl_ptr, idx));
   1684 
   1685             /* Update hash & reference count info. */
   1686             if (egressMode) {
   1687                 BCM_XGS3_L3_ENT_INIT(tbl_ptr, idx, _BCM_SINGLE_WIDE, BCM_XGS3_L3_ENT_HASH(tbl_ptr, idx));
   1688             }
   1689         }
   1690 
   1691         /*
   1692          * Set to indicate that L3 interface is used in Next Hop entry.
   1693          * This is used to skip the Next Hop table search in
   1694          * _bcm_fb_nh_intf_is_tnl_update().
   1695          */
   1696         BCM_XGS3_L3_INTF_USED_NH_SET(unit, nh_info.intf);
   1697 
   1698         BCM_XGS3_L3_NH_CNT(unit)++;
   1699 #ifdef BCM_RIOT_SUPPORT
   1700         if (BCMI_RIOT_IS_ENABLED(unit)) {
   1701                 bcmi_l3_nh_assoc_ol_ul_link_reinit(unit, idx);
   1702             }
   1703         if ((tbl_ptr->split_idx > 0) && (idx < tbl_ptr->split_idx)) {
   1704             tbl_ptr->split_maxused = idx;
   1705         } else
   1706 #endif
   1707         {
   1708             tbl_ptr->idx_maxused = idx;
   1709         }
   1710     }
   1711     if (l3_tbl_ptr) {
   1712         soc_cm_sfree(unit, l3_tbl_ptr);
   1713         l3_tbl_ptr = NULL;
   1714     }
   1715 
   1716     /*
   1717      * NH table is referenced to from three different tables
   1718      * DEFIP, L3_ENTRY_IPV4 and L3_ENTRY_IPV6; In this routine,
   1719      * we update NH software state based on references from
   1720      * L3_ENTRY_IPV4 and L3_ENTRY_IPV6; References from DEFIP
   1721      * table will be accounted for in ecmp_reinit() (See below)
   1722      * Recover nh usecount from IPv4 unicast L3 table
   1723      */
   1724 
   1725 #if defined(BCM_HAWKEYE_SUPPORT)
   1726     /*
   1727      * Update NH table reference count with software DEFIP table.
   1728      */
   1729     if (SOC_IS_HAWKEYE(unit)) {
   1730         /* Get l3 prefixes table. */
   1731         rp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
   1732 
   1733         /* Iterate over all host rules try to match passed address. */
   1734         for (idx = 0; idx < BCM_XGS3_L3_RP_MAX_PREFIXES(unit); idx++) {
   1735             if (!(rp_tbl_ptr->l3_arr[idx].flags & BCM_XGS3_L3_ENT_VALID)) {
   1736                 continue;
   1737             }
   1738             BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_ptr,
   1739                                         rp_tbl_ptr->l3_arr[idx].nh_idx,
   1740                                         _BCM_SINGLE_WIDE);
   1741         }
   1742         ret_val = BCM_E_NONE;
   1743         goto cleanup;
   1744     }
   1745 #endif
   1746     if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, v4))) {
   1747         index_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, v4));
   1748         index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, v4));
   1749         ret_val = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, v4),
   1750                                       BCM_XGS3_L3_ENT_SZ(unit, v4),
   1751                                       "l3_tbl", &l3_tbl_ptr, NULL);
   1752         if (BCM_FAILURE(ret_val)) {
   1753             l3_tbl_ptr = NULL;
   1754         }
   1755         /* Loop over all valid IPV4 unicast entries to get nh use count. */
   1756         for (idx = index_min; idx <= index_max; idx++) {
   1757             l3_cfg.l3c_flags = 0;
   1758             BCM_XGS3_L3_MODULE_LOCK(unit);
   1759             ret_val = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get_by_idx)(
   1760                           unit, l3_tbl_ptr, idx,
   1761                           &l3_cfg, &nh_idx);
   1762             BCM_XGS3_L3_MODULE_UNLOCK(unit);
   1763             if (ret_val == BCM_E_NOT_FOUND) {
   1764                 continue;
   1765             } else if (BCM_FAILURE(ret_val)) {
   1766                 goto cleanup;
   1767             }
   1768             if ((l3_cfg.l3c_flags & BCM_L3_IP6) == BCM_L3_IP6) {
   1769                 continue;
   1770             }
   1771             if ((l3_cfg.l3c_flags & BCM_L3_IPMC) == BCM_L3_IPMC) {
   1772                 continue;
   1773             }
   1774             BCM_XGS3_L3_IP4_CNT(unit)++;
   1775             if((l3_cfg.l3c_flags & BCM_L3_MULTIPATH) != BCM_L3_MULTIPATH) {
   1776                 BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_ptr, nh_idx, _BCM_SINGLE_WIDE);
   1777             }
   1778         }
   1779         if (l3_tbl_ptr) {
   1780             soc_cm_sfree(unit, l3_tbl_ptr);
   1781             l3_tbl_ptr = NULL;
   1782         }
   1783     }
   1784 
   1785     if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, v6))) {
   1786         index_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, v6));
   1787         index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, v6));
   1788         ret_val = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, v6),
   1789                                       BCM_XGS3_L3_ENT_SZ(unit, v6),
   1790                                       "l3_tbl", &l3_tbl_ptr, NULL);
   1791         if (BCM_FAILURE(ret_val)) {
   1792             l3_tbl_ptr = NULL;
   1793         }
   1794         /*
   1795          * Loop over all valid IPV6 unicast entries to get nh use count.
   1796          */
   1797         for (idx = index_min; idx <= index_max; idx++) {
   1798             flex_v4_entry = 0;
   1799             l3_cfg.l3c_flags = BCM_L3_IP6;
   1800             BCM_XGS3_L3_MODULE_LOCK(unit);
   1801             ret_val = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get_by_idx)(
   1802                 unit, l3_tbl_ptr, idx, &l3_cfg, &nh_idx);
   1803             BCM_XGS3_L3_MODULE_UNLOCK(unit);
   1804             if (ret_val == BCM_E_NOT_FOUND) {
   1805                 continue;
   1806             } else if (BCM_FAILURE(ret_val)) {
   1807                 goto cleanup;
   1808             }
   1809 #if defined(BCM_TRIDENT3_SUPPORT)
   1810             if (soc_feature(unit, soc_feature_flex_flow)) {
   1811                 soc_field_t data_type = 0;
   1812                 uint32 view_id = 0;
   1813                 int rv, alloc = FALSE;
   1814                 uint32 *buf_entry = NULL;
   1815                 soc_mem_t l3_mem = BCM_XGS3_L3_MEM(unit, v6);
   1816 
   1817                 if (l3_tbl_ptr == NULL) {
   1818                     BCM_XGS3_L3_ALLOC(buf_entry, BCM_XGS3_L3_ENT_SZ(unit, v6),
   1819                             "buf entry");
   1820                     if (buf_entry == NULL) {
   1821                         ret_val = BCM_E_MEMORY;
   1822                         goto cleanup;
   1823                     }
   1824                     ret_val = BCM_XGS3_MEM_READ(unit, l3_mem, idx, buf_entry);
   1825                     if (ret_val != BCM_E_NONE) {
   1826                         sal_free(buf_entry);
   1827                         goto cleanup;
   1828                     }
   1829                     alloc = TRUE;
   1830                 } else {
   1831                     buf_entry = soc_mem_table_idx_to_pointer(unit, l3_mem,
   1832                                 uint32 *, l3_tbl_ptr, idx);
   1833                 }
   1834                 if (soc_mem_field_valid(unit, l3_mem, DATA_TYPEf)) {
   1835                     data_type = soc_mem_field32_get(unit, l3_mem,
   1836                                     buf_entry, DATA_TYPEf);
   1837                     rv = soc_flow_db_mem_to_view_id_get(unit,
   1838                             l3_mem,
   1839                             SOC_FLOW_DB_KEY_TYPE_INVALID,
   1840                             data_type,
   1841                             0,
   1842                             NULL,
   1843                             &view_id);
   1844                     if (rv == BCM_E_NONE) {
   1845                         if (SOC_MEM_FIELD_VALID(unit, view_id, IPV4__SIPf) ||
   1846                             SOC_MEM_FIELD_VALID(unit, view_id, IPV4__DIPf)) {
   1847                             flex_v4_entry = 1;
   1848                         }
   1849                     }
   1850                 }
   1851                 if (alloc == TRUE) {
   1852                     sal_free(buf_entry);
   1853                 }
   1854             }
   1855 #endif
   1856             if (!flex_v4_entry && ((l3_cfg.l3c_flags & BCM_L3_IP6) != BCM_L3_IP6)) {
   1857                 continue;
   1858             }
   1859             if (!flex_v4_entry && ((l3_cfg.l3c_flags & BCM_L3_IPMC) == BCM_L3_IPMC)) {
   1860                 continue;
   1861             }
   1862 
   1863             if (flex_v4_entry) {
   1864                 BCM_XGS3_L3_IP4_CNT(unit)++;
   1865             } else {
   1866                 BCM_XGS3_L3_IP6_CNT(unit)++;
   1867             }
   1868 
   1869             if((l3_cfg.l3c_flags & BCM_L3_MULTIPATH) != BCM_L3_MULTIPATH) {
   1870                 BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_ptr, nh_idx, _BCM_SINGLE_WIDE);
   1871             }
   1872         }
   1873         if (l3_tbl_ptr) {
   1874             soc_cm_sfree(unit, l3_tbl_ptr);
   1875             l3_tbl_ptr = NULL;
   1876         }
   1877     }
   1878 #if defined(BCM_TRIUMPH3_SUPPORT)
   1879         if (soc_feature(unit, soc_feature_l3_extended_host_entry)) {
   1880             if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, v4_2))) {
   1881                 /* Loop over all valid IPV4 unicast entries to get nh use count. */
   1882                 index_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, v4_2));
   1883                 index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, v4_2));
   1884                 ret_val = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, v4_2),
   1885                                               BCM_XGS3_L3_ENT_SZ(unit, v4_2),
   1886                                               "l3_tbl", &l3_tbl_ptr, NULL);
   1887                 if (BCM_FAILURE(ret_val)) {
   1888                     l3_tbl_ptr = NULL;
   1889                 }
   1890                 for (idx = index_min; idx <= index_max; idx++) {
   1891                     l3_cfg.l3c_flags = BCM_L3_DEREFERENCED_NEXTHOP;
   1892                     BCM_XGS3_L3_MODULE_LOCK(unit);
   1893                     ret_val = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get_by_idx)(unit, l3_tbl_ptr,
   1894                                                                            idx, &l3_cfg,
   1895                                                                            &nh_idx);
   1896                     BCM_XGS3_L3_MODULE_UNLOCK(unit);
   1897                     if (ret_val == BCM_E_NOT_FOUND) {
   1898                         continue;
   1899                     } else if (BCM_FAILURE(ret_val)) {
   1900                         goto cleanup;
   1901                     }
   1902                     if ((l3_cfg.l3c_flags & BCM_L3_IP6) == BCM_L3_IP6) {
   1903                         continue;
   1904                     }
   1905                     if ((l3_cfg.l3c_flags & BCM_L3_IPMC) == BCM_L3_IPMC) {
   1906                         continue;
   1907                     }
   1908                     BCM_XGS3_L3_IP4_CNT(unit)++;
   1909                 }
   1910                 if (l3_tbl_ptr) {
   1911                     soc_cm_sfree(unit, l3_tbl_ptr);
   1912                     l3_tbl_ptr = NULL;
   1913                 }
   1914             }
   1915             if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, v6_4))) {
   1916                 index_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, v6_4));
   1917                 index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, v6_4));
   1918                 ret_val = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, v6_4),
   1919                                               BCM_XGS3_L3_ENT_SZ(unit, v6_4),
   1920                                               "l3_tbl", &l3_tbl_ptr, NULL);
   1921                 if (BCM_FAILURE(ret_val)) {
   1922                     l3_tbl_ptr = NULL;
   1923                 }
   1924                 /* Loop over all valid IPV6 unicast entries to get nh use count. */
   1925                 for (idx = index_min; idx <= index_max; idx++) {
   1926                     l3_cfg.l3c_flags = BCM_L3_IP6 | BCM_L3_DEREFERENCED_NEXTHOP;
   1927                     BCM_XGS3_L3_MODULE_LOCK(unit);
   1928                     ret_val = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get_by_idx)(unit, l3_tbl_ptr,
   1929                                                                            idx, &l3_cfg,
   1930                                                                            &nh_idx);
   1931                     BCM_XGS3_L3_MODULE_UNLOCK(unit);
   1932                     if (ret_val == BCM_E_NOT_FOUND) {
   1933                         continue;
   1934                     } else if (BCM_FAILURE(ret_val)) {
   1935                         goto cleanup;
   1936                     }
   1937                     if ((l3_cfg.l3c_flags & BCM_L3_IP6) != BCM_L3_IP6) {
   1938                         continue;
   1939                     }
   1940                     if ((l3_cfg.l3c_flags & BCM_L3_IPMC) == BCM_L3_IPMC) {
   1941                         continue;
   1942                     }
   1943                     BCM_XGS3_L3_IP6_CNT(unit)++;
   1944 #if defined(BCM_TRIDENT3_SUPPORT)
   1945                     if (soc_feature(unit, soc_feature_flex_flow)) {
   1946                         soc_field_t data_type_64 = 0;
   1947                         uint32 view_id_64 = 0;
   1948                         int rv_64, alloc = FALSE;
   1949                         uint32 *buf_entry_64 = NULL;
   1950                         soc_mem_t l3_mem_64 = BCM_XGS3_L3_MEM(unit, v6_4);
   1951                         if (l3_tbl_ptr == NULL) {
   1952                             BCM_XGS3_L3_ALLOC(buf_entry_64, BCM_XGS3_L3_ENT_SZ(unit, v6_4),
   1953                                     "buf entry 64");
   1954                             if (buf_entry_64 == NULL) {
   1955                                 ret_val = BCM_E_MEMORY;
   1956                                 goto cleanup;
   1957                             }
   1958                             ret_val = BCM_XGS3_MEM_READ(unit, l3_mem_64, idx, buf_entry_64);
   1959                             if (ret_val != BCM_E_NONE) {
   1960                                 sal_free(buf_entry_64);
   1961                                 goto cleanup;
   1962                             }
   1963                             alloc = TRUE;
   1964                         } else {
   1965                             buf_entry_64 = soc_mem_table_idx_to_pointer(unit, l3_mem_64,
   1966                                           uint32 *, l3_tbl_ptr, idx);
   1967                         }
   1968                         if (soc_mem_field_valid(unit, l3_mem_64, DATA_TYPEf)) {
   1969                             data_type_64 = soc_mem_field32_get(unit, l3_mem_64,
   1970                                                buf_entry_64, DATA_TYPEf);
   1971                             rv_64 = soc_flow_db_mem_to_view_id_get(unit,
   1972                                     l3_mem_64,
   1973                                     SOC_FLOW_DB_KEY_TYPE_INVALID,
   1974                                     data_type_64,
   1975                                     0,
   1976                                     NULL,
   1977                                     &view_id_64);
   1978                             if (rv_64 == BCM_E_NONE) {
   1979                                 if (SOC_MEM_FIELD_VALID(unit, view_id_64, IPV6__SIPf) ||
   1980                                         SOC_MEM_FIELD_VALID(unit, view_id_64, IPV6__DIPf)) {
   1981                                     if((l3_cfg.l3c_flags & BCM_L3_MULTIPATH) != BCM_L3_MULTIPATH) {
   1982                                         BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_ptr, nh_idx, _BCM_SINGLE_WIDE);
   1983                                     }
   1984                                 }
   1985                             }
   1986                         }
   1987                         if (alloc == TRUE) {
   1988                             sal_free(buf_entry_64);
   1989                         }
   1990                     }
   1991 #endif
   1992                 }
   1993             }
   1994         }
   1995 #endif
   1996     ret_val = BCM_E_NONE;
   1997 cleanup:
   1998     if (l3_tbl_ptr) {
   1999         soc_cm_sfree(unit, l3_tbl_ptr);
   2000     }
   2001     if (egr_nh_tbl_ptr) {
   2002         soc_cm_sfree(unit, egr_nh_tbl_ptr);
   2003     }
   2004 #ifdef BCM_TOMAHAWK3_SUPPORT
   2005     if (egr_nh2_tbl_ptr) {
   2006         soc_cm_sfree(unit, egr_nh2_tbl_ptr);
   2007     }
   2008 #endif
   2009     return ret_val;
   2010 }
   2011 
   2012 #ifdef BCM_TRIDENT2_SUPPORT
   2013 /*
   2014  * Function:
   2015  *     _bcm_xgs3_l3_ingress_intf_reinit
   2016  * Purpose:
   2017  *      Recover l3 ingress interfaces info
   2018  * Parameters:
   2019  *      unit  - SOC unit number
   2020  * Returns:
   2021  *      BCM_E_XXX
   2022  */
   2023 STATIC int
   2024 _bcm_xgs3_l3_ingress_intf_reinit(int unit)
   2025 {
   2026     int idx;                      /* Iteration index.              */
   2027     int rv = BCM_E_NONE;     /* Operation return status.*/
   2028     uint8 index;
   2029     char   *iif_tbl_ptr           = NULL; /* IIF Table dma pointer.           */
   2030     uint32 *iif_entry_ptr         = NULL; /* IIF Profile entry buffer pointer.*/
   2031 
   2032     if (BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) > 0) {
   2033         rv = bcm_xgs3_l3_tbl_dma(unit, L3_IIFm,
   2034                                  sizeof(iif_entry_t),
   2035                                  "l3_iif", &iif_tbl_ptr, NULL);
   2036         if (BCM_FAILURE(rv)) {
   2037             goto cleanup;
   2038         }
   2039     }
   2040 
   2041     for (idx=0; idx < (BCM_XGS3_L3_ING_IF_TBL_SIZE(unit)); idx++) {
   2042 
   2043         if (!(SHR_BITGET(BCM_XGS3_L3_ING_IF_INUSE(unit), idx))) {
   2044             continue;
   2045         }
   2046 
   2047         iif_entry_ptr =
   2048             soc_mem_table_idx_to_pointer(unit, L3_IIFm, uint32 *,
   2049                                          iif_tbl_ptr, idx);
   2050 
   2051         /* coverity[var_deref_model : FALSE] */
   2052         index = soc_mem_field32_get(unit, L3_IIFm, iif_entry_ptr,
   2053                                     L3_IIF_PROFILE_INDEXf);
   2054 
   2055         rv = _bcm_l3_iif_profile_entry_reference(unit, index, 1);
   2056         if (BCM_FAILURE(rv)) {
   2057             goto cleanup;
   2058         }
   2059     }
   2060 cleanup:
   2061     if (iif_tbl_ptr) {
   2062         soc_cm_sfree(unit, iif_tbl_ptr);
   2063     }
   2064 
   2065     return rv;
   2066 }
   2067 #endif
   2068 
   2069 STATIC int
   2070 _bcm_xgs3_l3_intf_reinit(int unit)
   2071 {
   2072     int idx;                      /* Iteration index.              */
   2073     _bcm_l3_intf_cfg_t intf_info; /* Interface configuration.      */ 
   2074     bcm_tunnel_initiator_t tnl_info;/* Tunnel initiator struct. */
   2075     int ret_val;                  /* Operation return value.       */
   2076     int entry_width;              /* Tunnel entry width.           */
   2077     bcm_mac_t  mac;
   2078     _bcm_l3_tbl_t *tbl_ptr;       /* L3 egress intf table pointer. */
   2079     soc_mem_t mem;
   2080     char      *l3_tbl_ptr      = NULL; /* Table dma pointer.             */
   2081     uint32    *l3_if_entry_ptr = NULL; /* Interface read buffer address. */
   2082     _bcm_l3_intf_fields_t *fld = NULL; /* Interface table common fields. */
   2083 
   2084     int ingress_map_mode = 0;
   2085 #ifdef BCM_RIOT_SUPPORT
   2086     egr_mac_da_profile_entry_t macda;
   2087     int profiled_mac = 0;
   2088     int macda_index = -1;
   2089 #endif
   2090     bcm_l3_intf_t intf_tmp;
   2091 
   2092     /* Make sure hw call pointer was initialized. */
   2093     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, if_get)) {
   2094         return (BCM_E_UNAVAIL);
   2095     }
   2096 
   2097     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, intf);
   2098     /* Get first egr intf index.  */
   2099     if (soc_feature(unit, soc_feature_l3_egr_intf_zero_invalid)) {
   2100         tbl_ptr->idx_min = soc_mem_index_min(unit,
   2101                 BCM_XGS3_L3_MEM(unit, intf)) + 1;
   2102     } else {
   2103         tbl_ptr->idx_min = soc_mem_index_min(unit,
   2104                 BCM_XGS3_L3_MEM(unit, intf));
   2105     }
   2106     /* Get last egr intf index. */
   2107     tbl_ptr->idx_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, intf));
   2108     /* Set egr intf max used to first entry.(table empty) */
   2109     tbl_ptr->idx_maxused = tbl_ptr->idx_min;
   2110 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   2111     /* Set up split table limits */
   2112     tbl_ptr->split_idx      = 0;
   2113     tbl_ptr->split_maxused  = 0;
   2114 #endif
   2115 
   2116     /* Get interface table start & end index. */
   2117     BCM_XGS3_L3_IF_TBL_SIZE(unit) = tbl_ptr->idx_max + 1;
   2118     sal_memset (mac, 0, sizeof(bcm_mac_t));
   2119     sal_memset(&intf_info, 0, sizeof(_bcm_l3_intf_cfg_t));
   2120 
   2121     mem = BCM_XGS3_L3_MEM(unit, intf);
   2122     ret_val = bcm_xgs3_l3_tbl_dma(unit, mem, BCM_XGS3_L3_ENT_SZ(unit, intf),
   2123                                   "l3_tbl", &l3_tbl_ptr, NULL);
   2124     if (BCM_FAILURE(ret_val)) {
   2125         l3_tbl_ptr = NULL;
   2126     }
   2127 
   2128     /* Loop over all valid interfaces. */
   2129     for (idx = tbl_ptr->idx_min; idx <= tbl_ptr->idx_max; idx++) {
   2130 
   2131         /* Read interface from hardware. */
   2132         intf_info.l3i_index = idx;
   2133         if (NULL == l3_tbl_ptr) {
   2134             BCM_XGS3_L3_MODULE_LOCK(unit);
   2135             ret_val = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get)(unit, &intf_info);
   2136             BCM_XGS3_L3_MODULE_UNLOCK(unit);
   2137             if (BCM_FAILURE(ret_val)) {
   2138                 goto cleanup;
   2139             }
   2140         } else {
   2141             l3_if_entry_ptr =
   2142                 soc_mem_table_idx_to_pointer(unit, mem, uint32 *,
   2143                                              l3_tbl_ptr,
   2144                                              intf_info.l3i_index);
   2145 
   2146             /* Extract interface information. */
   2147             fld = (_bcm_l3_intf_fields_t *)BCM_XGS3_L3_MEM_FIELDS(unit, intf);
   2148 
   2149             /* Get vlan id. */
   2150 #ifdef BCM_RIOT_SUPPORT
   2151             if (soc_feature(unit, soc_feature_riot)) {
   2152                 if (soc_feature(unit,soc_feature_egr_intf_vlan_vfi_deoverlay)) {
   2153                    profiled_mac = soc_mem_field32_get(unit, mem, l3_if_entry_ptr,
   2154                    MAC_ADDRESS_OVERLAY_TYPEf);
   2155                    macda_index = soc_mem_field32_get(unit, mem, l3_if_entry_ptr,
   2156                    MAC_ADDRESS_PROFILE_IDXf);
   2157                 }
   2158                 if (profiled_mac) {
   2159                     /* Read entry from MAC-DA-PROFILEm */
   2160                     BCM_IF_ERROR_RETURN (soc_mem_read(unit, EGR_MAC_DA_PROFILEm,
   2161                         MEM_BLOCK_ANY, macda_index, &macda));
   2162                     /* Get mac address from EGR_MACDA_PROFILE. */
   2163                     soc_mem_mac_addr_get(unit, EGR_MAC_DA_PROFILEm, &macda,
   2164                         MAC_ADDRESSf, intf_info.l3i_mac_addr);
   2165 
   2166                     if (soc_mem_field_valid(unit, mem, DATA_TYPEf) &&
   2167                     (0 == soc_mem_field32_get(unit, mem, l3_if_entry_ptr,
   2168                         DATA_TYPEf))) {
   2169 
   2170                         _bcm_common_profile_mem_ref_cnt_update(unit,
   2171                             EGR_MAC_DA_PROFILEm, macda_index, 1);
   2172                     }
   2173                 } else {
   2174                     /* Get mac address from EGR_L3_INTF. */
   2175                     soc_mem_mac_addr_get(unit, mem, l3_if_entry_ptr,
   2176                         fld->mac_addr, intf_info.l3i_mac_addr);
   2177                 }
   2178                 /*VLAN_VFI_OVERLAY_TYPE is not required in TD3 */
   2179                 if (soc_feature(unit,soc_feature_egr_intf_vlan_vfi_deoverlay)) {
   2180                     if (profiled_mac) {
   2181                         /* Use profiled_mac indicator to confirm presence of VFI and read the same */
   2182                     _BCM_VPN_SET(intf_info.l3i_vid, _BCM_VPN_TYPE_VFI,
   2183                         soc_mem_field32_get(unit, mem, l3_if_entry_ptr, VFIf));
   2184                     } else {
   2185                         intf_info.l3i_vid =
   2186                             soc_mem_field32_get(unit, mem, l3_if_entry_ptr,
   2187                                  fld->vlan_id);
   2188                     }
   2189                 } else if (soc_mem_field32_get(unit, mem, l3_if_entry_ptr,
   2190                                         VLAN_VFI_OVERLAY_TYPEf)) {
   2191                     _BCM_VPN_SET(intf_info.l3i_vid, _BCM_VPN_TYPE_VFI,
   2192                                  soc_mem_field32_get(unit, mem,
   2193                                                      l3_if_entry_ptr, VFIf));
   2194                 } else {
   2195                     intf_info.l3i_vid =
   2196                         soc_mem_field32_get(unit, mem, l3_if_entry_ptr,
   2197                                             fld->vlan_id);
   2198                 }
   2199             } else
   2200 #endif
   2201             {
   2202                 intf_info.l3i_vid = soc_mem_field32_get(
   2203                     unit, mem, l3_if_entry_ptr, fld->vlan_id);
   2204                 /* Get mac address. */
   2205                 soc_mem_mac_addr_get(unit, mem, l3_if_entry_ptr,
   2206                     fld->mac_addr, intf_info.l3i_mac_addr);
   2207             }
   2208 
   2209             /* Get tunnel index. */
   2210             if (SOC_MEM_FIELD_VALID(unit, mem, fld->tnl_id)) {
   2211                 intf_info.l3i_tunnel_idx = soc_mem_field32_get(
   2212                     unit, mem, l3_if_entry_ptr, fld->tnl_id);
   2213             }
   2214         }
   2215 
   2216         if (!sal_memcmp(intf_info.l3i_mac_addr, mac, sizeof(bcm_mac_t)) &&
   2217             !BCM_VLAN_VALID(intf_info.l3i_vid)){
   2218             continue;
   2219         }
   2220 
   2221         if (!BCM_L3_INTF_USED_GET(unit, idx)) {
   2222             /* Mark interface as used */
   2223             BCM_L3_INTF_USED_SET(unit, idx);
   2224         }
   2225 
   2226 #ifdef BCM_TRIUMPH_SUPPORT
   2227         /* Reference count for VLAN VRF */
   2228         if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
   2229             ret_val = bcm_xgs3_l3_ingress_intf_map_get(unit, &ingress_map_mode);
   2230             if (BCM_FAILURE(ret_val)) {
   2231                 goto cleanup;
   2232             }
   2233         }
   2234 #endif
   2235         if (!ingress_map_mode ||
   2236                 SOC_MEM_FIELD_VALID(unit, VLAN_TABm, VRF_IDf)) {
   2237             /* Increment ref count on related VLAN VRF here */
   2238             BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ing_intf),
   2239                     intf_info.l3i_vid, _BCM_SINGLE_WIDE);
   2240         }
   2241 
   2242         /* Reference counts & signatures for tnl_init and adj_mac tables. */
   2243         if (intf_info.l3i_tunnel_idx > 0) {
   2244             bcm_tunnel_initiator_t_init(&tnl_info);
   2245             bcm_l3_intf_t_init(&intf_tmp);
   2246             intf_tmp.l3a_intf_id = intf_info.l3i_index;
   2247             ret_val = bcm_xgs3_tunnel_initiator_get(unit, &intf_tmp, &tnl_info);
   2248             if (BCM_FAILURE(ret_val)) {
   2249                 /* For hurricane EGR_L3_INTF:TUNNEL_INDEXf is InValid */
   2250                 /* Below check (including SOC_IS_HURRICANE) should be replaced
   2251                    with intf_info.l3i_tunnel_idx == 0 check */
   2252                 /* ================================================== */
   2253                 if ((ret_val == BCM_E_NOT_FOUND) &&
   2254                     (SOC_IS_HURRICANE(unit) || SOC_IS_HURRICANE2(unit))) {
   2255                      continue;
   2256                 }
   2257                 goto cleanup;
   2258             }
   2259             if ((tnl_info.type != bcmTunnelTypeMpls) ||
   2260                 !BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, tnl_init), \
   2261                                          intf_info.l3i_tunnel_idx)) {
   2262             _bcm_xgs3_tnl_init_hash_calc(unit, &tnl_info,
   2263                           &BCM_XGS3_L3_ENT_HASH(BCM_XGS3_L3_TBL_PTR(unit, tnl_init),
   2264                                                 intf_info.l3i_tunnel_idx));
   2265 
   2266             entry_width = 
   2267                 (_BCM_EGR_IP_TUNNEL_DOUBLE_WIDE_ENTRY(unit, tnl_info.type)) ? \
   2268                     _BCM_DOUBLE_WIDE : _BCM_SINGLE_WIDE;
   2269 
   2270             BCM_XGS3_L3_ENT_REF_CNT_INC (BCM_XGS3_L3_TBL_PTR(unit, tnl_init),
   2271                                          intf_info.l3i_tunnel_idx, entry_width);
   2272 
   2273         }
   2274         }
   2275     }   /* Loop over interface table. */
   2276 
   2277     ret_val = BCM_E_NONE;
   2278 
   2279 cleanup:
   2280     if (l3_tbl_ptr) {
   2281         soc_cm_sfree(unit, l3_tbl_ptr);
   2282     }
   2283     return ret_val;
   2284 }
   2285 
   2286 /*
   2287  * Function:
   2288  *      _bcm_xgs3_l3_defip_reinit
   2289  * Purpose:
   2290  *      Recover basic DEFIP table info
   2291  * Parameters:
   2292  *      unit  - SOC unit number
   2293  * Returns:
   2294  *      BCM_E_XXX
   2295  */
   2296 STATIC int
   2297 _bcm_xgs3_l3_defip_table_reinit(int unit)
   2298 {
   2299     int index_min = 0;                /* First entry index.        */
   2300     int index_max = 0;                /* Last  entry index.        */
   2301     int rv;                       /* Operation return status.  */
   2302 
   2303 #if defined(BCM_HAWKEYE_SUPPORT)
   2304     if (SOC_IS_HAWKEYE(unit)) {
   2305         BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) = BCM_XGS3_L3_RP_MAX_PREFIXES(unit);
   2306         return (BCM_E_NONE);
   2307     }
   2308 #endif
   2309     if (soc_feature(unit, soc_feature_esm_support)) {
   2310 #ifdef BCM_TRIUMPH_SUPPORT
   2311         soc_mem_t mem_v4;      /* IPv4 Route table memory.             */
   2312 
   2313         BCM_IF_ERROR_RETURN(_bcm_tr_l3_defip_mem_get(unit, 0, 0, &mem_v4));
   2314         index_min = soc_mem_index_min(unit, mem_v4);
   2315         index_max = soc_mem_index_max(unit, mem_v4);
   2316 #endif
   2317     } else {
   2318         if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, defip))) {
   2319             index_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, defip));
   2320             index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, defip));
   2321         } else {
   2322             BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) = 0;
   2323             return (BCM_E_NONE);
   2324         }
   2325     }
   2326     BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) = index_max - index_min + 1;
   2327 
   2328     /* Traverse the defip table */
   2329     rv = bcm_xgs3_defip_traverse(unit, 0, index_min, index_max, NULL, NULL);
   2330     if (BCM_FAILURE(rv)) {
   2331        return (rv);
   2332     }
   2333 
   2334     if (soc_feature(unit, soc_feature_esm_support)) {
   2335 #ifdef BCM_TRIUMPH_SUPPORT
   2336         soc_mem_t mem_v6;      /* IPv6 Route table memory.             */
   2337 
   2338         BCM_IF_ERROR_RETURN
   2339             (_bcm_tr_l3_defip_mem_get(unit, BCM_L3_IP6, 0, &mem_v6));
   2340         index_min = soc_mem_index_min(unit, mem_v6);
   2341         index_max = soc_mem_index_max(unit, mem_v6);
   2342 #endif
   2343     }
   2344 
   2345     /* If warmboot and l3_alpm mode is enabled skip walking defip for IPv6
   2346        First defip(IPv4) walk above would have travesered all defip entries*/
   2347     if (soc_feature(unit, soc_feature_alpm) &&
   2348         soc_property_get(unit, spn_L3_ALPM_ENABLE, 0) &&
   2349         SOC_WARM_BOOT(unit)) {
   2350         return (rv);
   2351     } else {
   2352         rv = bcm_xgs3_defip_traverse(unit, BCM_L3_IP6, index_min,
   2353                                      index_max, NULL, NULL);
   2354         if (BCM_FAILURE(rv)) {
   2355            return (rv);
   2356         }
   2357     }
   2358     return (rv);
   2359 }
   2360 
   2361 #if defined(BCM_TRIUMPH2_SUPPORT)
   2362 /*
   2363  * Function:
   2364  *      _bcm_xgs3_l3_flexstat_recover
   2365  * Purpose:
   2366  *      Recover VRF counter table info
   2367  * Parameters:
   2368  *      unit  - SOC unit number
   2369  * Returns:
   2370  *      BCM_E_XXX
   2371  */
   2372 STATIC int
   2373 _bcm_xgs3_l3_flexstat_recover(int unit)
   2374 {
   2375     int index_min;                /* First entry index.        */
   2376     int index_max;                /* Last  entry index.        */
   2377     int vrf;                      /* VRF table index           */
   2378     int fs_idx;                   /* Service counter index     */
   2379     int rv = BCM_E_NONE;          /* Operation return status.  */
   2380     vrf_entry_t vrf_entry;        /* VRF memory entry          */
   2381 
   2382     index_min = soc_mem_index_min(unit, VRFm);
   2383     index_max = soc_mem_index_max(unit, VRFm);
   2384 
   2385     /* Traverse the VRF table */
   2386     for (vrf = index_min; vrf <= index_max; vrf++) {
   2387         rv = READ_VRFm(unit, MEM_BLOCK_ANY, vrf, &vrf_entry);
   2388         if (BCM_FAILURE(rv)) {
   2389             break;
   2390         }
   2391         fs_idx = soc_VRFm_field32_get(unit, &vrf_entry, SERVICE_CTR_IDXf);
   2392         if (fs_idx) {
   2393             _bcm_esw_flex_stat_reinit_add(unit,
   2394                                 _bcmFlexStatTypeVrf, fs_idx, vrf);
   2395         }
   2396     }
   2397 
   2398     return (rv);
   2399 }
   2400 #endif /* BCM_TRIUMPH2_SUPPORT */
   2401 
   2402 #if defined(BCM_TRIDENT_SUPPORT)
   2403 int
   2404 _bcm_xgs3_trunk_nh_store_recover(int unit)
   2405 {
   2406   _bcm_l3_bookkeeping_t *l3_bk_info = L3_INFO(unit);
   2407   int rv=BCM_E_NONE, trunk_idx=-1;
   2408   uint32 reg_val=0;
   2409   bcm_port_t      port_iter;
   2410   bcm_module_t  local_modid=0;
   2411 
   2412     BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get (unit, &local_modid));
   2413     /* EGR_PORT_TO_NHI_MAPPING is not Supported in TD2PLUS, Hence 
   2414      * Returning Success */
   2415     if (soc_feature(unit, soc_feature_multi_next_hops_on_port)) {
   2416         return BCM_E_NONE;
   2417     }
   2418 
   2419     PBMP_E_ITER(unit, port_iter) {
   2420         if (SOC_IS_STACK_PORT(unit, port_iter)) {
   2421             continue;
   2422         }
   2423         BCM_IF_ERROR_RETURN(
   2424                 READ_EGR_PORT_TO_NHI_MAPPINGr(unit, port_iter, &reg_val));
   2425         rv = bcm_esw_trunk_find(unit, local_modid, port_iter, &trunk_idx);
   2426         if (rv == BCM_E_NONE) {
   2427             l3_bk_info->l3_trunk_nh_store[trunk_idx] =
   2428                    soc_reg_field_get(unit, EGR_PORT_TO_NHI_MAPPINGr, reg_val, NEXT_HOP_INDEXf);
   2429         }
   2430     }
   2431     return BCM_E_NONE;
   2432 }
   2433 #endif /* BCM_TRIDENT_SUPPORT */
   2434 
   2435 /*
   2436  * Function:
   2437  *      _bcm_esw_l3_warmboot_recover
   2438  * Purpose:
   2439  *      Retrieve from L3 module scache.
   2440  * Parameters:
   2441  *      unit - StrataSwitch unit number.
   2442  * Returns:
   2443  *      BCM_E_XXX
   2444  */
   2445 STATIC int
   2446 _bcm_esw_l3_warmboot_recover(int unit, int32 *egrmode, int32 *ingrmode,
   2447         int32 *hostmode, int32 *intfMapmode, int *ecmp_max_paths, int *ecmp_refcnt)
   2448 {
   2449     /*
   2450      * Match with _bcm_esw_l3_warm_boot_alloc/_bcm_esw_l3_sync
   2451      */
   2452     uint8 *l3_scache_ptr;
   2453     uint16 recovered_ver;
   2454     soc_scache_handle_t scache_handle;
   2455     int alloc_sz = sizeof(int32) * 2, stable_size = 0, rv;
   2456     int additional_scache_sz = 0;
   2457     int alloc_size = 0;
   2458     int i;
   2459 #ifdef BCM_TRIUMPH3_SUPPORT
   2460     int urpfEnable;
   2461 #endif /* BCM_TRIUMPH3_SUPPORT */
   2462 #ifdef BCM_TRIUMPH2_SUPPORT
   2463     int idx;
   2464 #endif
   2465 #ifdef BCM_TRIDENT2_SUPPORT
   2466     int l3_ip4_options_recover = 0;
   2467     uint32 recovered_sz = 0;
   2468 #endif
   2469 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)
   2470     int l3_flags_recovered = 0;
   2471     int l3_flags_alloced = 0;
   2472     uint8 flag = 0;
   2473 #endif /* BCM_TRIDENT_SUPPORT || BCM_GREYHOUND2_SUPPORT */
   2474 #if defined(BCM_SCORPION_SUPPORT)
   2475     uint16              dev_id;
   2476     uint8               rev_id;
   2477 #endif
   2478 #ifdef BCM_TOMAHAWK_SUPPORT
   2479     SHR_BITDCL *ecmp_l1_flags = NULL;
   2480     SHR_BITDCL *ecmp_l2_flags = NULL;
   2481 #endif
   2482     SHR_BITDCL *ecmp_flags = NULL;
   2483 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   2484     int num_elements;
   2485 #endif
   2486 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_METROLITE_SUPPORT) ||\
   2487     defined(BCM_HURRICANE3_SUPPORT)
   2488     int skip_l3_ingress_intf_recover = FALSE;
   2489 #endif
   2490 
   2491     *egrmode = 0; /* Default values */
   2492     *ingrmode = 0;
   2493     *hostmode = 0;
   2494     *intfMapmode = 0;
   2495    
   2496     SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_L3, 0);
   2497     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
   2498     if (stable_size > 0) { /* Limited and Extended recovery only */
   2499 
   2500         if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
   2501             alloc_sz  += sizeof(int32); /* Ingress mode */
   2502             alloc_sz  += sizeof(int32); /* IntfMap mode */
   2503         }
   2504 
   2505 #if defined(BCM_SCORPION_SUPPORT)
   2506         if (SOC_IS_SCORPION(unit)) {
   2507             soc_cm_get_id(unit, &dev_id, &rev_id);
   2508 
   2509             rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE,
   2510                                          alloc_sz, &l3_scache_ptr,
   2511                                          BCM_WB_DEFAULT_VERSION, &recovered_ver);
   2512             if (BCM_FAILURE(rv)) {
   2513                 LOG_ERROR(BSL_LS_BCM_L3,
   2514                     (BSL_META_U(unit, "Failure on recovering version\n")));
   2515                 return rv;
   2516             }
   2517             if ((dev_id == BCM56820_DEVICE_ID) &&
   2518                     (recovered_ver < BCM_WB_VERSION_1_14)) {
   2519                 /* Till WB version 13, the ecmp group size was 512. */
   2520                 SOC_FEATURE_CLEAR(unit, soc_feature_l3_ecmp_2k_groups);
   2521             }
   2522         }
   2523 #endif /* BCM_SCORPION_SUPPORT */
   2524 
   2525 #ifdef BCM_TRIUMPH2_SUPPORT
   2526         /* For extended scache warmboot mode (level-2) only */
   2527         if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group) &&
   2528             BCM_XGS3_L3_MAX_ECMP_MODE(unit)                      &&
   2529             !SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) {
   2530             alloc_sz += sizeof(uint16) *
   2531                         BCM_XGS3_L3_ECMP_MAX_GROUPS(unit);
   2532         }
   2533 #endif
   2534 
   2535 #ifdef BCM_TRIUMPH3_SUPPORT
   2536         if (soc_feature(unit, soc_feature_ecmp_dlb)) {
   2537             int ecmp_dlb_alloc_sz;
   2538 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   2539             if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
   2540                 BCM_IF_ERROR_RETURN
   2541                     (bcm_th2_ecmp_dlb_wb_alloc_size_get(unit, &ecmp_dlb_alloc_sz));
   2542             } else
   2543 #endif /* BCM_TOMAHAWK2_SUPPORT */
   2544             {
   2545                 if (!SOC_IS_TRIDENT3X(unit)) {
   2546                     /* TD3TBD */
   2547                     BCM_IF_ERROR_RETURN
   2548                         (bcm_tr3_ecmp_dlb_wb_alloc_size_get(unit, &ecmp_dlb_alloc_sz));
   2549                 }
   2550             }
   2551             alloc_sz += ecmp_dlb_alloc_sz;
   2552         }
   2553 #endif /* BCM_TRIUMPH3_SUPPORT */
   2554 
   2555 #ifdef BCM_TRIUMPH2_SUPPORT
   2556         if (soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf) ||
   2557                 soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) {
   2558             int wb_alloc_sz;
   2559 
   2560             BCM_IF_ERROR_RETURN
   2561                 (bcm_tr2_l3_ecmp_defragment_buffer_wb_alloc_size_get(unit,
   2562                                                                      &wb_alloc_sz));
   2563             alloc_sz += wb_alloc_sz;
   2564         }
   2565 #endif /* BCM_TRIUMPH2_SUPPORT */
   2566 
   2567 #ifdef BCM_TRIDENT2_SUPPORT
   2568         /*
   2569          * WB version 1.4 was defined for supporting warmboot recovery of
   2570          * L3 IP4 Options profile indexes info but the relevant soc feature
   2571          * was disabled in sdk-6.2.9. The feature is enabled when the L3 scache
   2572          * version is at 1.6. So, 1.4 is just a dummy version.
   2573          */
   2574         if (soc_feature(unit, soc_feature_l3_ip4_options_profile)) {
   2575             int wb_alloc_sz;
   2576             BCM_IF_ERROR_RETURN
   2577                 (_bcm_td2_l3_ip4_options_profile_scache_len_get(unit, &wb_alloc_sz));
   2578                 alloc_sz += wb_alloc_sz;
   2579         }
   2580 
   2581         /*
   2582          * Check if scache space is allocated for l3_ip4_options_profile.
   2583          *
   2584          * SDK-6.2.9 did not allocate scache space for ip4 options profile
   2585          * although the scache version was at 1.4 (soc_feature was disabled).
   2586          * However since the relevant feature was enabled in SDK-6.3.2,
   2587          * ip4 options profile information can be recovered with 1.4.
   2588          *
   2589          * The scache size without ip4 options profile information is 24 Bytes
   2590          * To be able to recover the ip4 options profile information, the
   2591          * recovered scache size should be greater than 24 Bytes.
   2592          */
   2593         SOC_IF_ERROR_RETURN(soc_scache_ptr_get(unit, scache_handle,
   2594                                 &l3_scache_ptr, &recovered_sz));
   2595         recovered_sz -= SOC_WB_SCACHE_CONTROL_SIZE;
   2596         l3_ip4_options_recover = (recovered_sz > 24) ? 1 : 0;
   2597 
   2598         
   2599 #endif /* BCM_TRIDENT2_SUPPORT */
   2600 
   2601 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_METROLITE_SUPPORT) ||\
   2602     defined(BCM_HURRICANE3_SUPPORT)
   2603         if (soc_feature(unit, soc_feature_l3_ingress_interface) &&
   2604             !soc_feature(unit, soc_feature_l3_ingress_intf_kt2_recover)) {
   2605             alloc_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit));
   2606         }
   2607 #endif /* defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_METROLITE_SUPPORT) ||
   2608         * defined(BCM_HURRICANE3_SUPPORT)
   2609         */
   2610         /* Recover ECMP max paths from scache */
   2611         alloc_sz += sizeof(uint32);
   2612 
   2613         /* Determine ECMP_GRP entries size */
   2614         if (soc_feature(unit, soc_feature_l3)) {
   2615             alloc_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit));
   2616         }
   2617 
   2618 #ifdef BCM_TRIDENT2_SUPPORT
   2619         /* Recover ECMP Ecmp group resorting flags */
   2620 		if (soc_feature(unit, soc_feature_l3)) {
   2621             alloc_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit));
   2622         }
   2623 #endif
   2624 
   2625 #ifdef BCM_TRIUMPH3_SUPPORT
   2626         if (soc_feature(unit, soc_feature_l2gre)) {
   2627             alloc_sz +=  BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(uint8);
   2628             l3_flags_alloced = 1;
   2629         }
   2630 #endif /* BCM_TRIUMPH3_SUPPORT */    
   2631 #ifdef BCM_TRIDENT_SUPPORT
   2632         if (soc_feature(unit, soc_feature_trill)) {
   2633             if (!l3_flags_alloced) {
   2634                 alloc_sz +=  BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(uint8);
   2635                 l3_flags_alloced = 1;
   2636             }
   2637         }
   2638 #endif /* BCM_TRIDENT_SUPPORT */             
   2639 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)
   2640         if (soc_feature(unit, soc_feature_vxlan) ||
   2641             soc_feature(unit, soc_feature_vxlan_lite)) {
   2642             if (!l3_flags_alloced) {
   2643                 alloc_sz +=  BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(uint8);
   2644                 l3_flags_alloced = 1;
   2645             }
   2646         }
   2647 #endif /* BCM_TRIDENT2_SUPPORT || BCM_GREYHOUND2_SUPPORT */
   2648 
   2649     /* memory needed for multi level prot s/w state */
   2650     if (soc_feature(unit, soc_feature_l3) &&
   2651         (soc_feature(unit, soc_feature_hierarchical_protection))) {
   2652 
   2653         alloc_sz +=  (BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(int));
   2654     }
   2655 
   2656 #ifdef BCM_TRIDENT_SUPPORT
   2657         if (soc_feature(unit, soc_feature_nh_for_ifp_actions)) {
   2658             if (!l3_flags_alloced) {
   2659                 alloc_sz +=  BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(uint8);
   2660             }
   2661         }
   2662 #endif /* BCM_TRIDENT_SUPPORT */
   2663 #if defined(BCM_RIOT_SUPPORT)
   2664         if (soc_feature(unit, soc_feature_riot)) {
   2665             bcm_td2p_l3_extended_required_scache_size_get(unit, &alloc_sz);
   2666         }
   2667 #endif /* BCM_RIOT_SUPPORT */
   2668 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   2669     if (soc_feature(unit, soc_feature_dgm)) {
   2670         alloc_sz += sizeof(uint16) *
   2671                     BCM_XGS3_L3_ECMP_MAX_GROUPS(unit);
   2672     }
   2673 #endif /* BCM_TOMAHAWK2_SUPPORT */
   2674 
   2675         /* Maximum VRF IDs on the device */
   2676         alloc_sz += sizeof(uint16);
   2677 
   2678 #if defined(BCM_TRX_SUPPORT)
   2679         if (soc_feature(unit, soc_feature_l3_ingress_interface) &&
   2680                 soc_feature(unit, soc_feature_l3_ingress_intf_kt2_recover)) {
   2681             alloc_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit));
   2682         }
   2683 #endif
   2684 
   2685         rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE,
   2686                                      alloc_sz, &l3_scache_ptr,
   2687                                      BCM_WB_DEFAULT_VERSION, &recovered_ver);
   2688 
   2689         if (BCM_SUCCESS(rv)) {
   2690             /* Common to versions 1.1 and 1.0 */
   2691             sal_memcpy(egrmode, l3_scache_ptr, sizeof(*egrmode));
   2692             l3_scache_ptr += sizeof(*egrmode);
   2693             if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
   2694                 sal_memcpy(ingrmode, l3_scache_ptr, sizeof(*ingrmode));
   2695                 l3_scache_ptr += sizeof(*ingrmode);
   2696             }
   2697 
   2698             if (recovered_ver >= BCM_WB_VERSION_1_1) {
   2699                 sal_memcpy(hostmode, l3_scache_ptr, sizeof(*hostmode));
   2700                 l3_scache_ptr += sizeof(*hostmode);
   2701             }
   2702 
   2703             if (recovered_ver >= BCM_WB_VERSION_1_2) {
   2704                 if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
   2705                    sal_memcpy(intfMapmode, l3_scache_ptr, sizeof(*intfMapmode));
   2706                    l3_scache_ptr += sizeof(*intfMapmode);
   2707                 }
   2708             }
   2709 
   2710             if (recovered_ver >= BCM_WB_VERSION_1_3) {
   2711 #ifdef BCM_TRIUMPH2_SUPPORT
   2712                 /* Recover max paths per ecmp group
   2713                  * for extended scache warmboot mode (level-2) only
   2714                  */
   2715                 if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group) &&
   2716                     BCM_XGS3_L3_MAX_ECMP_MODE(unit)                      &&
   2717                     !SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) {
   2718                     for(idx=0; idx<BCM_XGS3_L3_ECMP_MAX_GROUPS(unit); idx++) {
   2719                         sal_memcpy(&(BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[idx]),
   2720                                 l3_scache_ptr, sizeof(uint16));
   2721                         l3_scache_ptr += sizeof(uint16);
   2722                     }
   2723                 }
   2724 #endif /* BCM_TRIUMPH2_SUPPORT */
   2725 
   2726 #ifdef BCM_TRIUMPH3_SUPPORT
   2727                 urpfEnable = 0;
   2728                 /* although no new scache information is synced,
   2729                  * the scache version was bumped to 1.5 here  */
   2730                 if (recovered_ver >= BCM_WB_VERSION_1_5) {
   2731                     rv = bcm_esw_switch_control_get(unit,
   2732                                                    bcmSwitchL3UrpfRouteEnable,
   2733                                                    &urpfEnable);
   2734                     if (BCM_SUCCESS(rv)) {
   2735                         SOC_CONTROL(unit)->l3_defip_urpf = urpfEnable;
   2736                     }
   2737                 }
   2738                 /* Recover ECMP DLB parameters */
   2739                 if (soc_feature(unit, soc_feature_ecmp_dlb)) {
   2740 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined (BCM_TRIDENT3_SUPPORT)
   2741                     if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
   2742                         BCM_IF_ERROR_RETURN
   2743                         (bcm_th2_ecmp_dlb_scache_recover(unit, &l3_scache_ptr));
   2744                     } else
   2745 #endif /* BCM_TOMAHAWK2_SUPPORT */
   2746                     {
   2747                             BCM_IF_ERROR_RETURN
   2748                                 (bcm_tr3_ecmp_dlb_scache_recover(unit, &l3_scache_ptr));
   2749                         }
   2750                     }
   2751 #endif /* BCM_TRIUMPH3_SUPPORT */
   2752 
   2753 #ifdef BCM_TRIUMPH2_SUPPORT
   2754                 /* Recover ECMP defragmentation buffer parameters */
   2755                 if (soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf) ||
   2756                     soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) {
   2757                     if (!soc_feature(unit, soc_feature_l3_no_ecmp)) {
   2758                         BCM_IF_ERROR_RETURN
   2759                             (bcm_tr2_l3_ecmp_defragment_buffer_recover(unit, &l3_scache_ptr));
   2760                     }
   2761                 }
   2762 #endif /* BCM_TRIUMPH2_SUPPORT */
   2763 
   2764             }
   2765 #ifdef BCM_TRIDENT2_SUPPORT
   2766             /*
   2767              * l3_ip4_options profile index information is recovered with
   2768              * warmboot scache version 1.4 if recovered from sdk-6.3.1
   2769              * whereas with 6.2.9 the information is not recovered.
   2770              * New version 1.6 will support warmboot sync/recovery for
   2771              * ip4 options profile hardware indexes...
   2772              */
   2773             if (soc_feature(unit, soc_feature_l3_ip4_options_profile)) {
   2774                 if ((recovered_ver >= BCM_WB_VERSION_1_6) ||
   2775                     ((recovered_ver >= BCM_WB_VERSION_1_4) &&
   2776                      (l3_ip4_options_recover == 1))) {
   2777                     BCM_IF_ERROR_RETURN
   2778                         (_bcm_td2_l3_ip4_options_recover(unit, &l3_scache_ptr));
   2779                 } else {
   2780                     int ip4_options_scache_len;
   2781                     /* extra scache space size for recovering ip4 options
   2782                      * profile information in TD2 is 16 bytes */
   2783                     BCM_IF_ERROR_RETURN(
   2784                         _bcm_td2_l3_ip4_options_profile_scache_len_get(
   2785                             unit, &ip4_options_scache_len));
   2786                     additional_scache_sz += ip4_options_scache_len;
   2787                 }
   2788             }
   2789 #endif /* BCM_TRIDENT2_SUPPORT */
   2790             if (recovered_ver >= BCM_WB_VERSION_1_7) {
   2791                 sal_memcpy(ecmp_max_paths, l3_scache_ptr, sizeof(int));
   2792                 l3_scache_ptr += sizeof(int);
   2793 
   2794             } else {
   2795                 /*
   2796                  * ECMP max paths information used to be saved in the last
   2797                  * entry in L3_ECMP table before scache version 1.7 was created
   2798                  *
   2799                  * While upgrading to this version, read ecmp_max_paths info
   2800                  * from the hardware (Level 1).
   2801                  *
   2802                  * Further warmboots will use scache to sync/recover the info.
   2803                  */
   2804                 ecmp_entry_t ecmp_entry;  /* ECMP entry Buffer */
   2805 
   2806                 /* Get maximum number of ECMP paths (stored in last entry) */
   2807                 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(
   2808                     unit,
   2809                     BCM_XGS3_L3_MEM(unit, ecmp),
   2810                     BCM_XGS3_L3_TBL_PTR(unit, ecmp)->idx_max,
   2811                     &ecmp_entry));
   2812 
   2813                 *ecmp_max_paths =
   2814                     soc_L3_ECMPm_field32_get(unit, &ecmp_entry, NEXT_HOPf);
   2815 
   2816                 /* Allocate scache space for storing ecmp max paths */
   2817                 additional_scache_sz += sizeof(int);
   2818             }
   2819 
   2820             if (recovered_ver >= BCM_WB_VERSION_1_8) {
   2821                 if (ecmp_refcnt && soc_feature(unit, soc_feature_l3) &&
   2822                     !soc_feature(unit, soc_feature_l3_no_ecmp)) {
   2823                     alloc_size = SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit));
   2824                     ecmp_flags = sal_alloc(alloc_size, "ECMP flags");
   2825                     if (ecmp_flags == NULL) {
   2826                         return SOC_E_MEMORY;
   2827                     }
   2828                     sal_memcpy(ecmp_flags, l3_scache_ptr, alloc_size);
   2829                     l3_scache_ptr += alloc_size;
   2830                     for (i = 0; i < BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit); i++) {
   2831                         if (!SHR_BITGET(ecmp_flags, i)) {
   2832                             ecmp_refcnt[i] = 0;
   2833                         }
   2834                     }
   2835                     sal_free(ecmp_flags);
   2836                 }
   2837             } else {
   2838                 /* Allocate scache space for storing ecmp ref counts */
   2839                 additional_scache_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit));
   2840             }
   2841 
   2842 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_METROLITE_SUPPORT) ||\
   2843     defined(BCM_HURRICANE3_SUPPORT)
   2844              if ((recovered_ver >= BCM_WB_VERSION_1_17) &&
   2845                      soc_feature(unit, soc_feature_l3_ingress_intf_kt2_recover)) {
   2846                  skip_l3_ingress_intf_recover = TRUE;
   2847              }
   2848              if (skip_l3_ingress_intf_recover == FALSE) {
   2849                  if (recovered_ver >= BCM_WB_VERSION_1_9) {
   2850                      if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
   2851                          sal_memcpy(BCM_XGS3_L3_ING_IF_INUSE(unit), l3_scache_ptr,
   2852                                  SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit)));
   2853                          l3_scache_ptr +=
   2854                              SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit));
   2855                      }
   2856                  } else {
   2857                      additional_scache_sz +=
   2858                          SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit));
   2859                  }
   2860              }
   2861 #endif /* defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_METROLITE_SUPPORT) ||
   2862         * defined(BCM_HURRICANE3_SUPPORT)
   2863         */
   2864 
   2865 #ifdef BCM_TRIDENT2_SUPPORT
   2866             if (recovered_ver >= BCM_WB_VERSION_1_9) {
   2867                if (soc_feature(unit, soc_feature_l3)) {
   2868                     alloc_size = SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit));
   2869                     ecmp_flags = sal_alloc(alloc_size, "ECMP flags");
   2870                     if (ecmp_flags == NULL) {
   2871                         return SOC_E_MEMORY;
   2872                     }
   2873                     sal_memcpy(ecmp_flags, l3_scache_ptr, alloc_size);
   2874                     l3_scache_ptr += alloc_size;
   2875                     for (i = 0; i < BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit); i++) {
   2876                         if (SHR_BITGET(ecmp_flags, i)) {
   2877                             BCM_XGS3_L3_ECMP_GROUP_FLAGS_SET(unit, i,
   2878                                              BCM_L3_ECMP_PATH_NO_SORTING);
   2879                         } else {
   2880                             BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit, i,
   2881                                              BCM_L3_ECMP_PATH_NO_SORTING);
   2882                         }
   2883                     }
   2884                     sal_free(ecmp_flags);
   2885                 }
   2886             } else {
   2887                 /* Allocate scache space for storing ecmp resorting flag */
   2888                 additional_scache_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit));
   2889 #ifdef BCM_TOMAHAWK_SUPPORT
   2890                 if (soc_feature(unit, soc_feature_l3) &&
   2891                     soc_feature(unit, soc_feature_hierarchical_ecmp)) {
   2892                     /* ECMP Level 1 flags */
   2893                     additional_scache_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS(unit));
   2894                     /* ECMP Level 2 flags */
   2895                     additional_scache_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS(unit));
   2896                 }
   2897 
   2898 #endif /* BCM_TOMAHAWK_SUPPORT */
   2899             }
   2900 #endif /* BCM_TRIDENT2_SUPPORT */
   2901             if (recovered_ver >= BCM_WB_VERSION_1_10) {
   2902 #ifdef BCM_TRIUMPH3_SUPPORT
   2903                 if (soc_feature(unit, soc_feature_l2gre)) {
   2904                     for (i = 0; i < BCM_XGS3_L3_NH_TBL_SIZE(unit); i++) {
   2905                         sal_memcpy(&flag, l3_scache_ptr, sizeof(uint8));
   2906                         BCM_XGS3_L3_ENT_FLAG(
   2907                             BCM_XGS3_L3_TBL_PTR(unit, next_hop), i) = flag;
   2908                         l3_scache_ptr += sizeof(uint8);
   2909                     }  
   2910                     l3_flags_recovered = 1;
   2911                 }
   2912 #endif /* BCM_TRIUMPH3_SUPPORT */
   2913 #ifdef BCM_TRIDENT_SUPPORT
   2914                 if (soc_feature(unit, soc_feature_trill)) {
   2915                     if (!l3_flags_recovered) {
   2916                         for (i = 0; i < BCM_XGS3_L3_NH_TBL_SIZE(unit); i++) {
   2917                             sal_memcpy(&flag, l3_scache_ptr, sizeof(uint8));
   2918                             BCM_XGS3_L3_ENT_FLAG(
   2919                                 BCM_XGS3_L3_TBL_PTR(unit, next_hop), i) = flag;
   2920                             l3_scache_ptr += sizeof(uint8);
   2921                         }  
   2922                         l3_flags_recovered = 1;
   2923                     }
   2924                 }
   2925 #endif /* BCM_TRIDENT_SUPPORT */      
   2926 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)
   2927                 if (soc_feature(unit, soc_feature_vxlan) ||
   2928                     soc_feature(unit, soc_feature_vxlan_lite)) {
   2929                     if (!l3_flags_recovered) {
   2930                         for (i = 0; i < BCM_XGS3_L3_NH_TBL_SIZE(unit); i++) {
   2931                             sal_memcpy(&flag, l3_scache_ptr, sizeof(uint8));
   2932                             BCM_XGS3_L3_ENT_FLAG(
   2933                                 BCM_XGS3_L3_TBL_PTR(unit, next_hop), i) = flag;
   2934                             l3_scache_ptr += sizeof(uint8);
   2935                         }
   2936                         l3_flags_recovered = 1;
   2937                     }
   2938                 }
   2939 #endif /* BCM_TRIDENT2_SUPPORT || BCM_GREYHOUND2_SUPPORT */
   2940             } else {
   2941                 additional_scache_sz += 
   2942                     BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(uint8);
   2943             }
   2944 
   2945             if (recovered_ver >= BCM_WB_VERSION_1_11) {
   2946 #ifdef BCM_TOMAHAWK_SUPPORT
   2947                 if (soc_feature(unit, soc_feature_hierarchical_ecmp)) {
   2948                     alloc_size = SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS(unit));
   2949                     ecmp_l1_flags = sal_alloc(alloc_size, "ECMP level1 flags");
   2950                     if (ecmp_l1_flags == NULL) {
   2951                         return SOC_E_MEMORY;
   2952                     }
   2953                     ecmp_l2_flags = sal_alloc(alloc_size, "ECMP level2 flags");
   2954                     if (ecmp_l2_flags == NULL) {
   2955                         sal_free(ecmp_l1_flags);
   2956                         return SOC_E_MEMORY;
   2957                     }
   2958                     sal_memcpy(ecmp_l1_flags, l3_scache_ptr, alloc_size);
   2959                     l3_scache_ptr += alloc_size;
   2960                     sal_memcpy(ecmp_l2_flags, l3_scache_ptr, alloc_size);
   2961                     l3_scache_ptr += alloc_size;
   2962                     for (i = 0; i < BCM_XGS3_L3_ECMP_MAX_GROUPS(unit); i++) {
   2963                         if (SHR_BITGET(ecmp_l1_flags, i)) {
   2964                             BCM_XGS3_L3_ECMP_GROUP_FLAGS_SET(unit, i,
   2965                                                      BCM_L3_ECMP_OVERLAY);
   2966                         } else {
   2967                             BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit, i,
   2968                                                      BCM_L3_ECMP_OVERLAY);
   2969                         }
   2970                         if (SHR_BITGET(ecmp_l2_flags, i)) {
   2971                             BCM_XGS3_L3_ECMP_GROUP_FLAGS_SET(unit, i,
   2972                                                      BCM_L3_ECMP_UNDERLAY);
   2973                         } else {
   2974                             BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit, i,
   2975                                                      BCM_L3_ECMP_UNDERLAY);
   2976                         }
   2977                     }
   2978                     sal_free(ecmp_l1_flags);
   2979                     sal_free(ecmp_l2_flags);
   2980                 }
   2981 
   2982                 if (soc_feature(unit, soc_feature_l3) &&
   2983                     soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) {
   2984                     /* save interface count for each ecmp group */
   2985                     BCM_IF_ERROR_RETURN
   2986                         (bcm_opt_l3_ecmp_rh_member_recover(unit, &l3_scache_ptr,
   2987                          *ecmp_max_paths));
   2988                 }
   2989 
   2990                 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
   2991                     BCM_IF_ERROR_RETURN
   2992                         (bcm_th_l3_extended_view_reinit(unit, &l3_scache_ptr));
   2993                 }
   2994 #endif /* BCM_TOMAHAWK_SUPPORT */
   2995             } else {
   2996 #ifdef BCM_TOMAHAWK_SUPPORT
   2997                 if (soc_feature(unit, soc_feature_hierarchical_ecmp)) {
   2998                     additional_scache_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS(unit));
   2999                     additional_scache_sz += SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_MAX_GROUPS(unit));
   3000                 }
   3001 
   3002                 if (soc_feature(unit, soc_feature_l3) &&
   3003                     soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) {
   3004                     /* save interface count for each ecmp group */
   3005                     additional_scache_sz += sizeof(int);
   3006                     /* ECMP max paths info per RH group */
   3007                     additional_scache_sz += sizeof(uint16) * BCM_XGS3_L3_ECMP_MAX_GROUPS(unit);
   3008                     /* Group, member tuples */
   3009                     additional_scache_sz += (RH_ECMP_MEMBER_TBL_MAX(unit) * (sizeof(int16) + sizeof(bcm_if_t)));
   3010                 }
   3011 
   3012                 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
   3013                     bcm_th_l3_extended_required_scache_size_get(unit, &additional_scache_sz);
   3014                 }
   3015 #endif /* BCM_TOMAHAWK_SUPPORT */
   3016 
   3017             } /* End of BCM_WB_VERSION_1_11 */
   3018             if (recovered_ver >= BCM_WB_VERSION_1_12) {
   3019                 if (soc_feature(unit, soc_feature_hierarchical_protection)) {
   3020                     sal_memcpy(BCM_XGS3_L3_NH_MULTI_COUNT(unit), l3_scache_ptr,
   3021                         BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(int));
   3022                     /* Till WB version 1_15, l3_scache_ptr was not incremented
   3023                        in sync as well as recover flow. So, this information
   3024                        was overwritten by other scache data. Now, it is being
   3025                        incremented, but to be backward-compatible, increment
   3026                        of l3_scache_ptr under version 1_16.
   3027                      */
   3028                     if (recovered_ver >= BCM_WB_VERSION_1_16) {
   3029                         l3_scache_ptr += (BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(int));
   3030                     }
   3031                 }
   3032             } else {
   3033                 if (soc_feature(unit, soc_feature_hierarchical_protection)) {
   3034                     additional_scache_sz +=
   3035                         (BCM_XGS3_L3_NH_TBL_SIZE(unit) * sizeof(int));
   3036                 }
   3037             } /* End of BCM_WB_VERSION_1_12 */
   3038 #ifdef BCM_TRIDENT_SUPPORT
   3039                 if (soc_feature(unit, soc_feature_nh_for_ifp_actions)) {
   3040                     if (!l3_flags_recovered) {
   3041                         for (i = 0; i < BCM_XGS3_L3_NH_TBL_SIZE(unit); i++) {
   3042                             sal_memcpy(&flag, l3_scache_ptr, sizeof(uint8));
   3043                             BCM_XGS3_L3_ENT_FLAG(
   3044                                 BCM_XGS3_L3_TBL_PTR(unit, next_hop), i) = flag;
   3045                             l3_scache_ptr += sizeof(uint8);
   3046                         }
   3047                     }
   3048                 }
   3049 #endif /* BCM_TRIDENT_SUPPORT */
   3050 
   3051 #ifdef BCM_RIOT_SUPPORT
   3052             if (soc_feature(unit, soc_feature_riot)) {
   3053                 if (recovered_ver >= BCM_WB_VERSION_1_13) {
   3054                     BCM_IF_ERROR_RETURN
   3055                         (bcm_td2p_l3_extended_view_reinit(unit, &l3_scache_ptr));
   3056                 } else {
   3057                     bcm_td2p_l3_extended_required_scache_size_get(unit, &additional_scache_sz);
   3058                 }
   3059             }
   3060 #endif /* BCM_RIOT_SUPPORT */
   3061 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   3062             /* Recover alternate count per ecmp group */
   3063             if (soc_feature(unit, soc_feature_dgm)) {
   3064                 for (idx = 0; idx < BCM_XGS3_L3_ECMP_MAX_GROUPS(unit); idx++) {
   3065                     sal_memcpy(&(BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit)[idx]),
   3066                                l3_scache_ptr, sizeof(uint16));
   3067                     l3_scache_ptr += sizeof(uint16);
   3068                 }
   3069             }
   3070 #endif /* BCM_TOMAHAWK2_SUPPORT */
   3071             if (recovered_ver >= BCM_WB_VERSION_1_15) {
   3072                 sal_memcpy(&(SOC_VRF_MAX(unit)), l3_scache_ptr, sizeof(uint16));
   3073                 l3_scache_ptr += sizeof(uint16);
   3074             } else {
   3075                 additional_scache_sz += sizeof(uint16);
   3076             }
   3077 
   3078             if (!(BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_DISABLE_ADD_TO_ARL))) {
   3079                 if (recovered_ver >= BCM_WB_VERSION_1_16) {
   3080                     sal_memcpy(BCM_XGS3_L3_IF_ADD2ARL(unit), l3_scache_ptr,
   3081                               SHR_BITALLOCSIZE(soc_mem_index_count(unit,  EGR_L3_INTFm)));
   3082                     l3_scache_ptr += SHR_BITALLOCSIZE(soc_mem_index_count(unit,  EGR_L3_INTFm));
   3083                 } else {
   3084                     additional_scache_sz +=
   3085                         SHR_BITALLOCSIZE((soc_mem_index_count(unit,  EGR_L3_INTFm)));
   3086                 }
   3087             }
   3088 
   3089 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   3090             if (soc_feature(unit, soc_feature_ecmp_dlb) &&
   3091                 soc_feature(unit, soc_feature_ecmp_dlb_optimized) &&
   3092                 !soc_feature(unit, soc_feature_th3_style_dlb)) {
   3093                 if (recovered_ver >= BCM_WB_VERSION_1_16) {
   3094                     BCM_IF_ERROR_RETURN(
   3095                         bcm_th2_ecmp_dlb_member_scache_recover(unit,
   3096                         &l3_scache_ptr));
   3097                 } else {
   3098                     num_elements = soc_mem_index_count(unit, ING_L3_NEXT_HOPm);
   3099                     additional_scache_sz += SHR_BITALLOCSIZE(num_elements);
   3100                 }
   3101             }
   3102 #endif /* BCM_TOMAHAWK2_SUPPORT */
   3103 
   3104 #if defined(BCM_TRX_SUPPORT)
   3105             if (soc_feature(unit, soc_feature_l3_ingress_interface) &&
   3106                     soc_feature(unit, soc_feature_l3_ingress_intf_kt2_recover)) {
   3107                 if (recovered_ver >= BCM_WB_VERSION_1_17) {
   3108                     sal_memcpy(BCM_XGS3_L3_ING_IF_INUSE(unit), l3_scache_ptr,
   3109                             SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit)));
   3110                     l3_scache_ptr +=
   3111                         SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit));
   3112                 } else {
   3113                     additional_scache_sz +=
   3114                         SHR_BITALLOCSIZE(BCM_XGS3_L3_ING_IF_TBL_SIZE(unit));
   3115                 }
   3116             }
   3117 #endif /* BCM_TRX_SUPPORT */
   3118 
   3119             /* scache realloc for further warm reboots */
   3120             if (additional_scache_sz > 0) {
   3121                 SOC_IF_ERROR_RETURN(soc_scache_realloc(unit,
   3122                     scache_handle, additional_scache_sz));
   3123             }
   3124 
   3125 #ifdef BCM_TRIDENT_SUPPORT
   3126             if (soc_feature(unit, soc_feature_trill) ||
   3127                 soc_feature(unit, soc_feature_l2gre) ||
   3128                 soc_feature(unit, soc_feature_vxlan)) {
   3129                     BCM_IF_ERROR_RETURN
   3130                         (_bcm_xgs3_trunk_nh_store_recover (unit));
   3131             }
   3132 #endif /* BCM_TRIDENT_SUPPORT */
   3133         }
   3134 
   3135 #if defined(BCM_SCORPION_SUPPORT)
   3136         if (SOC_IS_SCORPION(unit)) {
   3137             if ((dev_id == BCM56820_DEVICE_ID) &&
   3138                     (recovered_ver < BCM_WB_VERSION_1_14)) {
   3139                 /* Reset the soc feature. */
   3140                 SOC_FEATURE_SET(unit, soc_feature_l3_ecmp_2k_groups);
   3141             }
   3142         }
   3143 #endif /* BCM_SCORPION_SUPPORT */
   3144     }
   3145 
   3146     return BCM_E_NONE;
   3147 }
   3148 
   3149 /*
   3150  * Function:
   3151  *   _bcm_tunnel_initiator_reinit
   3152  * Purpose:
   3153  *	 Tunnel initiator state and ref-count recovery.
   3154  * Parameters:
   3155  *      unit      - (IN)  BCM device number.
   3156  * Returns:
   3157  *      BCM_E_XXX
   3158  */
   3159 int
   3160 _bcm_tunnel_initiator_reinit(int unit) {
   3161 
   3162     int i, idx;             /* Table iteration index.   */
   3163     int idx_min, idx_max;            /* Maximum Table index.     */
   3164     uint32 intf;
   3165     tunnel_entry_t l3_tnl_entry;
   3166     egr_ip_tunnel_entry_t egr_tnl_entry;
   3167     soc_field_t fld = ENTRY_TYPEf;
   3168     int local_idx_maxused = 0;
   3169 
   3170     if (!SOC_MEM_IS_VALID(unit,L3_TUNNELm)) {
   3171         /* if (SOC_IS_HURRICANE(unit)) */
   3172         return SOC_E_NONE;
   3173     }
   3174 
   3175     idx = soc_mem_index_min(unit, L3_TUNNELm);
   3176     idx_max = soc_mem_index_max(unit, L3_TUNNELm);
   3177 
   3178     for (idx = 0; idx <= idx_max; idx++) {
   3179         BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_TUNNELm,
   3180                             MEM_BLOCK_ANY, idx, &l3_tnl_entry));
   3181         if (!soc_L3_TUNNELm_field32_get(unit, &l3_tnl_entry, VALIDf)) {
   3182             continue;
   3183         }
   3184 
   3185         intf = soc_L3_TUNNELm_field32_get(unit, &l3_tnl_entry, IINTFf);
   3186         if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
   3187             SHR_BITSET(BCM_XGS3_L3_ING_IF_INUSE(unit), intf);
   3188         }
   3189     }
   3190 
   3191     /* Adjust ref counts */
   3192     idx_min = 1;
   3193     idx_max = soc_mem_index_max(unit, EGR_IP_TUNNELm);
   3194 
   3195 #if defined(BCM_FIREBOLT_SUPPORT)
   3196     if (SOC_IS_FB_FX_HX(unit) || SOC_IS_BRADLEY(unit)) {
   3197         fld = TUNNEL_TYPEf;
   3198     } else if (SOC_IS_TRIDENT3X(unit)) {
   3199         fld = DATA_TYPEf;
   3200     }
   3201 #endif
   3202 
   3203     for (i = idx_min; i <= idx_max; i++) {
   3204         SOC_IF_ERROR_RETURN(soc_mem_read(unit, EGR_IP_TUNNELm,
   3205                             MEM_BLOCK_ANY, i, &egr_tnl_entry));
   3206         if (soc_EGR_IP_TUNNELm_field32_get(unit, &egr_tnl_entry, fld) != 0) {
   3207             local_idx_maxused = i;
   3208         }
   3209     }
   3210 
   3211     if (local_idx_maxused != 0) {
   3212         BCM_XGS3_L3_TBL(unit, tnl_init).idx_maxused = local_idx_maxused;
   3213     } else {
   3214         BCM_XGS3_L3_TBL(unit, tnl_init).idx_maxused = idx_min;
   3215     }
   3216     return BCM_E_NONE;
   3217 }
   3218 
   3219 /*
   3220  * Function:
   3221  *      _bcm_xgs3_l3_reinit
   3222  * Purpose:
   3223  *      Recovers L3 sw state from hw tables
   3224  * Parameters:
   3225  *      unit  - SOC unit number
   3226  * Returns:
   3227  *      BCM_E_XXX
   3228  */
   3229 int
   3230 _bcm_xgs3_l3_reinit(int unit)
   3231 {
   3232     int32 l3EgressMode = 0, l3IngressMode = 0, l3HostAddMode=0, l3IntfMapMode=0;
   3233     int i, l3EcmpMaxPaths = 0;
   3234     int *ecmp_refcnt = NULL;
   3235     int alloc_size;
   3236     int rv = BCM_E_NONE;
   3237 
   3238     /*
   3239      * Init L3 counters.
   3240      */
   3241     BCM_XGS3_L3_CNTRS_RESET(unit);
   3242 
   3243     /*
   3244      * Init have table sizes & hw callbacks.
   3245      */
   3246     BCM_IF_ERROR_RETURN(bcm_xgs3_l3_tables_init(unit));
   3247 
   3248     if (soc_property_get(unit, spn_L3_INTF_VLAN_SPLIT_EGRESS, 0)) {
   3249         BCM_XGS3_L3_FLAGS(unit) |= _BCM_L3_SHR_L3_INTF_VLAN_SPLIT_EGRESS;
   3250     } else {
   3251         BCM_XGS3_L3_FLAGS(unit) &= ~_BCM_L3_SHR_L3_INTF_VLAN_SPLIT_EGRESS;
   3252     }
   3253 
   3254     /*
   3255      * Get L3 mode(s) and recover from scache
   3256      */
   3257     alloc_size = sizeof(int) * BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit);
   3258     ecmp_refcnt = sal_alloc(alloc_size, "ECMP refcnt");
   3259 
   3260     for (i = 0; i < (BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit)); i++) {
   3261         ecmp_refcnt[i] = 1;
   3262     }
   3263     rv = (_bcm_esw_l3_warmboot_recover(unit,
   3264         &l3EgressMode, &l3IngressMode, &l3HostAddMode,
   3265         &l3IntfMapMode, &l3EcmpMaxPaths, ecmp_refcnt));
   3266     if (BCM_FAILURE(rv)) {
   3267         sal_free(ecmp_refcnt);
   3268         return rv;
   3269     }
   3270 
   3271 #ifdef BCM_TRIUMPH_SUPPORT
   3272    /*
   3273     * Recover Ingress Mode
   3274     */
   3275     if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
   3276         rv = (bcm_xgs3_l3_ingress_mode_set(unit, l3IngressMode));
   3277         if (BCM_FAILURE(rv)) {
   3278             sal_free(ecmp_refcnt);
   3279             return rv;
   3280         }
   3281     }
   3282 #endif /* BCM_TRIUMPH_SUPPORT */
   3283 
   3284     /*
   3285      * Recover Egress Mode
   3286      */
   3287     rv = (bcm_xgs3_l3_egress_mode_set(unit, l3EgressMode));
   3288     if (BCM_FAILURE(rv)) {
   3289         sal_free(ecmp_refcnt);
   3290         return rv;
   3291     }
   3292 
   3293     /*
   3294      * Recover Host Add Mode
   3295      */
   3296     rv = (bcm_xgs3_l3_host_as_route_return_set(unit, l3HostAddMode));
   3297     if (BCM_FAILURE(rv)) {
   3298         sal_free(ecmp_refcnt);
   3299         return rv;
   3300     }
   3301 
   3302 #ifdef BCM_TRIUMPH_SUPPORT
   3303    /*
   3304     * Recover Intf Map mode
   3305     */
   3306     if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
   3307         if (soc_feature(unit, soc_feature_l3_iif_under_4k)) {
   3308             /* l3IntfMapMode can only be 1 for L3_IIFm size under 4K */
   3309             l3IntfMapMode = 1;
   3310         }
   3311         rv = (bcm_xgs3_l3_ingress_intf_map_set(unit, l3IntfMapMode));
   3312         if (BCM_FAILURE(rv)) {
   3313             sal_free(ecmp_refcnt);
   3314             return rv;
   3315         }
   3316     }
   3317 #endif /* BCM_TRIUMPH_SUPPORT */
   3318 
   3319     /*
   3320      * Recover L3 Intf sw state
   3321      */
   3322     rv = (_bcm_xgs3_l3_intf_reinit(unit));
   3323     if (BCM_FAILURE(rv)) {
   3324         sal_free(ecmp_refcnt);
   3325         return rv;
   3326     }
   3327 
   3328 #ifdef BCM_TRIDENT2_SUPPORT
   3329     if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
   3330         rv = (_bcm_xgs3_l3_ingress_intf_reinit(unit));
   3331         if (BCM_FAILURE(rv)) {
   3332             sal_free(ecmp_refcnt);
   3333             return rv;
   3334         }
   3335     }
   3336 #endif
   3337     /*
   3338      * Recover next hop table.
   3339      */
   3340     rv = (_bcm_xgs3_l3_nh_reinit(unit, l3EgressMode));
   3341     if (BCM_FAILURE(rv)) {
   3342         sal_free(ecmp_refcnt);
   3343         return rv;
   3344     }
   3345 
   3346     /*
   3347      * Recover ecmp groups.
   3348      */
   3349     rv = (_bcm_xgs3_l3_ecmp_reinit(unit, l3EcmpMaxPaths, ecmp_refcnt));
   3350     sal_free(ecmp_refcnt);
   3351     if (BCM_FAILURE(rv)) {
   3352         return rv;
   3353     }
   3354 
   3355     /*
   3356      * Recover l3 entries(host) table.
   3357      */
   3358     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_l3table_reinit(unit));
   3359 
   3360     /*
   3361      * Recover defip table.
   3362      */
   3363     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_defip_table_reinit(unit));
   3364 
   3365     /*
   3366      * Recover VRF table.
   3367      */
   3368 #if defined(BCM_TRIUMPH2_SUPPORT)
   3369     if (soc_feature(unit, soc_feature_gport_service_counters)) {
   3370         BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_flexstat_recover(unit));
   3371     }
   3372 #endif /* BCM_TRIUMPH2_SUPPORT */
   3373 
   3374     /*
   3375      * Recover tunnel terminator table.
   3376      */
   3377     if (!soc_feature(unit, soc_feature_no_tunnel)) {
   3378         BCM_IF_ERROR_RETURN(_bcm_tunnel_initiator_reinit(unit));
   3379         BCM_IF_ERROR_RETURN(soc_tunnel_term_reinit(unit));
   3380     } else {
   3381         if (soc_feature(unit, soc_feature_vxlan_lite)) {
   3382             BCM_IF_ERROR_RETURN(_bcm_tunnel_initiator_reinit(unit));
   3383         }
   3384     }
   3385 
   3386     /*
   3387      * Recover ESM host table state
   3388      */
   3389 #if defined(BCM_TRIUMPH3_SUPPORT)
   3390     if (SOC_IS_TRIUMPH3(unit) && BCM_TR3_ESM_HOST_TBL_PRESENT(unit)) {
   3391         BCM_IF_ERROR_RETURN(_bcm_tr3_l3_esm_host_state_recover(unit));
   3392     }
   3393 #endif /* BCM_TRIUMPH3_SUPPORT */
   3394 
   3395 #if defined(BCM_TRX_SUPPORT)
   3396     BCM_IF_ERROR_RETURN (_bcm_field_l3_recover_callback(unit));
   3397 #endif /* BCM_TRX_SUPPORT */
   3398 #if defined (BCM_KATANA_SUPPORT) || defined (BCM_TRIDENT_SUPPORT) \
   3399             || defined (BCM_TRIUMPH3_SUPPORT) || defined (BCM_GREYHOUND_SUPPORT)
   3400     BCM_IF_ERROR_RETURN (bcmi_xgs3_fp_l3_egress_ref_count_update(unit));
   3401 #endif
   3402     return (BCM_E_NONE);
   3403 }
   3404 #endif /* BCM_WARM_BOOT_SUPPORT */
   3405 
   3406 
   3407 /*
   3408  * Function:
   3409  *      _bcm_xgs3_l3_table_init
   3410  * Purpose:
   3411  *      Initialize L3 tables.
   3412  * Parameters:
   3413  *      unit    - (IN)  SOC unit number.
   3414  * Returns:
   3415  *      Number of L3 entries.
   3416  */
   3417 STATIC int
   3418 _bcm_xgs3_l3_table_init(int unit)
   3419 {
   3420 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \
   3421     defined(BCM_HAWKEYE_SUPPORT)
   3422     if (soc_feature(unit, soc_feature_fp_based_routing)) {
   3423         BCM_XGS3_L3_TBL_SIZE(unit) = BCM_XGS3_L3_RP_MAX_PREFIXES(unit);
   3424         return (BCM_E_NONE);
   3425     }
   3426 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */
   3427 
   3428     /* Get table L3 host table size. */
   3429     if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, v4))) {
   3430         BCM_XGS3_L3_TBL_SIZE(unit) =
   3431             soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, v4));
   3432     } else {
   3433         BCM_XGS3_L3_TBL_SIZE(unit) = 0;
   3434     }
   3435 
   3436     return (BCM_E_NONE);
   3437 }
   3438 
   3439 #ifdef BCM_FIREBOLT_SUPPORT
   3440 /*
   3441  * Function:
   3442  *      bcm_xgs3_l3_fbx_defip_init
   3443  * Purpose:
   3444  *      Initialize L3 DEFIP table for fbx devices.
   3445  * Parameters:
   3446  *      unit    - (IN)  SOC unit number.
   3447  * Returns:
   3448  *      BCM_E_XXX
   3449  */
   3450 int
   3451 bcm_xgs3_l3_fbx_defip_init(int unit)
   3452 {
   3453 #if defined (BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT) || \
   3454     defined (BCM_RAVEN_SUPPORT)
   3455     uint32 reg_val;    /* Buffer to store urpf register value.*/
   3456 
   3457     /* NOTE: URPF enable check  must be done before   */
   3458     /*  specific route table initialization.          */
   3459 
   3460     /* URPF support check. */
   3461     if (SOC_REG_IS_VALID(unit, L3_DEFIP_RPF_CONTROLr)) {
   3462         BCM_IF_ERROR_RETURN(READ_L3_DEFIP_RPF_CONTROLr(unit, &reg_val));
   3463 
   3464         if (soc_reg_field_get(unit, L3_DEFIP_RPF_CONTROLr, reg_val,
   3465                               DEFIP_RPF_ENABLEf)) {
   3466             SOC_URPF_STATUS_SET(unit, TRUE);
   3467         } else {
   3468             SOC_URPF_STATUS_SET(unit, FALSE);
   3469         }
   3470     }
   3471 #else /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT || BCM_RAVEN_SUPPORT */
   3472     SOC_URPF_STATUS_SET(unit, FALSE);
   3473 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT || BCM_RAVEN_SUPPORT */
   3474 
   3475 #if defined(BCM_SCORPION_SUPPORT)
   3476     if (SOC_IS_SCORPION(unit)) {
   3477         BCM_IF_ERROR_RETURN(_bcm_sc_defip_init(unit));
   3478     } else
   3479 #endif /* BCM_SCORPION_SUPPORT */
   3480 #ifdef BCM_KATANA2_SUPPORT
   3481     if (SOC_IS_KATANA2(unit)) {
   3482         BCM_IF_ERROR_RETURN(_bcm_kt2_l3_defip_init(unit));
   3483     } else
   3484 #endif
   3485 #ifdef BCM_TRIUMPH3_SUPPORT
   3486     if (SOC_IS_TRIUMPH3(unit)) {
   3487         BCM_IF_ERROR_RETURN(_bcm_tr3_l3_defip_init(unit));
   3488     } else
   3489 #endif
   3490 #if defined(BCM_TRIDENT2_SUPPORT)
   3491     if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
   3492         BCM_IF_ERROR_RETURN(_bcm_l3_defip_init(unit));
   3493 #if defined(BCM_TOMAHAWK3_SUPPORT)
   3494         /* Only config LPM_IP_CONTROLm here if ALPM is disabled. ALPM uses diff setting */
   3495         if (SOC_MEM_IS_VALID(unit, LPM_IP_CONTROLm) && !soc_property_get(unit, spn_L3_ALPM_ENABLE, 0)) {
   3496             lpm_ip_control_entry_t entry;
   3497             int tcam_pair_count = 0;
   3498             sal_memset(&entry, 0, sizeof(entry));
   3499 
   3500             SOC_IF_ERROR_RETURN(soc_fb_lpm_tcam_pair_count_get(unit, &tcam_pair_count));
   3501 
   3502             soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL1_KEY_INPUT_SEL_BLOCK_0f, !tcam_pair_count);
   3503             soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL1_KEY_INPUT_SEL_BLOCK_1f, !(tcam_pair_count / 2));
   3504             soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL1_KEY_INPUT_SEL_BLOCK_2f, !(tcam_pair_count / 3));
   3505             soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL1_KEY_INPUT_SEL_BLOCK_3f, !(tcam_pair_count / 4));
   3506             soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL2_KEY_INPUT_SEL_BLOCK_0f, 0);
   3507             soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL2_KEY_INPUT_SEL_BLOCK_1f, 0);
   3508             soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL3_KEY_INPUT_SEL_BLOCK_0f, 0);
   3509             soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL3_KEY_INPUT_SEL_BLOCK_1f, 0);
   3510 
   3511             soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL2_DATABASE_SEL_BLOCK_0f, 4);
   3512             soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL2_DATABASE_SEL_BLOCK_1f, 4);
   3513             soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL3_DATABASE_SEL_BLOCK_0f, 4);
   3514             soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL3_DATABASE_SEL_BLOCK_1f, 4);
   3515             soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL1_DATABASE_SEL_BLOCK_0f, 0);
   3516             soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL1_DATABASE_SEL_BLOCK_1f, 0);
   3517             soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL1_DATABASE_SEL_BLOCK_2f, 0);
   3518             soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, LEVEL1_DATABASE_SEL_BLOCK_3f, 0);
   3519             soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, DB1_MODEf, 0);
   3520             soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, DB0_MODEf, 1);
   3521             soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, DATA0_SELf, 0);
   3522             soc_mem_field32_set(unit, LPM_IP_CONTROLm, &entry, DATA1_SELf, 4);
   3523             soc_mem_write(unit, LPM_IP_CONTROLm, COPYNO_ALL, 0, &entry);
   3524 
   3525         }
   3526 #endif
   3527     } else
   3528 #endif /* BCM_TRIDENT2_SUPPORT*/
   3529 #if defined(BCM_TRIUMPH_SUPPORT)
   3530     if (SOC_IS_TR_VL(unit) && 
   3531         (!(SOC_IS_HURRICANEX(unit)||SOC_IS_GREYHOUND(unit)||
   3532         SOC_IS_GREYHOUND2(unit)))) {
   3533         BCM_IF_ERROR_RETURN(_bcm_tr_defip_init(unit));
   3534     } else
   3535 #endif /* BCM_TRIUMPH_SUPPORT*/
   3536 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \
   3537     defined(BCM_HAWKEYE_SUPPORT)
   3538     if (soc_feature(unit, soc_feature_fp_based_routing)) {
   3539         return (BCM_E_NONE);
   3540     } else
   3541 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */
   3542 #if defined(BCM_HURRICANE2_SUPPORT)||defined(BCM_GREYHOUND_SUPPORT)
   3543     if (SOC_IS_HURRICANE2(unit)||SOC_IS_GREYHOUND(unit) ||
   3544         SOC_IS_HURRICANE3(unit)||SOC_IS_GREYHOUND2(unit)) {
   3545         BCM_IF_ERROR_RETURN(soc_hu2_lpm_init(unit));
   3546     } else
   3547 #endif /*BCM_HURRICANE2_SUPPORT */
   3548     {
   3549         /* Init prefixes offsets, hash/avl - lookup engine. */
   3550         BCM_IF_ERROR_RETURN(soc_fb_lpm_init(unit));
   3551     }
   3552     return (BCM_E_NONE);
   3553 }
   3554 
   3555 /*
   3556  * Function:
   3557  *      bcm_xgs3_l3_fbx_defip_deinit
   3558  * Purpose:
   3559  *      De-initialize L3 DEFIP table for fbx devices.
   3560  * Parameters:
   3561  *      unit    - (IN)  SOC unit number.
   3562  * Returns:
   3563  *      BCM_E_XXX
   3564  */
   3565 int
   3566 bcm_xgs3_l3_fbx_defip_deinit(int unit)
   3567 {
   3568 
   3569 #if defined(BCM_SCORPION_SUPPORT)
   3570     if (SOC_IS_SCORPION(unit)) {
   3571         BCM_IF_ERROR_RETURN(_bcm_sc_defip_deinit(unit));
   3572     } else
   3573 #endif /* BCM_SCORPION_SUPPORT */
   3574 #if defined(BCM_KATANA2_SUPPORT)
   3575     if (SOC_IS_KATANA2(unit)) {
   3576         BCM_IF_ERROR_RETURN(_bcm_kt2_l3_defip_deinit(unit));
   3577     } else
   3578 #endif /* BCM_KATANA2_SUPPORT */
   3579 #if defined(BCM_TRIUMPH3_SUPPORT)
   3580     if (SOC_IS_TRIUMPH3(unit)) {
   3581         BCM_IF_ERROR_RETURN(_bcm_tr3_l3_defip_deinit(unit));
   3582     } else
   3583 #endif /* BCM_TRIUMPH3_SUPPORT */
   3584 #if defined(BCM_TRIDENT2_SUPPORT)
   3585     if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
   3586         BCM_IF_ERROR_RETURN(_bcm_l3_defip_deinit(unit));
   3587     } else
   3588 #endif /* BCM_TRIDENT2_SUPPORT */
   3589 #if defined(BCM_TRIUMPH_SUPPORT)
   3590     if (SOC_IS_TR_VL(unit)) {
   3591 #if defined(BCM_HURRICANE3_SUPPORT)
   3592         if (soc_feature(unit, soc_feature_miml_no_l3)) {
   3593             return (BCM_E_NONE);
   3594         }
   3595 #endif /* BCM_HURRICANE3_SUPPORT */
   3596         BCM_IF_ERROR_RETURN(_bcm_tr_defip_deinit(unit));
   3597     } else
   3598 #endif /* BCM_TRIUMPH_SUPPORT*/
   3599 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \
   3600     defined(BCM_HAWKEYE_SUPPORT)
   3601     if (soc_feature(unit, soc_feature_fp_based_routing)) {
   3602         return (BCM_E_NONE);
   3603     } else
   3604 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */
   3605 #if defined(BCM_HURRICANE2_SUPPORT)
   3606         if (SOC_IS_HURRICANE2(unit)) {
   3607             BCM_IF_ERROR_RETURN(soc_hu2_lpm_deinit(unit));
   3608         } else
   3609 #endif /*BCM_HURRICANE2_SUPPORT */
   3610     {
   3611         /* Init prefixes offsets, hash/avl - lookup engine. */
   3612         BCM_IF_ERROR_RETURN(soc_fb_lpm_deinit(unit));
   3613     }
   3614     return (BCM_E_NONE);
   3615 }
   3616 #endif /* BCM_FIREBOLT_SUPPORT */
   3617 
   3618 /*
   3619  * Function:
   3620  *      _bcm_xgs3_defip_table_init
   3621  * Purpose:
   3622  *      Initialize L3 DEFIP tables.
   3623  * Parameters:
   3624  *      unit    - (IN)  SOC unit number.
   3625  * Returns:
   3626  *      Number of DEFIP entries.
   3627  */
   3628 STATIC int
   3629 _bcm_xgs3_defip_table_init(int unit)
   3630 {
   3631     int defip_config = 0;
   3632     int ipv6_128_depth = 0;
   3633     int l3_defip_pair_128_size = 0;
   3634     soc_mem_t defip_pair_mem = L3_DEFIP_PAIR_128m;
   3635 
   3636 #ifdef BCM_TRIDENT2PLUS_SUPPORT
   3637     uint16              dev_id;
   3638     uint8               rev_id;
   3639     soc_cm_get_id_otp(unit, &dev_id, &rev_id);
   3640 #endif /* BCM_TRIDENT2PLUS_SUPPORT */
   3641 
   3642 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \
   3643     defined(BCM_HAWKEYE_SUPPORT)
   3644     if (soc_feature(unit, soc_feature_fp_based_routing)) {
   3645         BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) =
   3646             BCM_XGS3_L3_RP_MAX_PREFIXES(unit);
   3647         return (BCM_E_NONE);
   3648     }
   3649 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */
   3650     /* Get table size. */
   3651 
   3652     if (SOC_MEM_IS_VALID(unit, L3_DEFIP_PAIR_LEVEL1m)) {
   3653         defip_pair_mem = L3_DEFIP_PAIR_LEVEL1m;
   3654     }
   3655 
   3656     if (soc_feature(unit, soc_feature_l3_shared_defip_table)) {
   3657 #ifdef BCM_WARM_BOOT_SUPPORT
   3658         if (!SOC_WARM_BOOT(unit)) {
   3659 #endif
   3660             if (SOC_MEM_IS_VALID(unit, defip_pair_mem)) {
   3661                 if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) ||
   3662                     SOC_IS_HELIX4(unit) || SOC_IS_TRIDENT3X(unit) || 
   3663                     soc_feature(unit, soc_feature_l3_reduced_defip_table)) {
   3664                     defip_config = soc_property_get(unit,
   3665                                             spn_IPV6_LPM_128B_ENABLE, 1);
   3666                     if (!defip_config &&
   3667                         soc_property_get(unit, spn_L3_ALPM_ENABLE, 0) &&
   3668                         soc_feature(unit, soc_feature_alpm)) {
   3669                         ipv6_128_depth = 0;
   3670                     } else {
   3671                         int num_ipv6_def;
   3672     
   3673                         /* Pair half the tcams by default when ipv6_128b is enabled */
   3674                         num_ipv6_def = 
   3675                            ((SOC_CONTROL(unit)->l3_defip_max_tcams/2) * SOC_CONTROL(unit)->l3_defip_tcam_size) / 2;
   3676 #ifdef BCM_TRIDENT2PLUS_SUPPORT
   3677                         if (dev_id == BCM56832_DEVICE_ID) {
   3678                             num_ipv6_def = 512;
   3679                         } else
   3680 #endif /* BCM_TRIDENT2PLUS_SUPPORT */
   3681                         if (defip_config &&
   3682                             soc_feature(unit, soc_feature_l3_reduced_defip_table)) {
   3683                             num_ipv6_def = 2048;
   3684                         }
   3685                         ipv6_128_depth = soc_property_get(unit,
   3686                             spn_NUM_IPV6_LPM_128B_ENTRIES,
   3687                             (defip_config ? num_ipv6_def : 0));
   3688                     }
   3689                     ipv6_128_depth = ipv6_128_depth + (ipv6_128_depth % 2);
   3690 #ifdef ALPM_ENABLE
   3691 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   3692                     if ((SOC_IS_TOMAHAWKX(unit) || SOC_IS_APACHE(unit))
   3693                            && (soc_alpm_cmn_mode_get(unit) == SOC_ALPM_MODE_PARALLEL ||
   3694                                soc_alpm_cmn_mode_get(unit) == SOC_ALPM_MODE_TCAM_ALPM)) {
   3695                         ipv6_128_depth = (ipv6_128_depth + 3) / 4 * 4;
   3696                     } else
   3697 #endif /* BCM_TOMAHAWK_SUPPORT || BCM_APACHE_SUPPORT */
   3698                     {
   3699 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_TRIDENT2PLUS_SUPPORT)
   3700                         if (soc_trident2_alpm_mode_get(unit) == 1) {
   3701                             ipv6_128_depth = (ipv6_128_depth + 3) / 4 * 4;
   3702                         }
   3703 #endif /* BCM_TRIDENT2_SUPPORT || BCM_TRIDENT2PLUS_SUPPORT */
   3704                     }
   3705 #endif /* ALPM_ENABLE */
   3706 
   3707                     if (SOC_CONTROL(unit)->tcam_protect_write) {
   3708                         ipv6_128_depth = (ipv6_128_depth + 3) / 4 * 4;
   3709                     }
   3710                     l3_defip_pair_128_size = soc_mem_index_count(unit,
   3711                                                             defip_pair_mem);
   3712                     if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3713                        ipv6_128_depth = 0;
   3714                     }
   3715                     if (l3_defip_pair_128_size != ipv6_128_depth) {
   3716                         /* Resize the tables */
   3717                         BCM_IF_ERROR_RETURN(_bcm_xgs3_route_tables_resize(unit,
   3718                                                             ipv6_128_depth));
   3719                     }
   3720                 }
   3721             }
   3722 #ifdef BCM_WARM_BOOT_SUPPORT
   3723         }
   3724 #endif
   3725     }
   3726 
   3727 #ifdef BCM_HURRICANE3_SUPPORT
   3728     if (soc_feature(unit, soc_feature_miml_no_l3)) {
   3729         BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) = 0;
   3730         return (BCM_E_NONE);
   3731     }
   3732 #endif /* BCM_HURRICANE3_SUPPORT */
   3733 
   3734     BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) =
   3735         soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, defip));
   3736 #ifdef BCM_FIREBOLT_SUPPORT
   3737     if (SOC_IS_FBX(unit)) {
   3738         BCM_IF_ERROR_RETURN(bcm_xgs3_l3_fbx_defip_init(unit));
   3739     }
   3740 #endif /* BCM_FIREBOLT_SUPPORT */
   3741 
   3742 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   3743     if (soc_feature(unit, soc_feature_ipmc_defip)) {
   3744         BCM_IF_ERROR_RETURN(bcm_td2p_l3_defip_init(unit));
   3745     }
   3746 #endif
   3747 
   3748     return (BCM_E_NONE);
   3749 }
   3750 
   3751 /*
   3752  * Function:
   3753  *     _bcm_fb_mem_ip6_defip_lwr_set
   3754  * Purpose:
   3755  *    Set an IP6 address field in L3_DEFIPm at index n
   3756  * Parameters:
   3757  *    unit    - (IN) SOC unit number;
   3758  *    lpm_key - (OUT) Buffer to fill.
   3759  *    lpm_cfg - (IN) Route information.
   3760  * Note:
   3761  *    See soc_mem_ip6_addr_set()
   3762  */
   3763 STATIC void
   3764 _bcm_fb_mem_ip6_defip_lwr_set(int unit, void *lpm_key, _bcm_defip_cfg_t *lpm_cfg)
   3765 {
   3766     uint8 *ip6;                 /* Ip6 address.       */
   3767     uint8 mask[BCM_IP6_ADDRLEN];        /* Subnet mask.       */
   3768     uint32 ip6_word;            /* Temp storage.      */
   3769     int idx;
   3770 
   3771     /* Just to keep variable name short. */
   3772     ip6 = lpm_cfg->defip_ip6_addr;
   3773 
   3774     /* Create mask from prefix length. */
   3775     bcm_ip6_mask_create(mask, lpm_cfg->defip_sub_len);
   3776 
   3777    /* Apply subnet mask */
   3778     idx = lpm_cfg->defip_sub_len / 8;   /* Unchanged byte count.    */
   3779     if (idx < BCM_IP6_ADDRLEN) {
   3780         ip6[idx] &= mask[idx];      /* Apply mask on next byte. */
   3781     }
   3782     for (idx++; idx < BCM_IP6_ADDRLEN; idx++) {
   3783         ip6[idx] = 0;           /* Reset rest of bytes.     */
   3784     }
   3785 
   3786     if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) {
   3787         uint32 _key_data[2] = {0, 0};
   3788 
   3789         ip6_word = ((ip6[8] << 24) | (ip6[9] << 16) | (ip6[10] << 8) | (ip6[11]));
   3790         soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word);
   3791         soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_key, KEY1f, _key_data);
   3792 
   3793         ip6_word = ((ip6[12] << 24) | (ip6[13] << 16) | (ip6[14] << 8) | (ip6[15]));
   3794         soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word);
   3795         soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_key, KEY0f, _key_data);
   3796 
   3797         ip6_word = ((mask[8] << 24) | (mask[9] << 16) | (mask[10] << 8) |
   3798                    (mask[11]));
   3799         soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word);
   3800         soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_key, MASK1f, _key_data);
   3801 
   3802         ip6_word = ((mask[12] << 24) | (mask[13] << 16) | (mask[14] << 8) |
   3803                    (mask[15]));
   3804         soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word);
   3805         soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_key, MASK0f, _key_data);
   3806 
   3807         return;
   3808     }
   3809 
   3810     ip6_word = ((ip6[8] << 24) | (ip6[9] << 16) | (ip6[10] << 8) | (ip6[11]));
   3811     soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR1f, (void *)&ip6_word);
   3812 
   3813     ip6_word = ((ip6[12] << 24) | (ip6[13] << 16) | (ip6[14] << 8) | (ip6[15]));
   3814     soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR0f, (void *)&ip6_word);
   3815 
   3816     ip6_word = ((mask[8] << 24) | (mask[9] << 16) | (mask[10] << 8) |
   3817                (mask[11]));
   3818     soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_MASK1f,
   3819                             (void *)&ip6_word);
   3820 
   3821     ip6_word = ((mask[12] << 24) | (mask[13] << 16) | (mask[14] << 8) |
   3822                (mask[15]));
   3823     soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_MASK0f,
   3824                             (void *)&ip6_word);
   3825 }
   3826 
   3827 /*
   3828  * Function:
   3829  *     _bcm_fb_mem_ip6_defip_upr_set
   3830  * Purpose:
   3831  *    Set an IP6 address field in L3_DEFIPm at index n + 1024
   3832  * Parameters:
   3833  *    unit    - (IN) SOC unit number;
   3834  *    lpm_key - (OUT) Buffer to fill.
   3835  *    lpm_cfg - (IN) Route information.
   3836  * Note:
   3837  *    See soc_mem_ip6_addr_set()
   3838  */
   3839 STATIC void
   3840 _bcm_fb_mem_ip6_defip_upr_set(int unit, void *lpm_key,
   3841                               _bcm_defip_cfg_t *lpm_cfg)
   3842 {
   3843     uint8 *ip6;                 /* Ip6 address.       */
   3844     uint8 mask[BCM_IP6_ADDRLEN];        /* Subnet mask.       */
   3845     uint32 ip6_word;            /* Temp storage.      */
   3846 
   3847     /* Just to keep variable name short. */
   3848     ip6 = lpm_cfg->defip_ip6_addr;
   3849 
   3850     /* Create mask from prefix length. */
   3851     bcm_ip6_mask_create(mask, lpm_cfg->defip_sub_len);
   3852 
   3853     if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) {
   3854         uint32 _key_data[2] = {0};
   3855 
   3856         ip6_word = ((ip6[0] << 24) | (ip6[1] << 16) | (ip6[2] << 8) | (ip6[3]));
   3857         soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word);
   3858         soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x3));
   3859         soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1);
   3860         soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_key, KEY1f, _key_data);
   3861 
   3862         ip6_word = ((ip6[4] << 24) | (ip6[5] << 16) | (ip6[6] << 8) | (ip6[7]));
   3863         soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word);
   3864         soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x3));
   3865         soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1);
   3866         soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_key, KEY0f, _key_data);
   3867 
   3868         ip6_word = ((mask[0] << 24) | (mask[1] << 16) | (mask[2] << 8) |
   3869                    (mask[3]));
   3870         soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word);
   3871         soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x3));
   3872         soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1);
   3873         soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_key, MASK1f, _key_data);
   3874 
   3875         ip6_word = ((mask[4] << 24) | (mask[5] << 16) | (mask[6] << 8) |
   3876                    (mask[7]));
   3877         soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word);
   3878         soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x3));
   3879         soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1);
   3880         soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_key, MASK0f, _key_data);
   3881 
   3882         return;
   3883     }
   3884 
   3885     ip6_word = ((ip6[0] << 24) | (ip6[1] << 16) | (ip6[2] << 8) | (ip6[3]));
   3886     soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR1f, (void *)&ip6_word);
   3887 
   3888     ip6_word = ((ip6[4] << 24) | (ip6[5] << 16) | (ip6[6] << 8) | (ip6[7]));
   3889     soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR0f, (void *)&ip6_word);
   3890 
   3891     ip6_word = ((mask[0] << 24) | (mask[1] << 16) | (mask[2] << 8) |
   3892                (mask[3]));
   3893     soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_MASK1f,
   3894                             (void *)&ip6_word);
   3895 
   3896     ip6_word = ((mask[4] << 24) | (mask[5] << 16) | (mask[6] << 8) |
   3897                (mask[7]));
   3898     soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_MASK0f,
   3899                             (void *)&ip6_word);
   3900 }
   3901 
   3902 /*
   3903  * Function:
   3904  *     _bcm_fb_mem_ip6_128b_defip_get
   3905  * Purpose:
   3906  *    Set an IP6 address field in L3_DEFIPm
   3907  * Note:
   3908  *    See soc_mem_ip6_addr_set()
   3909  */
   3910 STATIC void
   3911 _bcm_fb_mem_ip6_128b_defip_get(int unit, const void *lpm_key,
   3912                             const void *lpm_key_upr, _bcm_defip_cfg_t *lpm_cfg)
   3913 {
   3914     uint8 *ip6;                 /* Ip6 address.       */
   3915     uint8 mask[BCM_IP6_ADDRLEN] = {0};        /* Subnet mask.       */
   3916     uint32 ip6_word;            /* Temp storage.      */
   3917 
   3918     /* Just to keep variable name short. */
   3919     ip6 = lpm_cfg->defip_ip6_addr;
   3920     sal_memset(ip6, 0, sizeof (bcm_ip6_t));
   3921 
   3922     if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) {
   3923         uint32 _key_data[2] = {0, 0};
   3924 
   3925         soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key_upr, KEY1f, _key_data);
   3926         ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf);
   3927         ip6[0] = (uint8) ((ip6_word >> 24) & 0xff);
   3928         ip6[1] = (uint8) ((ip6_word >> 16) & 0xff);
   3929         ip6[2] = (uint8) ((ip6_word >> 8) & 0xff);
   3930         ip6[3] = (uint8) (ip6_word & 0xff);
   3931 
   3932         soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key_upr, KEY0f, _key_data);
   3933         ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf);
   3934         ip6[4] = (uint8) ((ip6_word >> 24) & 0xff);
   3935         ip6[5] = (uint8) ((ip6_word >> 16) & 0xff);
   3936         ip6[6] = (uint8) ((ip6_word >> 8) & 0xff);
   3937         ip6[7] = (uint8) (ip6_word & 0xff);
   3938 
   3939         soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key, KEY1f, _key_data);
   3940         ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf);
   3941         ip6[8] = (uint8) ((ip6_word >> 24) & 0xff);
   3942         ip6[9] = (uint8) ((ip6_word >> 16) & 0xff);
   3943         ip6[10] = (uint8) ((ip6_word >> 8) & 0xff);
   3944         ip6[11] = (uint8) (ip6_word & 0xff);
   3945 
   3946         soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key, KEY0f, _key_data);
   3947         ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf);
   3948         ip6[12] = (uint8) ((ip6_word >> 24) & 0xff);
   3949         ip6[13] = (uint8) ((ip6_word >> 16) & 0xff);
   3950         ip6[14] = (uint8) ((ip6_word >> 8) & 0xff);
   3951         ip6[15] = (uint8) (ip6_word & 0xff);
   3952 
   3953 
   3954         soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key_upr, MASK1f, _key_data);
   3955         ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf);
   3956         mask[0] = (uint8) ((ip6_word >> 24) & 0xff);
   3957         mask[1] = (uint8) ((ip6_word >> 16) & 0xff);
   3958         mask[2] = (uint8) ((ip6_word >> 8) & 0xff);
   3959         mask[3] = (uint8) (ip6_word & 0xff);
   3960 
   3961         soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key_upr, MASK0f, _key_data);
   3962         ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf);
   3963         mask[4] = (uint8) ((ip6_word >> 24) & 0xff);
   3964         mask[5] = (uint8) ((ip6_word >> 16) & 0xff);
   3965         mask[6] = (uint8) ((ip6_word >> 8) & 0xff);
   3966         mask[7] = (uint8) (ip6_word & 0xff);
   3967 
   3968         soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key, MASK1f, _key_data);
   3969         ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf);
   3970         mask[8] = (uint8) ((ip6_word >> 24) & 0xff);
   3971         mask[9] = (uint8) ((ip6_word >> 16) & 0xff);
   3972         mask[10] = (uint8) ((ip6_word >> 8) & 0xff);
   3973         mask[11] = (uint8) (ip6_word & 0xff);
   3974 
   3975         soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key, MASK0f, _key_data);
   3976         ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf);
   3977         mask[12] = (uint8) ((ip6_word >> 24) & 0xff);
   3978         mask[13] = (uint8) ((ip6_word >> 16) & 0xff);
   3979         mask[14] = (uint8) ((ip6_word >> 8) & 0xff);
   3980         mask[15] = (uint8) (ip6_word & 0xff);
   3981 
   3982         lpm_cfg->defip_sub_len = bcm_ip6_mask_length(mask);
   3983         return;
   3984     }
   3985 
   3986     soc_L3_DEFIPm_field_get(unit, lpm_key_upr, IP_ADDR1f, &ip6_word);
   3987     ip6[0] = (uint8) ((ip6_word >> 24) & 0xff);
   3988     ip6[1] = (uint8) ((ip6_word >> 16) & 0xff);
   3989     ip6[2] = (uint8) ((ip6_word >> 8) & 0xff);
   3990     ip6[3] = (uint8) (ip6_word & 0xff);
   3991 
   3992     soc_L3_DEFIPm_field_get(unit, lpm_key_upr, IP_ADDR0f, &ip6_word);
   3993     ip6[4] = (uint8) ((ip6_word >> 24) & 0xff);
   3994     ip6[5] = (uint8) ((ip6_word >> 16) & 0xff);
   3995     ip6[6] = (uint8) ((ip6_word >> 8) & 0xff);
   3996     ip6[7] = (uint8) (ip6_word & 0xff);
   3997 
   3998     soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR1f, &ip6_word);
   3999     ip6[8] = (uint8) ((ip6_word >> 24) & 0xff);
   4000     ip6[9] = (uint8) ((ip6_word >> 16) & 0xff);
   4001     ip6[10] = (uint8) ((ip6_word >> 8) & 0xff);
   4002     ip6[11] = (uint8) (ip6_word & 0xff);
   4003 
   4004     soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR0f, &ip6_word);
   4005     ip6[12] = (uint8) ((ip6_word >> 24) & 0xff);
   4006     ip6[13] = (uint8) ((ip6_word >> 16) & 0xff);
   4007     ip6[14] = (uint8) ((ip6_word >> 8) & 0xff);
   4008     ip6[15] = (uint8) (ip6_word & 0xff);
   4009 
   4010     soc_L3_DEFIPm_field_get(unit, lpm_key_upr, IP_ADDR_MASK1f, &ip6_word);
   4011     mask[0] = (uint8) ((ip6_word >> 24) & 0xff);
   4012     mask[1] = (uint8) ((ip6_word >> 16) & 0xff);
   4013     mask[2] = (uint8) ((ip6_word >> 8) & 0xff);
   4014     mask[3] = (uint8) (ip6_word & 0xff);
   4015 
   4016     soc_L3_DEFIPm_field_get(unit, lpm_key_upr, IP_ADDR_MASK0f, &ip6_word);
   4017     mask[4] = (uint8) ((ip6_word >> 24) & 0xff);
   4018     mask[5] = (uint8) ((ip6_word >> 16) & 0xff);
   4019     mask[6] = (uint8) ((ip6_word >> 8) & 0xff);
   4020     mask[7] = (uint8) (ip6_word & 0xff);
   4021 
   4022     soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_MASK1f, &ip6_word);
   4023     mask[8] = (uint8) ((ip6_word >> 24) & 0xff);
   4024     mask[9] = (uint8) ((ip6_word >> 16) & 0xff);
   4025     mask[10] = (uint8) ((ip6_word >> 8) & 0xff);
   4026     mask[11] = (uint8) (ip6_word & 0xff);
   4027 
   4028     soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_MASK0f, &ip6_word);
   4029     mask[12] = (uint8) ((ip6_word >> 24) & 0xff);
   4030     mask[13] = (uint8) ((ip6_word >> 16) & 0xff);
   4031     mask[14] = (uint8) ((ip6_word >> 8) & 0xff);
   4032     mask[15] = (uint8) (ip6_word & 0xff);
   4033 
   4034     lpm_cfg->defip_sub_len = bcm_ip6_mask_length(mask);
   4035 }
   4036 
   4037 
   4038 /*
   4039  * Function:
   4040  *      _bcm_fb_lpm_upr_ent_init
   4041  * Purpose:
   4042  *      Service routine used to initialize lkup key for lpm entry.
   4043  * Parameters:
   4044  *      unit      - (IN)SOC unit number.
   4045  *      lpm_cfg   - (IN)Prefix info.
   4046  *      lpm_entry - (OUT)Hw buffer to fill.
   4047  * Returns:
   4048  *      BCM_E_XXX
   4049  */
   4050 STATIC int
   4051 _bcm_fb_lpm_upr_ent_init(int unit, _bcm_defip_cfg_t *lpm_cfg,
   4052                      uint32 *lpm_entry)
   4053 {
   4054     int vrf_id;
   4055     int vrf_mask;
   4056 
   4057     /* Extract entry  vrf id  & vrf mask. */
   4058     /*for Hurricane it should return default value
   4059     for vrf id*/
   4060     BCM_IF_ERROR_RETURN
   4061         (bcm_xgs3_internal_lpm_vrf_calc(unit, lpm_cfg, &vrf_id, &vrf_mask));
   4062 
   4063     if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) {
   4064         _bcm_th3_lpm_key_init(unit, lpm_cfg, lpm_entry);
   4065 
   4066         /* Set prefix ip address & mask. */
   4067         _bcm_fb_mem_ip6_defip_upr_set(unit, lpm_entry, lpm_cfg);
   4068 
   4069         /* Set valid bit. */
   4070         soc_mem_field32_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, VALID0f, 1);
   4071         /* Set second part valid bit. */
   4072         soc_mem_field32_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, VALID1f, 1);
   4073 
   4074         return BCM_E_NONE;
   4075     }
   4076 
   4077     /* Set prefix ip address & mask. */
   4078     _bcm_fb_mem_ip6_defip_upr_set(unit, lpm_entry, lpm_cfg);
   4079 
   4080     soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_0f, vrf_id);
   4081     soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_MASK0f, vrf_mask);
   4082     /* Set valid bit. */
   4083     soc_L3_DEFIPm_field32_set(unit, lpm_entry, VALID0f, 1);
   4084     /* Set second part valid bit. */
   4085     soc_L3_DEFIPm_field32_set(unit, lpm_entry, VALID1f, 1);
   4086 
   4087     /* Set mode to ipv6 */
   4088     soc_L3_DEFIPm_field32_set(unit, lpm_entry, defip_mode0_bit[unit], 3);
   4089     soc_L3_DEFIPm_field32_set(unit, lpm_entry, defip_mode1_bit[unit], 3);
   4090 
   4091     /* Set Virtual Router id if supported. */
   4092     if (SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), VRF_ID_1f)){
   4093         soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_1f, vrf_id);
   4094         soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_MASK1f, vrf_mask);
   4095     }
   4096 #if defined(BCM_TRX_SUPPORT) || defined(BCM_RAVEN_SUPPORT)
   4097     if (soc_mem_field_valid(unit, BCM_XGS3_L3_MEM(unit, defip), defip_mode_mask0_bit[unit])) {
   4098         soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, defip_mode_mask0_bit[unit],
   4099             (1 << soc_mem_field_length(unit, BCM_XGS3_L3_MEM(unit, defip), defip_mode_mask0_bit[unit])) - 1);
   4100     }
   4101     if (soc_mem_field_valid(unit, BCM_XGS3_L3_MEM(unit, defip), defip_mode_mask1_bit[unit])) {
   4102         soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, defip_mode_mask1_bit[unit],
   4103             (1 << soc_mem_field_length(unit, BCM_XGS3_L3_MEM(unit, defip), defip_mode_mask1_bit[unit])) - 1);
   4104     }
   4105 #endif /* BCM_TRX_SUPPORT || BCM_RAVEN_SUPPORT */
   4106 
   4107 #if defined(BCM_TRX_SUPPORT)
   4108     if (SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), GLOBAL_ROUTE0f)) {
   4109         if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) {
   4110             soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip),
   4111                                 lpm_entry, GLOBAL_ROUTE0f, 0x1);
   4112         }
   4113     }
   4114 #endif /* BCM_TRX_SUPPORT */
   4115 
   4116     return (BCM_E_NONE);
   4117 }
   4118 
   4119 int
   4120 _bcm_fb_get_largest_prefix(int u, int ipv6, void *e,
   4121                               int *index, int *pfx_len, int* count)
   4122 {
   4123     return soc_fb_get_largest_prefix(u, ipv6, e, index, pfx_len, count);
   4124 }
   4125 
   4126 int _bcm_fb_lpm128_get_smallest_movable_prefix(int u, int ipv6,
   4127                                               void *e, void *eupr, int *index,
   4128                                               int *pfx_len, int*count)
   4129 {
   4130     return soc_fb_lpm128_get_smallest_movable_prefix(u, ipv6, e, eupr, index,
   4131                                                      pfx_len, count);
   4132 }
   4133 
   4134 /*
   4135  * Function:
   4136  *      _bcm_fb_lpm128_ent_get_key
   4137  * Purpose:
   4138  *      Parse entry key from DEFIP table.
   4139  * Parameters:
   4140  *      unit        - (IN)SOC unit number.
   4141  *      lpm_cfg     - (OUT)Buffer to fill defip information.
   4142  *      lpm_entry   - (IN) Buffer read from hw.
   4143  *      lpm_entry_upr   - (IN) Buffer read from hw.
   4144  * Returns:
   4145  *      void
   4146  */
   4147 STATIC void
   4148 _bcm_fb_lpm128_ent_get_key(int unit, _bcm_defip_cfg_t *lpm_cfg,
   4149                         uint32 *lpm_entry, uint32 *lpm_entry_upr)
   4150 {
   4151     int ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6;
   4152 
   4153     /* Set prefix ip address & mask. */
   4154     if (ipv6) {
   4155         _bcm_fb_mem_ip6_128b_defip_get(unit, lpm_entry, lpm_entry_upr, lpm_cfg);
   4156     }
   4157 
   4158     /* Get Virtual Router id */
   4159     soc_fb_lpm_vrf_get(unit, lpm_entry, &lpm_cfg->defip_vrf);
   4160 
   4161     return;
   4162 }
   4163 
   4164 /*
   4165  * Function:
   4166  *     _bcm_fb_lpm128_defip_cfg_get
   4167  * Purpose:
   4168  *      Parse entry key from DEFIP table.
   4169  * Parameters:
   4170  *      unit        - (IN)SOC unit number.
   4171  *      lpm_entry   - (IN) Buffer read from hw.
   4172  *      lpm_entry_upr   - (IN) Buffer read from hw.
   4173  *      lpm_cfg     - (OUT)Buffer to fill defip information.
   4174  *      nh_ecmp_idx - (OUT) ecmp nh_index id
   4175  * Returns:
   4176  *      void
   4177  */
   4178 int
   4179 _bcm_fb_lpm128_defip_cfg_get(int unit, void *defip_lpm_entry,
   4180                              void *defip_lpm_entry_upr,
   4181                              _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx)
   4182 {
   4183     uint32 lpm_entry[SOC_MAX_MEM_WORDS];
   4184     uint32 lpm_entry_upr[SOC_MAX_MEM_WORDS];
   4185     int b128 = 0;
   4186 
   4187     if (lpm_cfg == NULL || defip_lpm_entry == NULL) {
   4188         return BCM_E_PARAM;
   4189     }
   4190 
   4191     sal_memcpy(lpm_entry, defip_lpm_entry,
   4192                BCM_XGS3_L3_ENT_SZ(unit, defip));
   4193     sal_memcpy(lpm_entry_upr, defip_lpm_entry_upr,
   4194                BCM_XGS3_L3_ENT_SZ(unit, defip));
   4195 
   4196     /* Parse  the entry. */
   4197     BCM_IF_ERROR_RETURN(
   4198         _bcm_fb_lpm_ent_parse(unit, lpm_cfg, nh_ecmp_idx,
   4199                           (uint32 *)lpm_entry, &b128));
   4200      if (!b128) {
   4201          return SOC_E_PARAM;
   4202      }
   4203 
   4204      _bcm_fb_lpm128_ent_get_key(unit, lpm_cfg, lpm_entry, lpm_entry_upr);
   4205      lpm_cfg->defip_index = BCM_XGS3_L3_INVALID_INDEX;
   4206      return SOC_E_NONE;
   4207 }
   4208 
   4209 /*
   4210  * Function:
   4211  *     _bcm_fb_mem_ip6_defip_set
   4212  * Purpose:
   4213  *    Set an IP6 address field in L3_DEFIPm
   4214  * Parameters:
   4215  *    unit    - (IN) SOC unit number;
   4216  *    lpm_key - (OUT) Buffer to fill.
   4217  *    lpm_cfg - (IN) Route information.
   4218  * Note:
   4219  *    See soc_mem_ip6_addr_set()
   4220  */
   4221 STATIC void
   4222 _bcm_fb_mem_ip6_defip_set(int unit, void *lpm_key, _bcm_defip_cfg_t *lpm_cfg)
   4223 {
   4224     uint8 *ip6;                 /* Ip6 address.       */
   4225     uint8 mask[BCM_IP6_ADDRLEN];        /* Subnet mask.       */
   4226     uint32 ip6_word;            /* Temp storage.      */
   4227     int idx;                    /* Iteration index .  */
   4228 
   4229     /* Just to keep variable name short. */
   4230     ip6 = lpm_cfg->defip_ip6_addr;
   4231 
   4232     /* Create mask from prefix length. */
   4233     bcm_ip6_mask_create(mask, lpm_cfg->defip_sub_len);
   4234 
   4235     /* Apply subnet mask */
   4236     idx = lpm_cfg->defip_sub_len / 8;   /* Unchanged byte count.    */
   4237     ip6[idx] &= mask[idx];      /* Apply mask on next byte. */
   4238     for (idx++; idx < BCM_IP6_ADDRLEN; idx++) {
   4239         ip6[idx] = 0;           /* Reset rest of bytes.     */
   4240     }
   4241 
   4242 
   4243     ip6_word = ((ip6[0] << 24) | (ip6[1] << 16) | (ip6[2] << 8) | (ip6[3]));
   4244     soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR1f, (void *)&ip6_word);
   4245 
   4246     ip6_word = ((ip6[4] << 24) | (ip6[5] << 16) | (ip6[6] << 8) | (ip6[7]));
   4247     soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR0f, (void *)&ip6_word);
   4248 
   4249     ip6_word = ((mask[0] << 24) | (mask[1] << 16) | (mask[2] << 8) | (mask[3]));
   4250     soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_MASK1f,
   4251                             (void *)&ip6_word);
   4252 
   4253     ip6_word = ((mask[4] << 24) | (mask[5] << 16) | (mask[6] << 8) | (mask[7]));
   4254     soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_MASK0f,
   4255                             (void *)&ip6_word);
   4256 }
   4257 
   4258 int
   4259 _bcm_th3_lpm_key_init(int unit, _bcm_defip_cfg_t *lpm_cfg,
   4260                      uint32 *lpm_entry)
   4261 {
   4262     int ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6;
   4263     uint32 _key_data[2] = {0,0};
   4264     uint8 *ip6;                 /* Ip6 address.       */
   4265     uint8 mask[BCM_IP6_ADDRLEN];        /* Subnet mask.       */
   4266     uint32 ip6_word;            /* Temp storage.      */
   4267     int idx;
   4268 
   4269     int mode = 1;
   4270     int vrf_id;
   4271     int vrf_mask;
   4272     bcm_ip_t ip4_mask;
   4273     ip4_mask = BCM_IP4_MASKLEN_TO_ADDR(lpm_cfg->defip_sub_len);
   4274 
   4275     BCM_IF_ERROR_RETURN
   4276         (bcm_xgs3_internal_lpm_vrf_calc(unit, lpm_cfg, &vrf_id, &vrf_mask));
   4277 
   4278     if (!ipv6) {
   4279         mode = 0;
   4280     } else if (lpm_cfg->defip_sub_len > 64 ||
   4281                lpm_cfg->defip_flags_high & BCM_XGS3_L3_ENTRY_IN_DEFIP_PAIR) {
   4282         mode = 3;
   4283     } else {
   4284         mode = 1;
   4285     }
   4286 
   4287     /* Just to keep variable name short. */
   4288     ip6 = lpm_cfg->defip_ip6_addr;
   4289 
   4290     /* Create mask from prefix length. */
   4291     bcm_ip6_mask_create(mask, lpm_cfg->defip_sub_len);
   4292 
   4293    /* Apply subnet mask */
   4294     idx = lpm_cfg->defip_sub_len / 8;   /* Unchanged byte count.    */
   4295     if (idx < BCM_IP6_ADDRLEN) {
   4296         ip6[idx] &= mask[idx];      /* Apply mask on next byte. */
   4297     }
   4298     for (idx++; idx < BCM_IP6_ADDRLEN; idx++) {
   4299         ip6[idx] = 0;           /* Reset rest of bytes.     */
   4300     }
   4301 
   4302     soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, lpm_cfg->defip_ip_addr);
   4303     soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, mode);
   4304     soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf, vrf_id);
   4305     soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, (ipv6 ? 1 : 0));
   4306     soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, KEY0f, _key_data);
   4307 
   4308     _key_data[0] = _key_data[1] = 0;
   4309     soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf, vrf_mask);
   4310     soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip4_mask);
   4311     soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x3));
   4312     soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1);
   4313     soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, MASK0f, _key_data);
   4314     if (ipv6) {
   4315         /* Apply subnet mask */
   4316         idx = lpm_cfg->defip_sub_len / 8;   /* Unchanged byte count.    */
   4317         if (idx < BCM_IP6_ADDRLEN) {
   4318             ip6[idx] &= mask[idx];      /* Apply mask on next byte. */
   4319         }
   4320         for (idx++; idx < BCM_IP6_ADDRLEN; idx++) {
   4321             ip6[idx] = 0;           /* Reset rest of bytes.     */
   4322         }
   4323 
   4324         _key_data[0] = _key_data[1] = 0;
   4325 
   4326         if (mode == 3) {
   4327            ip6_word = ((ip6[8] << 24) | (ip6[9] << 16) | (ip6[10] << 8) | (ip6[11]));
   4328            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word);
   4329            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf, vrf_id);
   4330            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x3));
   4331            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1);
   4332            soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, KEY1f, _key_data);
   4333 
   4334            ip6_word = ((ip6[12] << 24) | (ip6[13] << 16) | (ip6[14] << 8) | (ip6[15]));
   4335            _key_data[0] = _key_data[1] = 0;
   4336            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word);
   4337            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x3));
   4338            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1);
   4339            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf, vrf_id);
   4340            soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, KEY0f, _key_data);
   4341 
   4342            ip6_word = ((mask[8] << 24) | (mask[9] << 16) | (mask[10] << 8) |
   4343                       (mask[11]));
   4344            _key_data[0] = _key_data[1] = 0;
   4345            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word);
   4346            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf, vrf_mask);
   4347            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x3));
   4348            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1);
   4349            soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, MASK1f, _key_data);
   4350 
   4351            ip6_word = ((mask[12] << 24) | (mask[13] << 16) | (mask[14] << 8) |
   4352                       (mask[15]));
   4353            _key_data[0] = _key_data[1] = 0;
   4354            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word);
   4355            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x3));
   4356            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1);
   4357            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf, vrf_mask);
   4358            soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, MASK0f, _key_data);
   4359 
   4360         } else {
   4361 
   4362            ip6_word = ((ip6[0] << 24) | (ip6[1] << 16) | (ip6[2] << 8) | (ip6[3]));
   4363            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word);
   4364            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf, vrf_id);
   4365            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x1));
   4366            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1);
   4367            soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, KEY1f, _key_data);
   4368 
   4369            ip6_word = ((ip6[4] << 24) | (ip6[5] << 16) | (ip6[6] << 8) | (ip6[7]));
   4370            _key_data[0] = _key_data[1] = 0;
   4371            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word);
   4372            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf, vrf_id);
   4373            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x1));
   4374            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1);
   4375            soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, KEY0f, _key_data);
   4376 
   4377            ip6_word = ((mask[0] << 24) | (mask[1] << 16) | (mask[2] << 8) |
   4378                       (mask[3]));
   4379            _key_data[0] = _key_data[1] = 0;
   4380            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word);
   4381            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf, vrf_mask);
   4382            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x1));
   4383            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1);
   4384            soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, MASK1f, _key_data);
   4385 
   4386            ip6_word = ((mask[4] << 24) | (mask[5] << 16) | (mask[6] << 8) |
   4387                       (mask[7]));
   4388            _key_data[0] = _key_data[1] = 0;
   4389            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf, ip6_word);
   4390            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf, vrf_mask);
   4391            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf, (0x1));
   4392            soc_format_field32_set(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf, 1);
   4393            soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry, MASK0f, _key_data);
   4394        }
   4395     }
   4396     return (BCM_E_NONE);
   4397 }
   4398 
   4399 /*
   4400  * Function:
   4401  *      _bcm_fb_lpm_ent_init
   4402  * Purpose:
   4403  *      Service routine used to initialize lkup key for lpm entry.
   4404  * Parameters:
   4405  *      unit      - (IN)SOC unit number.
   4406  *      lpm_cfg   - (IN)Prefix info.
   4407  *      lpm_entry - (OUT)Hw buffer to fill.
   4408  * Returns:
   4409  *      BCM_E_XXX
   4410  */
   4411 int
   4412 _bcm_fb_lpm_ent_init(int unit, _bcm_defip_cfg_t *lpm_cfg,
   4413                      uint32 *lpm_entry)
   4414 {
   4415     bcm_ip_t ip4_mask;
   4416     int vrf_id;
   4417     int vrf_mask;
   4418     int ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6;
   4419     int ipmc = lpm_cfg->defip_flags & BCM_L3_IPMC;
   4420     int pfx_len = lpm_cfg->defip_sub_len;
   4421     int mode = 1;
   4422 
   4423 #ifdef BCM_TRIDENT3_SUPPORT
   4424     if (soc_feature(unit, soc_feature_flex_flow) &&
   4425         lpm_cfg->defip_flow_handle != 0) {
   4426        return _bcm_td3_lpm_flex_ent_init(unit, lpm_cfg, lpm_entry);
   4427     }
   4428 #endif
   4429 
   4430     /* Extract entry  vrf id  & vrf mask. */
   4431     /*for Hurricane it should return default value
   4432     for vrf id*/
   4433     BCM_IF_ERROR_RETURN
   4434         (bcm_xgs3_internal_lpm_vrf_calc(unit, lpm_cfg, &vrf_id, &vrf_mask));
   4435 
   4436     /* Set mode  */
   4437     if (!ipv6) {
   4438         mode = 0;
   4439     } else if (pfx_len > 64 ||
   4440                lpm_cfg->defip_flags_high & BCM_XGS3_L3_ENTRY_IN_DEFIP_PAIR) {
   4441         mode = 3;
   4442     } else {
   4443         mode = 1;
   4444     }
   4445 
   4446     /* Set prefix ip address & mask. */
   4447     if (ipv6) {
   4448         if (SOC_MEM_IS_VALID(unit, L3_DEFIPm)) {
   4449             if (mode == 3) {
   4450                _bcm_fb_mem_ip6_defip_lwr_set(unit, lpm_entry, lpm_cfg);
   4451             } else {
   4452                _bcm_fb_mem_ip6_defip_set(unit, lpm_entry, lpm_cfg);
   4453             }
   4454         }
   4455     } else {
   4456         ip4_mask = BCM_IP4_MASKLEN_TO_ADDR(lpm_cfg->defip_sub_len);
   4457         /* Apply subnet mask. */
   4458         lpm_cfg->defip_ip_addr &= ip4_mask;
   4459 
   4460         if (SOC_MEM_IS_VALID(unit, L3_DEFIPm)) {
   4461             /* Set address to the buffer. */
   4462             soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, IP_ADDR0f,
   4463                                       lpm_cfg->defip_ip_addr);
   4464             soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, IP_ADDR_MASK0f, ip4_mask);
   4465         }
   4466     }
   4467 
   4468 
   4469     if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) {
   4470         uint32          fmte[10];
   4471         _bcm_th3_lpm_key_init(unit, lpm_cfg, lpm_entry);
   4472         sal_memset(fmte, 0, sizeof(fmte));
   4473         if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) {
   4474             soc_format_field32_set(unit, FIXED_DATAfmt, fmte,
   4475                                    SUB_DB_PRIORITYf, 2);
   4476         } else if (BCM_L3_VRF_OVERRIDE == lpm_cfg->defip_vrf) {
   4477             soc_format_field32_set(unit, FIXED_DATAfmt, fmte,
   4478                                    SUB_DB_PRIORITYf, 0);
   4479         } else {
   4480             soc_format_field32_set(unit, FIXED_DATAfmt, fmte,
   4481                                    SUB_DB_PRIORITYf, 1);
   4482         }
   4483         soc_mem_field_set(unit, L3_DEFIP_LEVEL1m, lpm_entry,
   4484                           FIXED_DATA0f, fmte);
   4485     } else {
   4486         if (ipv6) {
   4487 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \
   4488     defined(BCM_TRX_SUPPORT)
   4489             /* Set Virtual Router id if supported. */
   4490             if (SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), VRF_ID_1f)){
   4491                 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, VRF_ID_1f, vrf_id);
   4492                 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, VRF_ID_MASK1f, vrf_mask);
   4493             }
   4494 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */
   4495         }
   4496     }
   4497 
   4498     /* Set valid bit. */
   4499     soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, VALID0f, 1);
   4500     if (ipv6) {
   4501         /* Set second part valid bit. */
   4502         soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, VALID1f, 1);
   4503     }
   4504 
   4505 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \
   4506     defined(BCM_TRX_SUPPORT)
   4507     /* Set Virtual Router id if supported. */
   4508     if (!SOC_IS_HURRICANEX(unit) && SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), VRF_ID_0f)) {
   4509         soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, VRF_ID_0f, vrf_id);
   4510         soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, VRF_ID_MASK0f, vrf_mask);
   4511     }
   4512 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */
   4513 
   4514 #if defined(BCM_TRIDENT2_SUPPORT)
   4515     if (lpm_cfg->defip_entry_type == bcmDefipEntryTypeFcoe && SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), VRF_ID_0f)) {
   4516         soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, VRF_ID_0f, vrf_id);
   4517         soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, VRF_ID_MASK0f, vrf_mask);
   4518         soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, D_ID0f,
   4519                                   lpm_cfg->defip_fcoe_d_id);
   4520         soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, D_ID_MASK0f,
   4521                                   lpm_cfg->defip_fcoe_d_id_mask);
   4522 #ifdef BCM_TRIDENT3_SUPPORT
   4523         if (SOC_IS_TRIDENT3X(unit)) {
   4524             soc_L3_DEFIPm_field32_set(unit, lpm_entry, DATA_TYPE0f, 3);
   4525         } else
   4526 #endif /* BCM_TRIDENT3_SUPPORT */
   4527         {
   4528         soc_L3_DEFIPm_field32_set(unit, lpm_entry, ENTRY_TYPE0f, 1);
   4529         soc_L3_DEFIPm_field32_set(unit, lpm_entry, ENTRY_TYPE_MASK0f, 1);
   4530     }
   4531     }
   4532 #endif
   4533 
   4534     if (ipmc && SOC_IS_TRIDENT3X(unit)) {
   4535         soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, DATA_TYPE0f, 2);
   4536     }
   4537 
   4538     if (SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), defip_mode0_bit[unit])) {
   4539         soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, defip_mode0_bit[unit], mode);
   4540     }
   4541 
   4542     if (SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), defip_mode1_bit[unit])) {
   4543         soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, defip_mode1_bit[unit], mode);
   4544     }
   4545 
   4546 #if defined(BCM_TRX_SUPPORT) || defined(BCM_RAVEN_SUPPORT)
   4547     if (soc_mem_field_valid(unit, BCM_XGS3_L3_MEM(unit, defip), defip_mode_mask0_bit[unit])) {
   4548         soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, defip_mode_mask0_bit[unit],
   4549             (1 << soc_mem_field_length(unit, BCM_XGS3_L3_MEM(unit, defip), defip_mode_mask0_bit[unit])) - 1);
   4550     }
   4551     if (soc_mem_field_valid(unit, BCM_XGS3_L3_MEM(unit, defip), defip_mode_mask1_bit[unit])) {
   4552         soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, defip_mode_mask1_bit[unit],
   4553             (1 << soc_mem_field_length(unit, BCM_XGS3_L3_MEM(unit, defip), defip_mode_mask1_bit[unit])) - 1);
   4554     }
   4555 #endif /* BCM_TRX_SUPPORT || BCM_RAVEN_SUPPORT */
   4556 #if defined(BCM_RAVEN_SUPPORT)
   4557     if (soc_mem_field_valid(unit, BCM_XGS3_L3_MEM(unit, defip), RESERVED_MASK0f)) {
   4558         soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip),
   4559                             lpm_entry, RESERVED_MASK0f, 0);
   4560     }
   4561     if (soc_mem_field_valid(unit, BCM_XGS3_L3_MEM(unit, defip), RESERVED_KEY0f)) {
   4562         soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, RESERVED_KEY0f, 0);
   4563     }
   4564     if (soc_mem_field_valid(unit, BCM_XGS3_L3_MEM(unit, defip), RESERVED_MASK1f)) {
   4565         soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip),
   4566                             lpm_entry, RESERVED_MASK1f, 0);
   4567     }
   4568     if (soc_mem_field_valid(unit, BCM_XGS3_L3_MEM(unit, defip), RESERVED_KEY1f)) {
   4569         soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, RESERVED_KEY1f, 0);
   4570     }
   4571 #endif /* BCM_RAVEN_SUPPORT */
   4572 
   4573 #if defined(BCM_TRX_SUPPORT)
   4574     if (SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), GLOBAL_ROUTE0f)) {
   4575         if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) {
   4576             soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip),
   4577                                 lpm_entry, GLOBAL_ROUTE0f, 0x1);
   4578         }
   4579     }
   4580 #endif /* BCM_TRX_SUPPORT */
   4581 
   4582     return (BCM_E_NONE);
   4583 }
   4584 
   4585 
   4586 /*
   4587  * Routine to fill the L3_DEFIP_DATA_ONLY and L3_DEFIP_HIT_ONLY buffers
   4588  * as per the given DEFIP config structure.
   4589  */ 
   4590 int
   4591 _bcm_fb_lpm_prepare_defip_data(int unit,
   4592                                _bcm_defip_cfg_t *lpm_cfg,
   4593                                int nh_ecmp_idx,
   4594                                uint32 *lpm_data,
   4595                                uint32 *lpm_hit,
   4596                                int upper)
   4597 {
   4598     int rpe[2] = {RPE0f, RPE1f};
   4599     int pri[2] = {PRI0f, PRI1f};
   4600     int ecmp[2] = {ECMP0f, ECMP1f};
   4601 #if defined(BCM_TRX_SUPPORT)
   4602     int class_id[2] = {CLASS_ID0f, CLASS_ID1f};
   4603     int global_route[2] = {GLOBAL_ROUTE0f, GLOBAL_ROUTE1f};
   4604 #endif
   4605     int dst_discard[2] = {DST_DISCARD0f, DST_DISCARD1f};
   4606     int default_route[2] = {DEFAULTROUTE0f, DEFAULTROUTE1f};
   4607     int next_hop_index[2] = {NEXT_HOP_INDEX0f, NEXT_HOP_INDEX1f};
   4608     int ecmp_count[2] = {ECMP_COUNT0f, ECMP_COUNT1f};
   4609 #if defined(BCM_TRIDENT3_SUPPORT)
   4610     int dest_field[2] = {DESTINATION0f, DESTINATION1f};
   4611 #endif
   4612 #if 0
   4613     int ecmp_ptr[2] = {ECMP_PTR0f, ECMP_PTR1f};
   4614     int src_discard[2] = {SRC_DISCARD0f, SRC_DISCARD1f};
   4615     int reserved_ecmp_ptr[2] = {RESERVED_ECMP_PTR0f, RESERVED_ECMP_PTR1f};
   4616 #endif
   4617     soc_mem_t mem = L3_DEFIP_DATA_ONLYm;
   4618     soc_mem_t hit_mem = L3_DEFIP_HIT_ONLYm;
   4619 
   4620     if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1_HIT_ONLYm)) {
   4621         mem = L3_DEFIP_DATA_LEVEL1m;
   4622         hit_mem = L3_DEFIP_LEVEL1_HIT_ONLYm;
   4623     }
   4624     if (NULL == lpm_cfg || NULL == lpm_data) {
   4625         return BCM_E_INTERNAL;
   4626     }
   4627 
   4628     if (upper >> 1) {
   4629        return BCM_E_INTERNAL;
   4630     }
   4631 
   4632     /* Set hit bit. */
   4633     if (lpm_hit != NULL) {
   4634         int hit[2] = {HIT0f, HIT1f};
   4635 
   4636         if (lpm_cfg->defip_flags & BCM_L3_HIT) {
   4637            soc_mem_field32_set(unit, hit_mem, lpm_hit, hit[upper], 1);
   4638         }
   4639     }
   4640 
   4641     if (SOC_IS_TOMAHAWK3(unit)) {
   4642         uint32          fmte[10];
   4643         sal_memset(fmte, 0, sizeof(fmte));
   4644         if (lpm_cfg->defip_flags & BCM_L3_RPE) {
   4645             soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, RPE0f, 1);
   4646         }
   4647         soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, PRI0f, lpm_cfg->defip_prio);
   4648         soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, CLASS_ID0f,
   4649                                       lpm_cfg->defip_lookup_class);
   4650         soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, DESTINATIONf, nh_ecmp_idx);
   4651 
   4652         if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) {
   4653             soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, DEST_TYPEf, 1);
   4654         } else if (nh_ecmp_idx != BCM_XGS3_L3_INVALID_INDEX) {
   4655             soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, DEST_TYPEf, 0);
   4656         }
   4657 
   4658         if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   4659             soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, FLEX_CTR_OFFSET_MODEf,
   4660                                       lpm_cfg->defip_flex_ctr_mode);
   4661             soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, FLEX_CTR_POOL_NUMBERf,
   4662                                       lpm_cfg->defip_flex_ctr_pool);
   4663             soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, FLEX_CTR_BASE_COUNTER_IDXf,
   4664                                       lpm_cfg->defip_flex_ctr_base_id);
   4665         }
   4666         if (lpm_cfg->defip_flags & BCM_L3_DST_DISCARD) {
   4667             soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, DST_DISCARDf, 1);
   4668         }
   4669         if (upper) {
   4670             soc_mem_field_set(unit, mem, lpm_data, ASSOC_DATA1f, fmte);
   4671         } else {
   4672             soc_mem_field_set(unit, mem, lpm_data, ASSOC_DATA0f, fmte);
   4673         }
   4674         sal_memset(fmte, 0, sizeof(fmte));
   4675         soc_format_field32_set(unit, ALPM1_DATAfmt, fmte, DIRECT_ROUTEf, 1);
   4676         soc_mem_field_set(unit, mem, lpm_data, ALPM1_DATA0f, fmte);
   4677         sal_memset(fmte, 0, sizeof(fmte));
   4678         if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) {
   4679             soc_format_field32_set(unit, FIXED_DATAfmt, fmte, SUB_DB_PRIORITYf, 2);
   4680         } else if (BCM_L3_VRF_OVERRIDE == lpm_cfg->defip_vrf) {
   4681             soc_format_field32_set(unit, FIXED_DATAfmt, fmte, SUB_DB_PRIORITYf, 0);
   4682         } else {
   4683             soc_format_field32_set(unit, FIXED_DATAfmt, fmte, SUB_DB_PRIORITYf, 1);
   4684         }
   4685         soc_mem_field_set(unit, mem, lpm_data, FIXED_DATA0f, fmte);
   4686         return BCM_E_NONE;
   4687     }
   4688     /* Set priority override bit. */
   4689     if (lpm_cfg->defip_flags & BCM_L3_RPE) {
   4690         soc_mem_field32_set(unit, mem, lpm_data, rpe[upper], 1);
   4691     }
   4692 
   4693     /* Configure entry for SIP lookup if URPF is enabled.
   4694      * For devices like KT2 both DIP and SIP lookup is done
   4695      * using only 1 L3_DEFIP entry, unlike other devices where
   4696      * L3_DEFIP table is divided in 2 parts to support URPF.
   4697      * RPExf and DEFAULTROUTExf are not overlayed in KT2 like previous devices.
   4698      */
   4699     if (soc_feature(unit, soc_feature_l3_defip_advanced_lookup)) {
   4700         soc_mem_field32_set(unit, mem, lpm_data, default_route[upper],
   4701             (SOC_URPF_STATUS_GET(unit) ? 1 : 0));
   4702     }
   4703 
   4704     /* Write priority field. */
   4705     soc_mem_field32_set(unit, mem, lpm_data, pri[upper], lpm_cfg->defip_prio);
   4706 
   4707     /* Fill next hop information. */
   4708 #if defined(BCM_TRIDENT3_SUPPORT)
   4709     if (SOC_IS_TRIDENT3X(unit)) {
   4710         /* TRIDENT3 has DESTINATION0 and DESTINATION1 fields */
   4711         if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) {
   4712             soc_mem_field32_dest_set(unit, mem, lpm_data, dest_field[upper],
   4713                                      SOC_MEM_FIF_DEST_ECMP, nh_ecmp_idx);
   4714         } else if (nh_ecmp_idx != BCM_XGS3_L3_INVALID_INDEX) {
   4715             soc_mem_field32_dest_set(unit, mem, lpm_data, dest_field[upper],
   4716                                      SOC_MEM_FIF_DEST_NEXTHOP, nh_ecmp_idx);
   4717         }
   4718     } else
   4719 #endif
   4720     {
   4721         if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) {
   4722             soc_mem_field32_set(unit, mem, lpm_data, ecmp[upper], 1);
   4723             /* NOTE: Order is important set next hop index before ECMP_COUNT.
   4724             * If device doesn't have ECMP_COUNT:  ECMP_PTR field is shorter than
   4725             * next hop -> we must ensure that write resets high bits of next hop
   4726             * field.
   4727             */
   4728             if (nh_ecmp_idx != BCM_XGS3_L3_INVALID_INDEX) {
   4729                 soc_mem_field32_set(unit, mem, lpm_data, next_hop_index[upper],
   4730                                     nh_ecmp_idx);
   4731             }
   4732             if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, ecmp_count[upper])) {
   4733                 soc_mem_field32_set(unit, mem, lpm_data, ecmp_count[upper],
   4734                                     lpm_cfg->defip_ecmp_count);
   4735             }
   4736         } else {
   4737             soc_mem_field32_set(unit, mem, lpm_data, ecmp[upper], 0);
   4738             if (nh_ecmp_idx != BCM_XGS3_L3_INVALID_INDEX) {
   4739                 soc_mem_field32_set(unit, mem, lpm_data, next_hop_index[upper],
   4740                                     nh_ecmp_idx);
   4741             }
   4742         }
   4743     }
   4744 
   4745     /* Set destination discard flag. */
   4746     if (lpm_cfg->defip_flags & BCM_L3_DST_DISCARD) {
   4747         if (SOC_MEM_FIELD_VALID(unit, mem, dst_discard[upper])) {
   4748             soc_mem_field32_set(unit, mem, lpm_data, dst_discard[upper], 1);
   4749         } else {
   4750             return (BCM_E_UNAVAIL);
   4751         }
   4752     }
   4753 
   4754 #if defined(BCM_TRX_SUPPORT)
   4755     /* Set classification group id. */
   4756     if (SOC_MEM_FIELD_VALID(unit, mem, class_id[upper])) {
   4757         soc_mem_field32_set(unit, mem, lpm_data, class_id[upper],
   4758                                   lpm_cfg->defip_lookup_class);
   4759     }
   4760 
   4761     /* Set Global route flag. */
   4762     if (SOC_MEM_FIELD_VALID(unit, mem, global_route[upper])) {
   4763         if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) {
   4764             soc_mem_field32_set(unit, mem, lpm_data,
   4765                                 global_route[upper], 0x1);
   4766         }
   4767     }
   4768 #endif /* BCM_TRX_SUPPORT */
   4769 
   4770 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   4771     if (soc_feature(unit, soc_feature_ipmc_defip) &&  
   4772             (lpm_cfg->defip_flags & BCM_L3_IPMC)) {
   4773 
   4774         int l3mc_index[2] = {L3MC_INDEX0f, L3MC_INDEX1f};
   4775         int dest_fmt[2] = {DESTINATION0f, DESTINATION1f};
   4776         int expected_l3_iif[2] = {EXPECTED_L3_IIF0f, EXPECTED_L3_IIF1f};
   4777         int multicast_route[2] = {MULTICAST_ROUTE0f, MULTICAST_ROUTE1f};
   4778         int data_type[2] = {DATA_TYPE0f, DATA_TYPE1f};
   4779         int ipmc_ext_l3_iifp_mismatch_drop[2] =
   4780           {IPMC_EXPECTED_L3_IIF_MISMATCH_DROP0f, IPMC_EXPECTED_L3_IIF_MISMATCH_DROP1f};
   4781         int ipmc_ext_l3_iifp_mismatch_tocpu[2] =
   4782           {IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPU0f, IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPU1f};
   4783 
   4784         if (soc_mem_field_valid(unit, mem, multicast_route[upper])) {
   4785             soc_mem_field32_set(unit, mem, lpm_data, multicast_route[upper], 1);
   4786         } else if (soc_mem_field_valid(unit, mem, data_type[upper])) {
   4787             soc_mem_field32_set(unit, mem, lpm_data, data_type[upper], 2);
   4788         }
   4789 
   4790         if (soc_feature(unit, soc_feature_generic_dest)) {
   4791             if (lpm_cfg->defip_mc_group > 0) {
   4792                 soc_mem_field32_dest_set(unit, mem, lpm_data, dest_fmt[upper],
   4793                     SOC_MEM_FIF_DEST_IPMC, lpm_cfg->defip_mc_group);
   4794             }
   4795         } else {
   4796             soc_mem_field32_set(unit, mem, lpm_data, l3mc_index[upper], lpm_cfg->defip_mc_group);
   4797         }
   4798 
   4799         /*
   4800          * RP ID needs uplift by _BCM_L3_DEFIP_RP_ID_BASE value, Now it wil fit in EXPECTED_L3_IIFf
   4801          */
   4802         if (lpm_cfg->defip_l3a_rp != BCM_IPMC_RP_ID_INVALID) {
   4803             soc_mem_field32_set(unit, mem, lpm_data, expected_l3_iif[upper], 
   4804                                     _BCM_DEFIP_IPMC_RP_SET(lpm_cfg->defip_l3a_rp));
   4805 
   4806         } else if ((lpm_cfg->defip_ipmc_flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) && 
   4807                 (lpm_cfg->defip_expected_intf != 0))  {
   4808 
   4809             soc_mem_field32_set(unit, mem, lpm_data, expected_l3_iif[upper],
   4810                                       lpm_cfg->defip_expected_intf);
   4811 
   4812             if (lpm_cfg->defip_ipmc_flags & BCM_IPMC_RPF_FAIL_DROP) {
   4813                 soc_mem_field32_set(unit, mem, lpm_data,
   4814                                        ipmc_ext_l3_iifp_mismatch_drop[upper], 1);
   4815             }
   4816             if (lpm_cfg->defip_ipmc_flags & BCM_IPMC_RPF_FAIL_TOCPU) {
   4817                 soc_mem_field32_set(unit, mem, lpm_data,
   4818                                       ipmc_ext_l3_iifp_mismatch_tocpu[upper], 1);
   4819             }
   4820         }
   4821     }
   4822 #endif
   4823 
   4824     return BCM_E_NONE;
   4825 }
   4826 
   4827 
   4828 int
   4829 _bcm_fb_lpm_prepare_defip_entry(int unit, _bcm_defip_cfg_t *lpm_cfg,
   4830                                 int nh_ecmp_idx, uint32 *lpm_entry,
   4831                                 uint32 *lpm_entry_upr)
   4832 {
   4833     soc_mem_t mem = L3_DEFIPm;
   4834     if (NULL == lpm_cfg || NULL == lpm_entry) {
   4835         return BCM_E_PARAM;
   4836     }
   4837 
   4838     if (!SOC_MEM_IS_VALID(unit, L3_DEFIPm)) {
   4839         mem = L3_DEFIP_LEVEL1m;
   4840     }
   4841 #ifdef BCM_TRIDENT3_SUPPORT
   4842     if (soc_feature(unit, soc_feature_flex_flow) &&
   4843         lpm_cfg->defip_flow_handle != 0) {
   4844         BCM_IF_ERROR_RETURN(
   4845             _bcm_td3_lpm_prepare_flex_defip_entry(unit, lpm_cfg,
   4846                                                   nh_ecmp_idx, lpm_entry));
   4847         return BCM_E_NONE;
   4848     }
   4849 #endif
   4850 
   4851 
   4852     /* Set hit bit. */
   4853     if (lpm_cfg->defip_flags & BCM_L3_HIT) {
   4854         soc_mem_field32_set(unit, mem, lpm_entry,
   4855                                 HIT0f, 0x1);
   4856     }
   4857 
   4858     if (!SOC_IS_TOMAHAWK3(unit)) {
   4859         /* Set priority override bit. */
   4860         if (lpm_cfg->defip_flags & BCM_L3_RPE) {
   4861             soc_mem_field32_set(unit, mem, lpm_entry,
   4862                                     RPE0f, 0x1);
   4863         }
   4864         /* Write priority field. */
   4865         soc_L3_DEFIPm_field32_set(unit, lpm_entry, PRI0f, lpm_cfg->defip_prio);
   4866 
   4867         /* Configure entry for SIP lookup if URPF is enabled.
   4868          * For devices like KT2 both DIP and SIP lookup is done
   4869          * using only 1 L3_DEFIP entry, unlike other devices where
   4870          * L3_DEFIP table is divided in 2 parts to support URPF.
   4871          * RPExf and DEFAULTROUTExf are not overlayed in KT2 like previous devices.
   4872          */
   4873         if (soc_feature(unit, soc_feature_l3_defip_advanced_lookup)) {
   4874             soc_mem_field32_set(unit, mem, lpm_entry, DEFAULTROUTE0f,
   4875                 (SOC_URPF_STATUS_GET(unit) ? 1 : 0));
   4876         }
   4877     }
   4878 
   4879     /* Fill next hop information. */
   4880     if (SOC_IS_TRIDENT3X(unit)) {
   4881         /* TRIDENT3 has DESTINATION0 and DESTINATION1 fields */
   4882         if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) {
   4883             soc_mem_field32_dest_set(unit, L3_DEFIPm, lpm_entry, DESTINATION0f, 
   4884                                      SOC_MEM_FIF_DEST_ECMP, nh_ecmp_idx);
   4885         } else if (nh_ecmp_idx != BCM_XGS3_L3_INVALID_INDEX) {
   4886             soc_mem_field32_dest_set(unit, L3_DEFIPm, lpm_entry, DESTINATION0f, 
   4887                                      SOC_MEM_FIF_DEST_NEXTHOP, nh_ecmp_idx);
   4888 
   4889         }
   4890         /* Set destination discard flag. */
   4891         if (lpm_cfg->defip_flags & BCM_L3_DST_DISCARD) {
   4892             if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, DST_DISCARD0f)) {
   4893                 soc_mem_field32_set(unit, mem, lpm_entry, DST_DISCARD0f, 1);
   4894             } else {
   4895                 return (BCM_E_UNAVAIL);
   4896             }
   4897         }
   4898     } else if (!SOC_IS_TOMAHAWK3(unit)){
   4899         if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) {
   4900             soc_L3_DEFIPm_field32_set(unit, lpm_entry, ECMP0f, 1);
   4901             /* NOTE: Order is important set next hop index before ECMP_COUNT.
   4902              * If device doesn't have ECMP_COUNT:  ECMP_PTR field is shorter than
   4903              * next hop -> we must ensure that write resets high bits of next hop
   4904              * field.
   4905              */
   4906             if (nh_ecmp_idx != BCM_XGS3_L3_INVALID_INDEX) {
   4907                 soc_mem_field32_set(unit, mem, lpm_entry, NEXT_HOP_INDEX0f,
   4908                                           nh_ecmp_idx);
   4909             }
   4910             if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, ECMP_COUNT0f)) {
   4911                 soc_mem_field32_set(unit, mem, lpm_entry, ECMP_COUNT0f,
   4912                                           lpm_cfg->defip_ecmp_count);
   4913             }
   4914         } else {
   4915             if (nh_ecmp_idx != BCM_XGS3_L3_INVALID_INDEX) {
   4916                 soc_mem_field32_set(unit, mem, lpm_entry, NEXT_HOP_INDEX0f,
   4917                                           nh_ecmp_idx);
   4918             }
   4919         }
   4920 
   4921         /* Set destination discard flag. */
   4922         if (lpm_cfg->defip_flags & BCM_L3_DST_DISCARD) {
   4923             if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, DST_DISCARD0f)) {
   4924                 soc_mem_field32_set(unit, mem, lpm_entry, DST_DISCARD0f, 1);
   4925             } else {
   4926                 return (BCM_E_UNAVAIL);
   4927             }
   4928         }
   4929     }
   4930 
   4931 #if defined(BCM_TRX_SUPPORT)
   4932     if (!SOC_IS_TOMAHAWK3(unit)) {
   4933         /* Set classification group id. */
   4934         if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, CLASS_ID0f)) {
   4935             soc_mem_field32_set(unit, mem, lpm_entry, CLASS_ID0f,
   4936                                       lpm_cfg->defip_lookup_class);
   4937         }
   4938 
   4939         /* Set Global route flag. */
   4940         if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, GLOBAL_ROUTE0f)) {
   4941             if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) {
   4942                 soc_mem_field32_set(unit, mem, lpm_entry,
   4943                                     GLOBAL_ROUTE0f, 0x1);
   4944             }
   4945         }
   4946     }
   4947 #endif /* BCM_TRX_SUPPORT */
   4948 
   4949 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   4950     if (soc_feature(unit, soc_feature_ipmc_defip) &&
   4951             (lpm_cfg->defip_flags & BCM_L3_IPMC) && !(SOC_IS_TOMAHAWK3(unit))) {
   4952         if (soc_mem_field_valid(unit, L3_DEFIPm, MULTICAST_ROUTE0f)) {
   4953             soc_L3_DEFIPm_field32_set(unit, lpm_entry, MULTICAST_ROUTE0f, 1);
   4954         } else if (soc_mem_field_valid(unit, L3_DEFIPm, DATA_TYPE0f)) {
   4955             soc_L3_DEFIPm_field32_set(unit, lpm_entry, DATA_TYPE0f, 2);
   4956         }
   4957 
   4958         if (soc_feature(unit, soc_feature_generic_dest)) {
   4959             if (lpm_cfg->defip_mc_group > 0) {
   4960                 soc_mem_field32_dest_set(unit, L3_DEFIPm, lpm_entry, DESTINATION0f,
   4961                     SOC_MEM_FIF_DEST_IPMC, lpm_cfg->defip_mc_group);
   4962             }
   4963         } else {
   4964             soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, L3MC_INDEX0f, lpm_cfg->defip_mc_group);
   4965         }
   4966 
   4967         /*
   4968          * RP ID needs uplift by _BCM_L3_DEFIP_RP_ID_BASE value, Now it wil fit in EXPECTED_L3_IIFf
   4969          */
   4970         if (lpm_cfg->defip_l3a_rp != BCM_IPMC_RP_ID_INVALID) {
   4971             soc_mem_field32_set(unit, mem, lpm_entry, EXPECTED_L3_IIF0f,
   4972                                     _BCM_DEFIP_IPMC_RP_SET(lpm_cfg->defip_l3a_rp));
   4973 
   4974         } else if ((lpm_cfg->defip_ipmc_flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) && 
   4975                 (lpm_cfg->defip_expected_intf != 0))  {
   4976 
   4977             soc_mem_field32_set(unit, mem, lpm_entry, EXPECTED_L3_IIF0f, lpm_cfg->defip_expected_intf);
   4978 
   4979             if (lpm_cfg->defip_ipmc_flags & BCM_IPMC_RPF_FAIL_DROP) {
   4980                 soc_mem_field32_set(unit, mem, lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_DROP0f, 1);
   4981             }
   4982             if (lpm_cfg->defip_ipmc_flags & BCM_IPMC_RPF_FAIL_TOCPU) {
   4983                 soc_mem_field32_set(unit, mem, lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPU0f, 1);
   4984             }
   4985         }
   4986     }
   4987 #endif
   4988 
   4989 #if defined(BCM_TRIDENT2_SUPPORT)
   4990 #if defined(BCM_TOMAHAWK3_SUPPORT)
   4991     if (SOC_IS_TOMAHAWK3(unit)) {
   4992         uint32          fmte[4];
   4993         sal_memset(fmte, 0, sizeof(fmte));
   4994         if (lpm_cfg->defip_flags & BCM_L3_RPE) {
   4995             soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, RPEf, 1);
   4996         }
   4997         soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, PRIf, lpm_cfg->defip_prio);
   4998         soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, CLASS_IDf,
   4999                                       lpm_cfg->defip_lookup_class);
   5000         soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, DESTINATIONf, nh_ecmp_idx);
   5001 
   5002         if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) {
   5003             soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, DEST_TYPEf, 1);
   5004         } else if (nh_ecmp_idx != BCM_XGS3_L3_INVALID_INDEX) {
   5005             soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, DEST_TYPEf, 0);
   5006         }
   5007 
   5008         if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
   5009             soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, FLEX_CTR_OFFSET_MODEf,
   5010                                       lpm_cfg->defip_flex_ctr_mode);
   5011             soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, FLEX_CTR_POOL_NUMBERf,
   5012                                       lpm_cfg->defip_flex_ctr_pool);
   5013             soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, FLEX_CTR_BASE_COUNTER_IDXf,
   5014                                       lpm_cfg->defip_flex_ctr_base_id);
   5015         }
   5016 
   5017         /* Set destination discard flag. */
   5018         if (lpm_cfg->defip_flags & BCM_L3_DST_DISCARD) {
   5019              soc_format_field32_set(unit, ASSOC_DATA_FULLfmt, fmte, DST_DISCARDf, 1);
   5020         }
   5021 
   5022         soc_mem_field_set(unit, mem, lpm_entry, ASSOC_DATA0f, fmte);
   5023         sal_memset(fmte, 0, sizeof(fmte));
   5024         soc_format_field32_set(unit, ALPM1_DATAfmt, fmte, DIRECT_ROUTEf, 1);
   5025         soc_mem_field_set(unit, mem, lpm_entry, ALPM1_DATA0f, fmte);
   5026 
   5027         sal_memset(fmte, 0, sizeof(fmte));
   5028         if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) {
   5029             soc_format_field32_set(unit, FIXED_DATAfmt, fmte, SUB_DB_PRIORITYf, 2);
   5030         } else if (BCM_L3_VRF_OVERRIDE == lpm_cfg->defip_vrf) {
   5031             soc_format_field32_set(unit, FIXED_DATAfmt, fmte, SUB_DB_PRIORITYf, 0);
   5032         } else {
   5033             soc_format_field32_set(unit, FIXED_DATAfmt, fmte, SUB_DB_PRIORITYf, 1);
   5034         }
   5035         soc_mem_field_set(unit, mem, lpm_entry, FIXED_DATA0f, fmte);
   5036 
   5037     } else if (soc_feature(unit,soc_feature_advanced_flex_counter))
   5038 #endif
   5039     {
   5040         if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, FLEX_CTR_OFFSET_MODE0f)) {
   5041             soc_mem_field32_set(unit, mem, lpm_entry, FLEX_CTR_OFFSET_MODE0f,
   5042                                       lpm_cfg->defip_flex_ctr_mode);
   5043             soc_mem_field32_set(unit, mem, lpm_entry, FLEX_CTR_POOL_NUMBER0f,
   5044                                       lpm_cfg->defip_flex_ctr_pool);
   5045             soc_mem_field32_set(unit, mem, lpm_entry, FLEX_CTR_BASE_COUNTER_IDX0f,
   5046                                       lpm_cfg->defip_flex_ctr_base_id);
   5047         }
   5048     }
   5049 #endif
   5050 
   5051     /*
   5052      * Note ipv4 entries are expected to reside in part 0 of the entry.
   5053      *      ipv6 entries both parts should be filled.
   5054      *      Hence if entry is ipv6 copy part 0 to part 1
   5055      */
   5056     if (lpm_cfg->defip_flags & BCM_L3_IP6) {
   5057         soc_fb_lpm_ip4entry0_to_1(unit, lpm_entry, lpm_entry, TRUE);
   5058         if (lpm_entry_upr != NULL) {
   5059             sal_memcpy(lpm_entry_upr, lpm_entry,
   5060                        BCM_XGS3_L3_ENT_SZ(unit, defip));
   5061         }
   5062     }
   5063 
   5064     /*
   5065      * Initialize hw buffer from lpm configuration.
   5066      * NOTE: DON'T MOVE _bcm_fb_defip_ent_init CALL UP,
   5067      * We want to copy flags & nh info, avoid  ipv6 mask & address corruption.
   5068      */
   5069     BCM_IF_ERROR_RETURN(_bcm_fb_lpm_ent_init(unit, lpm_cfg, lpm_entry));
   5070 
   5071     if (NULL == lpm_entry_upr) {
   5072         /* lpm_entry_upr should not be null only in case of 128b entries */
   5073         return BCM_E_NONE;
   5074     }
   5075 
   5076     return _bcm_fb_lpm_upr_ent_init(unit, lpm_cfg, lpm_entry_upr);
   5077 
   5078 }
   5079 
   5080 int
   5081 _bcm_fb_lpm128_add(int unit, _bcm_defip_cfg_t *lpm_cfg, int nh_ecmp_idx)
   5082 {
   5083     uint32 hw_entry_lwr[SOC_MAX_MEM_WORDS];
   5084     uint32 hw_entry_upr[SOC_MAX_MEM_WORDS];
   5085     int hw_index = 0;                           /* Entry offset in the TCAM. */
   5086     int rv = BCM_E_NONE;                        /* Operation return status.  */
   5087     int ipv6 = 1;
   5088 
   5089 
   5090     /* Input parameters check. */
   5091     if (lpm_cfg == NULL) {
   5092         return (BCM_E_PARAM);
   5093     }
   5094     /*
   5095      * No support for routes matching AFTER vrf specific.
   5096      * By not allowing VRF_GLOBAL for 128-V6 routes,
   5097      * we make sure that 64-V6 private entries dont get
   5098      * priotized over 128-V6 public/global entries.
   5099      */
   5100     if ((BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) &&
   5101         (lpm_cfg->defip_sub_len > 64)) {
   5102         return (BCM_E_UNAVAIL);
   5103     }
   5104 
   5105     sal_memset(hw_entry_lwr, 0x0, BCM_XGS3_L3_ENT_SZ(unit, defip));
   5106 
   5107     if (!(lpm_cfg->defip_flags & BCM_L3_IP6)) {
   5108        ipv6 = 0;
   5109     }
   5110 
   5111     if (ipv6) {
   5112         sal_memset(hw_entry_upr, 0x0, BCM_XGS3_L3_ENT_SZ(unit, defip));
   5113         lpm_cfg->defip_flags_high |= BCM_XGS3_L3_ENTRY_IN_DEFIP_PAIR;
   5114         _bcm_fb_lpm_prepare_defip_entry(unit, lpm_cfg, nh_ecmp_idx,
   5115                                         hw_entry_lwr,
   5116                                         hw_entry_upr);
   5117     } else {
   5118         _bcm_fb_lpm_prepare_defip_entry(unit, lpm_cfg, nh_ecmp_idx,
   5119                                         hw_entry_lwr,
   5120                                         NULL);
   5121     }
   5122 
   5123     if (ipv6) {
   5124         rv = soc_fb_lpm128_insert(unit, hw_entry_lwr, hw_entry_upr, &hw_index);
   5125     } else {
   5126         rv = soc_fb_lpm128_insert(unit, hw_entry_lwr, NULL, &hw_index);
   5127    }
   5128     /* Lack of index indicates a new route. */
   5129     if (BCM_SUCCESS(rv) && BCM_XGS3_L3_INVALID_INDEX == lpm_cfg->defip_index) {
   5130         BCM_XGS3_L3_DEFIP_CNT_INC(unit, ipv6);
   5131         lpm_cfg->defip_flags_high |= BCM_XGS3_L3_ENTRY_IN_DEFIP_PAIR;
   5132     }
   5133 
   5134     return rv;
   5135 }
   5136 
   5137 /*
   5138  * Function:
   5139  *      _bcm_fb_lpm_clear_hit
   5140  * Purpose:
   5141  *      Clear prefix entry hit bit.
   5142  * Parameters:
   5143  *      unit      - (IN)SOC unit number.
   5144  *      lpm_cfg   - (IN)Route info.
   5145  *      lpm_entry - (IN)Buffer to write to hw.
   5146  * Returns:
   5147  *      BCM_E_XXX
   5148  */
   5149 STATIC int
   5150 _bcm_fb_lpm_clear_hit(int unit, _bcm_defip_cfg_t *lpm_cfg,
   5151                       uint32 *lpm_entry)
   5152 {
   5153     int rv;                        /* Operation return status. */
   5154     int tbl_idx;                   /* Defip table index.       */
   5155     defip_hit_only_entry_t lpm_hit_entry;
   5156                                    /* LPM Hit Only Entry       */
   5157     int defip_hit_size = 0;        /* LPM Hit Only Entry Size  */
   5158     soc_field_t hit_field = HIT0f; /* HIT bit field id.        */
   5159 
   5160     /* Input parameters check */
   5161     if ((NULL == lpm_cfg) || (NULL == lpm_entry)) {
   5162         return (BCM_E_PARAM);
   5163     }
   5164 
   5165     /* If entry was not hit  clear "clear hit" and return */
   5166     if (!(lpm_cfg->defip_flags & BCM_L3_HIT)) {
   5167         return (BCM_E_NONE);
   5168     }
   5169 
   5170     if (soc_feature(unit, soc_feature_lpm_atomic_write)) {
   5171         /* Use only HIT ONLY VIEW to write entry */
   5172 
   5173         defip_hit_size = sizeof(defip_hit_only_entry_t);
   5174         sal_memset(&lpm_hit_entry, 0, defip_hit_size);
   5175 
   5176         if (lpm_cfg->defip_flags & BCM_L3_IP6) {
   5177             tbl_idx = lpm_cfg->defip_index;
   5178         } else {
   5179             tbl_idx = lpm_cfg->defip_index >> 1;
   5180         }
   5181 
   5182         BCM_IF_ERROR_RETURN(READ_L3_DEFIP_HIT_ONLYm(unit,
   5183                                 MEM_BLOCK_ALL, tbl_idx, &lpm_hit_entry));
   5184         /* Reset entry hit bit in buffer. */
   5185         if (lpm_cfg->defip_flags & BCM_L3_IP6) {
   5186             soc_L3_DEFIP_HIT_ONLYm_field32_set(unit, &lpm_hit_entry, HIT1f, 0);
   5187         } else {
   5188             if (lpm_cfg->defip_index & 0x1) {
   5189                 hit_field = HIT1f;
   5190             }
   5191         }
   5192         soc_L3_DEFIP_HIT_ONLYm_field32_set(unit, &lpm_hit_entry, hit_field, 0);
   5193 
   5194         rv = BCM_XGS3_MEM_WRITE(unit, L3_DEFIP_HIT_ONLYm, tbl_idx, &lpm_hit_entry);
   5195     } else {
   5196         /* Reset entry hit bit in buffer. */
   5197         if (lpm_cfg->defip_flags & BCM_L3_IP6) {
   5198             tbl_idx = lpm_cfg->defip_index;
   5199             soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, HIT1f, 0);
   5200         } else {
   5201             tbl_idx = lpm_cfg->defip_index >> 1;
   5202             if (SOC_MEM_IS_VALID(unit, L3_DEFIPm)) {
   5203                 rv = READ_L3_DEFIPm(unit, MEM_BLOCK_ALL, tbl_idx, lpm_entry);
   5204             } else {
   5205                 rv = READ_L3_DEFIP_LEVEL1m(unit, MEM_BLOCK_ALL, tbl_idx, lpm_entry);
   5206             }
   5207             if (lpm_cfg->defip_index & 0x1) {
   5208                 hit_field = HIT1f;
   5209             }
   5210         }
   5211         soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, hit_field, 0);
   5212 
   5213         /* Write lpm buffer to hardware. */
   5214         rv = BCM_XGS3_MEM_WRITE(unit, BCM_XGS3_L3_MEM(unit, defip), tbl_idx, lpm_entry);
   5215     }
   5216     return rv;
   5217 }
   5218 
   5219 int _bcm_fb_lpm128_get(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx)
   5220 {
   5221     uint32 lpm_key[SOC_MAX_MEM_WORDS];      /* Route lookup key.        */
   5222     uint32 lpm_key_upr[SOC_MAX_MEM_WORDS];      /* Route lookup key.        */
   5223     uint32 lpm_entry[SOC_MAX_MEM_WORDS];    /* Search result buffer.    */
   5224     uint32 lpm_entry_upr[SOC_MAX_MEM_WORDS];    /* Search result buffer.    */
   5225     int clear_hit;              /* Clear hit indicator.     */
   5226     int rv;                     /* Operation return status. */
   5227     int pfx;
   5228     int ipv6 = 1;
   5229 
   5230     /* Input parameters check */
   5231     if (NULL == lpm_cfg) {
   5232         return (BCM_E_PARAM);
   5233     }
   5234 
   5235 
   5236     if (!(lpm_cfg->defip_flags & BCM_L3_IP6)) {
   5237        ipv6 = 0;
   5238     }
   5239 
   5240     /* Zero buffers. */
   5241     sal_memset(lpm_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, defip));
   5242     sal_memset(lpm_key, 0, BCM_XGS3_L3_ENT_SZ(unit, defip));
   5243 
   5244     if (ipv6) {
   5245         sal_memset(lpm_key_upr, 0, BCM_XGS3_L3_ENT_SZ(unit, defip));
   5246         sal_memset(lpm_entry_upr, 0, BCM_XGS3_L3_ENT_SZ(unit, defip));
   5247         lpm_cfg->defip_flags_high |= BCM_XGS3_L3_ENTRY_IN_DEFIP_PAIR;
   5248     }
   5249     /* Check if clear hit bit required. */
   5250     clear_hit = lpm_cfg->defip_flags & BCM_L3_HIT_CLEAR;
   5251 
   5252     /* Initialize lkup key. */
   5253     BCM_IF_ERROR_RETURN(_bcm_fb_lpm_ent_init(unit, lpm_cfg, (uint32 *)lpm_key));
   5254     if (ipv6) {
   5255         BCM_IF_ERROR_RETURN(_bcm_fb_lpm_upr_ent_init(unit, lpm_cfg,
   5256                                                      (uint32 *)lpm_key_upr));
   5257         /* Perform hw lookup. */
   5258         rv = soc_fb_lpm128_match(unit, (uint32 *)lpm_key, (uint32 *)lpm_key_upr, (uint32 *)lpm_entry,
   5259                               (uint32 *)lpm_entry_upr, &lpm_cfg->defip_index, &pfx, NULL);
   5260     } else {
   5261         /* Perform hw lookup. */
   5262         rv = soc_fb_lpm128_match(unit, (uint32 *)lpm_key, NULL, (uint32 *)lpm_entry,
   5263                                  NULL, &lpm_cfg->defip_index, &pfx, NULL);
   5264     }
   5265 
   5266     BCM_IF_ERROR_RETURN(rv);
   5267 
   5268     /* Found the entry in paired tcam */
   5269     lpm_cfg->defip_flags_high |= BCM_XGS3_L3_ENTRY_IN_DEFIP_PAIR;
   5270 
   5271     /*
   5272      * If entry is ipv4 we always operate on entry in "zero" half of the
   5273      * buffer. copy "one" half to "zero" half of lpm_entry, if  entry is found
   5274      * at "one" half.
   5275      */
   5276     if ((!(lpm_cfg->defip_flags & BCM_L3_IP6)) && (lpm_cfg->defip_index & 0x1)) {
   5277         soc_fb_lpm_ip4entry1_to_0(unit, &lpm_entry, &lpm_entry, TRUE);
   5278     }
   5279 
   5280 #ifdef BCM_TRIDENT_SUPPORT
   5281     if (!(SOC_IS_TOMAHAWK3(unit)) && (SOC_IS_TD_TT(unit) || SOC_IS_TD2_TT2(unit))) {
   5282         uint32 i, hit;
   5283         defip_hit_only_entry_t hit_entry[2];
   5284         soc_mem_t hit_mem[] = {L3_DEFIP_HIT_ONLY_Xm, L3_DEFIP_HIT_ONLY_Ym};
   5285         int hit_mem_cnt = 2;
   5286 
   5287         if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_APACHE(unit) || SOC_IS_TRIDENT3X(unit)) {
   5288             hit_mem[0] = L3_DEFIP_HIT_ONLYm;
   5289             hit_mem_cnt = 1;
   5290         }
   5291 
   5292         if (lpm_cfg->defip_flags & BCM_L3_IP6) {
   5293             for (i = 0, hit = 0; i < hit_mem_cnt; i++) {
   5294                 BCM_IF_ERROR_RETURN
   5295                     (BCM_XGS3_MEM_READ(unit, hit_mem[i],
   5296                                        lpm_cfg->defip_index, &hit_entry[i]));
   5297                 hit |= soc_mem_field32_get(unit, hit_mem[i],
   5298                                           &hit_entry[i], HIT0f);
   5299             }
   5300             soc_mem_field32_set(unit, L3_DEFIPm, &lpm_entry, HIT0f, hit);
   5301             for (i = 0, hit = 0; i < hit_mem_cnt; i++) {
   5302                 hit |= soc_mem_field32_get(unit, hit_mem[i],
   5303                                            &hit_entry[i], HIT1f);
   5304             }            
   5305             soc_mem_field32_set(unit, L3_DEFIPm, &lpm_entry, HIT1f, hit);
   5306         } else {
   5307             for (i = 0, hit = 0; i < hit_mem_cnt; i++) {
   5308                 BCM_IF_ERROR_RETURN
   5309                     (BCM_XGS3_MEM_READ(unit, hit_mem[i],
   5310                                        lpm_cfg->defip_index >> 1, &hit_entry[i]));
   5311                 hit |= soc_mem_field32_get(unit, hit_mem[i], &hit_entry[i],
   5312                                            lpm_cfg->defip_index & 0x1 ?
   5313                                            HIT1f : HIT0f);
   5314             }
   5315             soc_mem_field32_set(unit, L3_DEFIPm, &lpm_entry, HIT0f, hit);
   5316         }
   5317     }
   5318 #endif /* BCM_TRIDENT_SUPPORT */
   5319 
   5320     /* Parse hw buffer to defip entry. */
   5321     BCM_IF_ERROR_RETURN(
   5322         _bcm_fb_lpm_ent_parse(unit, lpm_cfg, nh_ecmp_idx, (uint32 *)lpm_entry, NULL));
   5323 
   5324     /* Clear the HIT bit */
   5325     if (clear_hit) {
   5326         BCM_IF_ERROR_RETURN(_bcm_fb_lpm_clear_hit(unit, lpm_cfg, (uint32 *)lpm_entry));
   5327     }
   5328 
   5329     return BCM_E_NONE;
   5330 }
   5331 
   5332 int
   5333 _bcm_fb_lpm128_del(int unit, _bcm_defip_cfg_t *lpm_cfg)
   5334 {
   5335 
   5336     int rv;                     /* Operation return status. */
   5337     uint32 lpm_entry[SOC_MAX_MEM_WORDS];  /* Search result buffer.    */
   5338     uint32 lpm_entry_upr[SOC_MAX_MEM_WORDS]; /* Search result buffer.    */
   5339     int ipv6 = 1;
   5340 
   5341     /* Input parameters check */
   5342     if (NULL == lpm_cfg) {
   5343         return (BCM_E_PARAM);
   5344     }
   5345 
   5346     lpm_cfg->defip_flags_high |= BCM_XGS3_L3_ENTRY_IN_DEFIP_PAIR;
   5347 
   5348     if (!(lpm_cfg->defip_flags & BCM_L3_IP6)) {
   5349        ipv6 = 0;
   5350     }
   5351 
   5352     /* Zero buffers. */
   5353     sal_memset(lpm_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, defip));
   5354     /* Initialize hw buffer deletion key. */
   5355     BCM_IF_ERROR_RETURN(_bcm_fb_lpm_ent_init(unit, lpm_cfg, lpm_entry));
   5356     if (ipv6) {
   5357         sal_memset(&lpm_entry_upr, 0, BCM_XGS3_L3_ENT_SZ(unit, defip));
   5358         BCM_IF_ERROR_RETURN(_bcm_fb_lpm_upr_ent_init(unit, lpm_cfg,
   5359                                                  lpm_entry_upr));
   5360     }
   5361 
   5362     /* Write buffer to hw. */
   5363     if (ipv6) {
   5364         rv = soc_fb_lpm128_delete(unit, lpm_entry, lpm_entry_upr);
   5365     } else {
   5366         rv = soc_fb_lpm128_delete(unit, lpm_entry, NULL);
   5367     }
   5368     /* If  route delete, then decrement total number of routes.  */
   5369     if (rv >= 0) {
   5370         BCM_XGS3_L3_DEFIP_CNT_DEC(unit, ipv6);
   5371     }
   5372     return rv;
   5373 }
   5374 
   5375 /*
   5376  * Function:
   5377  *     _bcm_fb_mem_ip6_defip_get
   5378  * Purpose:
   5379  *    Set an IP6 address field in L3_DEFIPm
   5380  * Note:
   5381  *    See soc_mem_ip6_addr_set()
   5382  */
   5383 STATIC void
   5384 _bcm_fb_mem_ip6_defip_get(int unit, const void *lpm_key,
   5385                           _bcm_defip_cfg_t *lpm_cfg)
   5386 {
   5387     uint8 *ip6;                 /* Ip6 address.       */
   5388     uint8 mask[BCM_IP6_ADDRLEN];        /* Subnet mask.       */
   5389     uint32 ip6_word;            /* Temp storage.      */
   5390 
   5391     sal_memset(mask, 0, sizeof (bcm_ip6_t));
   5392 
   5393     /* Just to keep variable name short. */
   5394     ip6 = lpm_cfg->defip_ip6_addr;
   5395     sal_memset(ip6, 0, sizeof (bcm_ip6_t));
   5396 
   5397     if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) {
   5398         uint32 _key_data[2] = {0, 0};
   5399 
   5400         soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key, KEY1f, _key_data);
   5401         ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf);
   5402         ip6[0] = (uint8) ((ip6_word >> 24) & 0xff);
   5403         ip6[1] = (uint8) ((ip6_word >> 16) & 0xff);
   5404         ip6[2] = (uint8) ((ip6_word >> 8) & 0xff);
   5405         ip6[3] = (uint8) (ip6_word & 0xff);
   5406 
   5407         soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key, KEY0f, _key_data);
   5408         ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf);
   5409         ip6[4] = (uint8) ((ip6_word >> 24) & 0xff);
   5410         ip6[5] = (uint8) ((ip6_word >> 16) & 0xff);
   5411         ip6[6] = (uint8) ((ip6_word >> 8) & 0xff);
   5412         ip6[7] = (uint8) (ip6_word & 0xff);
   5413 
   5414         soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key, MASK1f, _key_data);
   5415         ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf);
   5416         mask[0] = (uint8) ((ip6_word >> 24) & 0xff);
   5417         mask[1] = (uint8) ((ip6_word >> 16) & 0xff);
   5418         mask[2] = (uint8) ((ip6_word >> 8) & 0xff);
   5419         mask[3] = (uint8) (ip6_word & 0xff);
   5420 
   5421         soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, (void *)lpm_key, MASK0f, _key_data);
   5422         ip6_word = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf);
   5423         mask[4] = (uint8) ((ip6_word >> 24) & 0xff);
   5424         mask[5] = (uint8) ((ip6_word >> 16) & 0xff);
   5425         mask[6] = (uint8) ((ip6_word >> 8) & 0xff);
   5426         mask[7] = (uint8) (ip6_word & 0xff);
   5427 
   5428         lpm_cfg->defip_sub_len = bcm_ip6_mask_length(mask);
   5429         return;
   5430     }
   5431 
   5432     soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR1f, &ip6_word);
   5433     ip6[0] = (uint8) ((ip6_word >> 24) & 0xff);
   5434     ip6[1] = (uint8) ((ip6_word >> 16) & 0xff);
   5435     ip6[2] = (uint8) ((ip6_word >> 8) & 0xff);
   5436     ip6[3] = (uint8) (ip6_word & 0xff);
   5437 
   5438     soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR0f, &ip6_word);
   5439     ip6[4] = (uint8) ((ip6_word >> 24) & 0xff);
   5440     ip6[5] = (uint8) ((ip6_word >> 16) & 0xff);
   5441     ip6[6] = (uint8) ((ip6_word >> 8) & 0xff);
   5442     ip6[7] = (uint8) (ip6_word & 0xff);
   5443 
   5444     soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_MASK1f, &ip6_word);
   5445     mask[0] = (uint8) ((ip6_word >> 24) & 0xff);
   5446     mask[1] = (uint8) ((ip6_word >> 16) & 0xff);
   5447     mask[2] = (uint8) ((ip6_word >> 8) & 0xff);
   5448     mask[3] = (uint8) (ip6_word & 0xff);
   5449 
   5450     soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_MASK0f, &ip6_word);
   5451     mask[4] = (uint8) ((ip6_word >> 24) & 0xff);
   5452     mask[5] = (uint8) ((ip6_word >> 16) & 0xff);
   5453     mask[6] = (uint8) ((ip6_word >> 8) & 0xff);
   5454     mask[7] = (uint8) (ip6_word & 0xff);
   5455 
   5456     lpm_cfg->defip_sub_len = bcm_ip6_mask_length(mask);
   5457 }
   5458 
   5459 
   5460 STATIC int
   5461 _bcm_th3_lpm_ent_get_key(int unit, _bcm_defip_cfg_t *lpm_cfg,
   5462                         uint32 *lpm_entry)
   5463 {
   5464     uint32          _key_data[2];
   5465     bcm_ip_t v4_mask;
   5466     int ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6;
   5467 
   5468     sal_memset(_key_data, 0, sizeof(_key_data));
   5469 
   5470     soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, lpm_entry, KEY0f, _key_data);
   5471 
   5472     if (ipv6) {
   5473         _bcm_fb_mem_ip6_defip_get(unit, lpm_entry, lpm_cfg);
   5474         /* Get Virtual Router id */
   5475         soc_fb_lpm_vrf_get(unit, lpm_entry, &lpm_cfg->defip_vrf);
   5476     } else {
   5477         lpm_cfg->defip_ip_addr = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf);
   5478         lpm_cfg->defip_entry_type = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf);
   5479         /* Get Virtual Router id */
   5480         soc_fb_lpm_vrf_get(unit, lpm_entry, &lpm_cfg->defip_vrf);
   5481         /* Get subnet mask. */
   5482         soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, lpm_entry, MASK0f, _key_data);
   5483         v4_mask = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf);
   5484 
   5485         /* Fill mask length. */
   5486         lpm_cfg->defip_sub_len = bcm_ip_mask_length(v4_mask);
   5487     }
   5488     return (BCM_E_NONE);
   5489 }
   5490 
   5491 /*
   5492  * Function:
   5493  *      _bcm_fb_lpm_ent_get_key
   5494  * Purpose:
   5495  *      Parse entry key from DEFIP table.
   5496  * Parameters:
   5497  *      unit        - (IN)SOC unit number.
   5498  *      lpm_cfg     - (OUT)Buffer to fill defip information.
   5499  *      lpm_entry   - (IN) Buffer read from hw.
   5500  * Returns:
   5501  *      void
   5502  */
   5503 STATIC int
   5504 _bcm_fb_lpm_ent_get_key(int unit, _bcm_defip_cfg_t *lpm_cfg,
   5505                         uint32 *lpm_entry)
   5506 {
   5507 
   5508     bcm_ip_t v4_mask;
   5509     int ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6;
   5510 
   5511 #ifdef BCM_TRIDENT3_SUPPORT
   5512     if (soc_feature(unit, soc_feature_flex_flow)) {
   5513         uint32 key_type;
   5514 
   5515         key_type = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, KEY_TYPE0f);
   5516 
   5517         if (BCMI_LPM_FLEX_VIEW(key_type)) {
   5518             return _bcm_td3_lpm_flex_ent_get_key(unit, lpm_cfg, lpm_entry, key_type);
   5519         }
   5520     }
   5521 #endif
   5522 
   5523     if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) {
   5524         return _bcm_th3_lpm_ent_get_key(unit, lpm_cfg, lpm_entry);
   5525     }
   5526     /* Set prefix ip address & mask. */
   5527     if (ipv6) {
   5528         _bcm_fb_mem_ip6_defip_get(unit, lpm_entry, lpm_cfg);
   5529     } else {
   5530         /* Get ipv4 address. */
   5531         lpm_cfg->defip_ip_addr =
   5532             soc_L3_DEFIPm_field32_get(unit, lpm_entry, IP_ADDR0f);
   5533 
   5534         /* Get subnet mask. */
   5535         v4_mask = soc_L3_DEFIPm_field32_get(unit, lpm_entry, IP_ADDR_MASK0f);
   5536 
   5537         /* Fill mask length. */
   5538         lpm_cfg->defip_sub_len = bcm_ip_mask_length(v4_mask);
   5539     }
   5540 
   5541     /* Get Virtual Router id */
   5542     soc_fb_lpm_vrf_get(unit, lpm_entry, &lpm_cfg->defip_vrf);
   5543 
   5544     return (BCM_E_NONE);
   5545 }
   5546 
   5547 /*
   5548  * Function:
   5549  *      _bcm_fb_lpm128_update_match
   5550  * Purpose:
   5551  *      Update/Delete all entries in defip table matching a certain rule.
   5552  * Parameters:
   5553  *      unit     - (IN)SOC unit number.
   5554  *      trv_data - (IN)Delete pattern + compare,act,notify routines.
   5555  * Returns:
   5556  *      BCM_E_XXX
   5557  */
   5558 int
   5559 _bcm_fb_lpm128_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data)
   5560 {
   5561     uint32 ipv6 = 0;            /* Iterate over ipv6 only flag. */
   5562     int idx;                    /* Iteration index.             */
   5563     int tmp_idx;                /* ipv4 entries iterator.       */
   5564     char *lpm_tbl_ptr = NULL;   /* Dma table pointer.           */
   5565     int nh_ecmp_idx;            /* Next hop/Ecmp group index.   */
   5566     int cmp_result;             /* Test routine result.         */
   5567     uint32 *lpm_entry = NULL;   /* Hw entry buffer.             */
   5568     uint32 *lpm_entry_upr = NULL;   /* Hw entry buffer.             */
   5569     _bcm_defip_cfg_t lpm_cfg;   /* Buffer to fill route info.   */
   5570     int defip_table_size;       /* Defip table size.            */
   5571     int rv = BCM_E_NONE;        /* Operation return status.     */
   5572     int idx_start = 0;
   5573     int idx_end = 0;
   5574 #ifdef BCM_TRIDENT_SUPPORT
   5575     char *lpm_hit_only_tbl_ptr[2] = { NULL }; /* Dma table pointer. */
   5576     int tbl_entry_sz;
   5577 #endif /* BCM_TRIDENT_SUPPORT */
   5578     int tcam_depth = SOC_L3_DEFIP_TCAM_DEPTH_GET(unit);
   5579     int tcam_pair_count = 0;
   5580     int b128 = 0;
   5581     int tcam_number;
   5582     int read_reverse = 0;
   5583     uint32 lpm_entry_tmp[SOC_MAX_MEM_WORDS];
   5584 #ifdef BCM_WARM_BOOT_SUPPORT
   5585     int need_reinit = 0;
   5586 #endif
   5587 
   5588     if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   5589         return BCM_E_UNAVAIL;
   5590     }
   5591 
   5592     ipv6 = (trv_data->flags & BCM_L3_IP6);
   5593     read_reverse = (trv_data->flags & BCM_XGS3_L3_OP_GET_REVERSE);
   5594     SOC_IF_ERROR_RETURN(soc_fb_lpm_tcam_pair_count_get(unit, &tcam_pair_count));
   5595 
   5596     /* If soc_feature_l3_defip_advanced_lookup is TRUE then
   5597      * both DIP and SIP lookup is done using only 1 L3_DEFIP entry.
   5598      * L3_DEFIP table is not divided into 2 to support URPF (For ex: Katana2).
   5599      */
   5600     if (SOC_URPF_STATUS_GET(unit) &&
   5601         !soc_feature(unit, soc_feature_l3_defip_advanced_lookup)) {
   5602         switch(tcam_pair_count) {
   5603             case 1:
   5604             case 2:
   5605                 defip_table_size = 2 * tcam_depth;
   5606                 break;
   5607             case 3:
   5608             case 4:
   5609                 defip_table_size = 4 * tcam_depth;
   5610                 break;
   5611             case 5:
   5612             case 6:
   5613                 defip_table_size = 6 * tcam_depth;
   5614                 break;
   5615             case 7:
   5616             case 8:
   5617                 defip_table_size = 8 * tcam_depth;
   5618                 break;
   5619             default:
   5620                 defip_table_size = 0;
   5621                break;
   5622         }
   5623     } else {
   5624         defip_table_size = (tcam_pair_count * tcam_depth * 2);
   5625     }
   5626 
   5627     if (!defip_table_size) {
   5628         return BCM_E_NONE;
   5629     }
   5630     /* Table DMA the LPM table to software copy */
   5631     rv = bcm_xgs3_l3_tbl_range_dma(unit, BCM_XGS3_L3_MEM(unit, defip),
   5632                              BCM_XGS3_L3_ENT_SZ(unit, defip), "lpm_tbl",
   5633                              0, defip_table_size - 1,
   5634                              &lpm_tbl_ptr);
   5635     if (rv < 0) {
   5636         goto free_table;
   5637     }
   5638 
   5639     idx_start = 0;
   5640     idx_end = defip_table_size;
   5641 
   5642     /* Table DMA the HIT table to software copy */
   5643 #ifdef BCM_TRIDENT_SUPPORT
   5644     if (SOC_IS_TD_TT(unit) && !(SOC_IS_TOMAHAWK3(unit))) {
   5645         if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_APACHE(unit) || SOC_IS_TRIDENT3X(unit)) {
   5646             tbl_entry_sz = WORDS2BYTES(soc_mem_entry_words(unit,
   5647                                L3_DEFIP_HIT_ONLYm));
   5648             rv = bcm_xgs3_l3_tbl_range_dma(unit, 
   5649                                            L3_DEFIP_HIT_ONLYm,
   5650                                            tbl_entry_sz,
   5651                                            "lpm_hit_only_tbl",
   5652                                            idx_start, idx_end - 1,
   5653                                            &lpm_hit_only_tbl_ptr[0]);
   5654             if (rv < 0) {
   5655                 goto free_table;
   5656             }
   5657         } else {
   5658             tbl_entry_sz = WORDS2BYTES(soc_mem_entry_words(unit,
   5659                                        L3_DEFIP_HIT_ONLY_Xm));
   5660             rv = bcm_xgs3_l3_tbl_range_dma(unit, 
   5661                                            L3_DEFIP_HIT_ONLY_Xm,
   5662                                            tbl_entry_sz,
   5663                                            "lpm_hit_only_x_tbl",
   5664                                            idx_start, idx_end - 1,
   5665                                            &lpm_hit_only_tbl_ptr[0]);
   5666             if (rv < 0) {
   5667                 goto free_table;
   5668             }
   5669 
   5670             rv = bcm_xgs3_l3_tbl_range_dma(unit, 
   5671                                            L3_DEFIP_HIT_ONLY_Ym,
   5672                                            tbl_entry_sz,
   5673                                            "lpm_hit_only_y_tbl",
   5674                                            idx_start, idx_end - 1,
   5675                                            &lpm_hit_only_tbl_ptr[1]);
   5676             if (rv < 0) {
   5677                 goto free_table;
   5678             }
   5679         }
   5680     }
   5681 #endif /* BCM_TRIDENT_SUPPORT */
   5682 
   5683     for (idx  = read_reverse ? (idx_end - 1) : idx_start;
   5684          (read_reverse ? (idx >= idx_start) : (idx < idx_end));
   5685          (read_reverse ? idx-- : idx++)) {
   5686          tcam_number = idx / tcam_depth;
   5687          if (ipv6 && (tcam_number & 1)) {
   5688              if (read_reverse) {
   5689                  idx -= tcam_depth;
   5690              } else {
   5691                  idx += tcam_depth;
   5692              }
   5693              if (idx >= defip_table_size) {
   5694                  break;
   5695              }
   5696          }
   5697         /* Calculate entry ofset. */
   5698         if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) {
   5699             lpm_entry =
   5700                 (uint32 *)soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip),
   5701                                          defip_level1_entry_t *, lpm_tbl_ptr, idx);
   5702         } else {
   5703             lpm_entry =
   5704                 (uint32 *)soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip),
   5705                                          defip_entry_t *, lpm_tbl_ptr, idx);
   5706         }
   5707         if (ipv6) {
   5708             /* Calculate entry ofset. */
   5709             if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) {
   5710                 lpm_entry_upr =
   5711                     (uint32 *)soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip),
   5712                                                  defip_level1_entry_t *, lpm_tbl_ptr,
   5713                                                  idx + tcam_depth);
   5714             } else {
   5715                 lpm_entry_upr =
   5716                     (uint32 *)soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip),
   5717                                          defip_entry_t *, lpm_tbl_ptr, idx + tcam_depth);
   5718             }
   5719         }
   5720 
   5721         sal_memcpy(&lpm_entry_tmp, lpm_entry, BCM_XGS3_L3_ENT_SZ(unit, defip));
   5722 #ifdef BCM_WARM_BOOT_SUPPORT
   5723         need_reinit = 0;
   5724 #endif
   5725         /* Each lpm entry contains 2 ipv4 entries ->  Check both. */
   5726         for (tmp_idx = 0; tmp_idx < ((ipv6) ? 1 : 2); tmp_idx++) {
   5727 
   5728             if (tmp_idx) {
   5729                 /* Check second part of the entry. */
   5730                 soc_fb_lpm_ip4entry1_to_0(unit, lpm_entry, lpm_entry, TRUE);
   5731             }
   5732 
   5733             /* The ipv4 route can not be in the first half of L3_DEFIPm since the TH2 L3_DEFIP issue , 
   5734                          so skip it*/
   5735             if (soc_feature(unit,soc_feature_half_of_l3_defip_ipv4_capacity) &&
   5736                 !ipv6 && !tmp_idx) {
   5737                 continue;
   5738             }
   5739 
   5740             /* Make sure entry is valid. */
   5741             if (!soc_mem_field32_get(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, VALID0f)) {
   5742                 continue;
   5743             }
   5744 
   5745             if (ipv6) {
   5746                 /* Make sure entry is valid. */
   5747                 if (!soc_mem_field32_get(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry_upr, VALID0f)) {
   5748                     continue;
   5749                 }
   5750 
   5751 #if defined(BCM_TOMAHAWK3_SUPPORT)
   5752                 if (SOC_IS_TOMAHAWK3(unit)) {
   5753                     uint32 _key_data[2] = {0, 0};
   5754                     soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, lpm_entry, KEY0f, _key_data);
   5755                     if (!(soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf))) {
   5756                         continue;
   5757                     }
   5758                 } else
   5759 #endif
   5760                 if (!soc_mem_field32_get(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, defip_mode0_bit[unit])) {
   5761                     continue;
   5762                 }
   5763             }
   5764 #ifdef BCM_TRIDENT_SUPPORT
   5765             if (SOC_IS_TD_TT(unit) && !(SOC_IS_TOMAHAWK3(unit))) {
   5766                 uint32 i, hit;
   5767                 defip_hit_only_entry_t *hit_entry[2];
   5768                 soc_mem_t hit_mem[] = {L3_DEFIP_HIT_ONLY_Xm, L3_DEFIP_HIT_ONLY_Ym};
   5769                 int hit_mem_cnt = 2;
   5770 
   5771                 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_APACHE(unit)
   5772                                       || SOC_IS_TRIDENT3X(unit)) {
   5773                     hit_mem[0] = L3_DEFIP_HIT_ONLYm;
   5774                     hit_mem_cnt = 1;
   5775                 }
   5776 
   5777                 if (ipv6) {
   5778                     for (i = 0, hit = 0; i < hit_mem_cnt; i++) {
   5779                         hit_entry[i] = soc_mem_table_idx_to_pointer(unit,
   5780                                            hit_mem[i],
   5781                                            defip_hit_only_entry_t *,
   5782                                            lpm_hit_only_tbl_ptr[i],
   5783                                            idx);
   5784                         hit |= soc_mem_field32_get(unit, hit_mem[i],
   5785                                                    hit_entry[i], HIT0f);
   5786                     }
   5787                     soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, HIT0f, hit);
   5788                     for (i = 0, hit = 0; i < hit_mem_cnt; i++) {
   5789                         hit |= soc_mem_field32_get(unit, hit_mem[i],
   5790                                                    hit_entry[i], HIT1f);
   5791                     }
   5792                     soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, HIT1f, hit);
   5793                 } else {
   5794                     for (i = 0, hit = 0; i < hit_mem_cnt; i++) {
   5795                         hit_entry[i] = soc_mem_table_idx_to_pointer(unit,
   5796                                            hit_mem[i],
   5797                                            defip_hit_only_entry_t *,
   5798                                            lpm_hit_only_tbl_ptr[i],
   5799                                            idx);
   5800                         hit |= soc_mem_field32_get(unit, hit_mem[i],
   5801                                                    hit_entry[i],
   5802                                                    tmp_idx ? HIT1f : HIT0f);
   5803                     }
   5804                     soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, HIT0f, hit);
   5805                 }
   5806             }
   5807 #endif /* BCM_TRIDENT_SUPPORT */
   5808 
   5809             /* Zero destination buffer first. */
   5810             sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t));
   5811 
   5812             /* Parse  the entry. */
   5813             rv = _bcm_fb_lpm_ent_parse(unit, &lpm_cfg, &nh_ecmp_idx, lpm_entry, &b128);
   5814             if (BCM_FAILURE(rv)) {
   5815                LOG_ERROR(BSL_LS_BCM_L3,
   5816                           (BSL_META_U(unit,
   5817                                       "_bcm_fb_lpm_ent_parse failed\n")));
   5818                 goto free_table;
   5819             }
   5820             if (ipv6 && b128 != 1) {
   5821                 LOG_ERROR(BSL_LS_BCM_L3,
   5822                           (BSL_META_U(unit,
   5823                                       "b128 traverse: entry is not b128\n")));
   5824                 rv = SOC_E_INTERNAL;
   5825                 goto free_table;
   5826             }
   5827             if (ipv6) {
   5828                 lpm_cfg.defip_index = ((idx / (tcam_depth * 2)) * tcam_depth) +
   5829                                       (idx % tcam_depth);
   5830             } else {
   5831                 lpm_cfg.defip_index = idx;
   5832             }
   5833             /* If protocol doesn't match skip the entry. */
   5834             if ((lpm_cfg.defip_flags & BCM_L3_IP6) != ipv6) {
   5835                 continue;
   5836             }
   5837 
   5838             /* Fill entry ip address &  subnet mask. */
   5839             if (ipv6) {
   5840                 _bcm_fb_lpm128_ent_get_key(unit, &lpm_cfg, lpm_entry,
   5841                                            lpm_entry_upr);
   5842             } else {
   5843                 _bcm_fb_lpm_ent_get_key(unit, &lpm_cfg, lpm_entry);
   5844             }
   5845             lpm_cfg.defip_flags_high |= BCM_XGS3_L3_ENTRY_IN_DEFIP_PAIR;
   5846             /* Execute operation routine if any. */
   5847             if (trv_data->op_cb) {
   5848                 rv = (*trv_data->op_cb) (unit, (void *)trv_data,
   5849                                          (void *)&lpm_cfg,
   5850                                          (void *)&nh_ecmp_idx, &cmp_result);
   5851                 if (rv < 0) {
   5852                     goto free_table;
   5853                 }
   5854             }
   5855 #ifdef BCM_WARM_BOOT_SUPPORT
   5856             need_reinit = 1;
   5857 #endif
   5858         }
   5859 #ifdef BCM_WARM_BOOT_SUPPORT
   5860         if (SOC_WARM_BOOT(unit) && need_reinit) {
   5861             /* coverity[forward_null : FALSE] */
   5862             rv = soc_fb_lpm128_reinit(unit, idx, (uint32 *)&lpm_entry_tmp,
   5863                                       lpm_entry_upr);
   5864             if (rv < 0) {
   5865                 goto free_table;
   5866             }
   5867         }
   5868 #endif /* BCM_WARM_BOOT_SUPPORT */
   5869     }
   5870 
   5871 #ifdef BCM_WARM_BOOT_SUPPORT
   5872     if (SOC_WARM_BOOT(unit)) {
   5873         SOC_IF_ERROR_RETURN(soc_fb_lpm128_reinit_done(unit, ipv6));
   5874     }
   5875 #endif /* BCM_WARM_BOOT_SUPPORT */
   5876 
   5877 free_table:
   5878     if (lpm_tbl_ptr != NULL) {
   5879         soc_cm_sfree(unit, lpm_tbl_ptr);
   5880     }
   5881 #ifdef BCM_TRIDENT_SUPPORT
   5882     if (lpm_hit_only_tbl_ptr[0] != NULL) {
   5883         soc_cm_sfree(unit, lpm_hit_only_tbl_ptr[0]);
   5884     }
   5885     if (lpm_hit_only_tbl_ptr[1] != NULL) {
   5886         soc_cm_sfree(unit, lpm_hit_only_tbl_ptr[1]);
   5887     }
   5888 #endif
   5889 
   5890     return rv;
   5891 }
   5892 
   5893 /*
   5894  * Function:
   5895  *      bcm_xgs3_l3_tbl_range_dma
   5896  * Purpose:
   5897  *
   5898  * Parameters:
   5899  *      unit         -(IN)SOC unit number.
   5900  *      tbl_mem      -(IN)Table memory.
   5901  *      tbl_entry_sz -(IN)Table entry size.
   5902  *      descr        -(IN)Table descriptor.
   5903  *      start        -(IN) Start index
   5904  *      end          -(IN) End index
   5905  *      res_ptr      -(OUT) Allocated pointer filled with table info
   5906  * Returns:
   5907  *      BCM_E_XXX
   5908  */
   5909 int
   5910 bcm_xgs3_l3_tbl_range_dma(int unit, soc_mem_t tbl_mem, uint16 tbl_entry_sz,
   5911                           const char *descr, int start, int end, char **res_ptr)
   5912 {
   5913     int alloc_size;             /* Allocation size.          */
   5914     char *buffer;               /* Buffer to read the table. */
   5915     int tbl_size;               /* HW table size.            */
   5916 
   5917     /* Input parameters sanity check. */
   5918     if ((NULL == res_ptr) || (NULL == descr)) {
   5919         return (BCM_E_PARAM);
   5920     }
   5921 
   5922     /* If entry size is not deterministic. reject. */
   5923     if (tbl_entry_sz == BCM_XGS3_L3_INVALID_ENT_SZ) {
   5924         return (BCM_E_UNAVAIL);
   5925     }
   5926 
   5927     if (INVALIDm == tbl_mem) {
   5928         return (BCM_E_NOT_FOUND);
   5929     }
   5930 
   5931     if (start < soc_mem_index_min(unit, tbl_mem) ||
   5932         end > soc_mem_index_max(unit, tbl_mem)) {
   5933         return BCM_E_PARAM;
   5934     }
   5935 
   5936     /* Calculate table size. */
   5937     tbl_size = (end - start) + 1;
   5938     alloc_size = tbl_entry_sz * tbl_size;
   5939 
   5940     /* Allocate memory buffer. */
   5941     buffer = soc_cm_salloc(unit, alloc_size, descr);
   5942     if (buffer == NULL) {
   5943         return (BCM_E_MEMORY);
   5944     }
   5945 
   5946     /* Reset allocated buffer. */
   5947     memset(buffer, 0, alloc_size);
   5948 
   5949     /* Read table to the buffer. */
   5950     if (soc_mem_read_range(unit, tbl_mem, MEM_BLOCK_ANY,
   5951                            start,
   5952                            end, buffer) < 0) {
   5953         soc_cm_sfree(unit, buffer);
   5954         return (BCM_E_INTERNAL);
   5955     }
   5956 
   5957     *res_ptr = buffer;
   5958     return (BCM_E_NONE);
   5959 }
   5960 
   5961 
   5962 /*
   5963  * Function:
   5964  *      _bcm_xgs3_l3_tnl_initiator_init
   5965  * Purpose:
   5966  *      Initiate the tunnel terminator table.
   5967  * Parameters:
   5968  *      unit    - (IN)  SOC unit number.
   5969  * Returns:
   5970  *      BCM_E_XXX
   5971  */
   5972 STATIC int
   5973 _bcm_xgs3_l3_tnl_initiator_init(int unit)
   5974 {
   5975     int mem_sz;                 /* Memory allocation size. */
   5976     _bcm_l3_tbl_t *tbl_ptr;     /* Tunnel initiator table. */
   5977 
   5978     /* Get table pointer. */
   5979     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, tnl_init);
   5980 
   5981     /* Get L3 tunnel table first & last index. */
   5982     tbl_ptr->idx_min = soc_mem_index_min(unit,
   5983                                          BCM_XGS3_L3_MEM(unit, tnl_init_v4));
   5984     tbl_ptr->idx_max = soc_mem_index_max(unit,
   5985                                          BCM_XGS3_L3_MEM(unit, tnl_init_v4));
   5986 
   5987     /* Set max used tunnel to first one (table is empty). */
   5988     tbl_ptr->idx_maxused = tbl_ptr->idx_min;
   5989 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   5990     tbl_ptr->split_idx     = 0;
   5991     tbl_ptr->split_maxused = 0;
   5992 #endif
   5993 
   5994 
   5995     BCM_XGS3_L3_TUNNEL_TBL_SIZE(unit) = tbl_ptr->idx_max - tbl_ptr->idx_min + 1;
   5996 
   5997     /*
   5998      * Keep track of tunnel initiator table usage.
   5999      * Table size doesn't include first reserved entry.
   6000      */
   6001     mem_sz = (BCM_XGS3_L3_TUNNEL_TBL_SIZE(unit) + 1) *
   6002         sizeof(_bcm_l3_tbl_ext_t);
   6003     BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_TBL(unit, tnl_init).ext_arr,
   6004                          mem_sz, "l3_tnl_init");
   6005     if (NULL == BCM_XGS3_L3_TBL(unit, tnl_init).ext_arr) {
   6006         return (BCM_E_MEMORY);
   6007     }
   6008 
   6009     return (BCM_E_NONE);
   6010 }
   6011 
   6012 /*
   6013  * Function:
   6014  *      _bcm_xgs3_l3_tnl_dscp_init
   6015  * Purpose:
   6016  *      Initiate the tunnel dscp table.
   6017  * Parameters:
   6018  *      unit    - (IN)  SOC unit number.
   6019  * Returns:
   6020  *      BCM_E_XXX
   6021  */
   6022 STATIC int
   6023 _bcm_xgs3_l3_tnl_dscp_init(int unit)
   6024 {
   6025     int mem_sz;          /* Allocated memory size. */
   6026     int tnl_dscp_tbl_sz; /* Dscp map entry count. */
   6027 
   6028 #ifdef BCM_HURRICANE3_SUPPORT
   6029     if (soc_feature(unit, soc_feature_miml_no_l3)) {
   6030         tnl_dscp_tbl_sz = 0;
   6031         BCM_XGS3_L3_TUNNEL_DSCP_MAP_TBL_SIZE(unit) = tnl_dscp_tbl_sz;
   6032         return (BCM_E_NONE);
   6033     }
   6034 #endif
   6035     tnl_dscp_tbl_sz = soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, tnl_dscp));
   6036 
   6037     /* Keep track of L3 tunnel dscp map IDs based on
   6038      * the number of DSCP map table instances. Each
   6039      * instance has (#prio * #color) entries. For Firebolt
   6040      * there are 8 priorities and 4 colors.
   6041      */
   6042     BCM_XGS3_L3_TUNNEL_DSCP_MAP_TBL_SIZE(unit) =
   6043         SOC_IS_TRX(unit) ? (1) : tnl_dscp_tbl_sz / (8 * 4);
   6044     mem_sz = SHR_BITALLOCSIZE(BCM_XGS3_L3_TUNNEL_DSCP_MAP_TBL_SIZE(unit));
   6045     BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_TUNNEL_DSCP_MAP_INUSE(unit), mem_sz,
   6046                          "l3_dscp_map");
   6047     if (NULL == BCM_XGS3_L3_TUNNEL_DSCP_MAP_INUSE(unit)) {
   6048         return (BCM_E_MEMORY);
   6049     }
   6050 
   6051     return (BCM_E_NONE);
   6052 }
   6053 
   6054 
   6055 /*
   6056  * Function:
   6057  *      _bcm_xgs3_l3_adj_mac_init
   6058  * Purpose:
   6059  *      Initialize L3 tables.
   6060  * Parameters:
   6061  *      unit    - (IN)  SOC unit number.
   6062  * Returns:
   6063  *      BCM_E_XXX
   6064  */
   6065 STATIC int
   6066 _bcm_xgs3_l3_adj_mac_init(int unit)
   6067 {
   6068     return (BCM_E_NONE);
   6069 }
   6070 
   6071 #ifdef BCM_TRIDENT_SUPPORT
   6072 /*
   6073  * Function:
   6074  *      _bcm_xgs3_trunk_nh_store_init
   6075  * Purpose:
   6076  *      Initialize Trunk to NextHop Index Store
   6077  * Parameters:
   6078  *      unit    - (IN)  SOC unit number.
   6079  * Returns:
   6080  *      BCM_E_XXX
   6081  */
   6082 int
   6083 _bcm_xgs3_trunk_nh_store_init(int unit)
   6084 {
   6085     _bcm_l3_bookkeeping_t *l3_bk_info = L3_INFO(unit);
   6086     int num_trunk;
   6087     soc_mem_t trunk_mem = TRUNK_GROUPm;
   6088 
   6089     if (soc_feature(unit, soc_feature_fastlag)) {
   6090         trunk_mem = FAST_TRUNK_GROUPm;
   6091     }
   6092 
   6093     num_trunk = soc_mem_index_count(unit, trunk_mem);
   6094 
   6095     /* Allocate ip4 options profile usage bitmap */
   6096     if (NULL == l3_bk_info->l3_trunk_nh_store) {
   6097         l3_bk_info->l3_trunk_nh_store =
   6098               sal_alloc(sizeof(int) * num_trunk, "trunk nextHop store");
   6099         if (l3_bk_info->l3_trunk_nh_store == NULL) {
   6100             return BCM_E_MEMORY;
   6101         }
   6102     }
   6103     sal_memset( l3_bk_info->l3_trunk_nh_store, 0, sizeof(int) * num_trunk);
   6104     return BCM_E_NONE;
   6105 }
   6106 
   6107 /*
   6108  * Function:
   6109  *      _bcm_xgs3_trunk_nh_store_init
   6110  * Purpose:
   6111  *      Initialize Trunk to NextHop Index Store
   6112  * Parameters:
   6113  *      unit    - (IN)  SOC unit number.
   6114  * Returns:
   6115  *      BCM_E_XXX
   6116  */
   6117 void
   6118 _bcm_xgs3_trunk_nh_store_deinit(int unit)
   6119 {
   6120     _bcm_l3_bookkeeping_t *l3_bk_info = L3_INFO(unit);
   6121 
   6122     if (l3_bk_info->l3_trunk_nh_store) {
   6123         sal_free(l3_bk_info->l3_trunk_nh_store);
   6124         l3_bk_info->l3_trunk_nh_store = NULL;
   6125     }
   6126 
   6127 }
   6128 
   6129 /*
   6130  * Function:
   6131  *      _bcm_xgs3_trunk_nh_store_set
   6132  * Purpose:
   6133  *      Set Trunk to NextHop Index Store entry
   6134  * Parameters:
   6135  *      unit    - (IN)  SOC unit number.
   6136  * Returns:
   6137  *      BCM_E_XXX
   6138  */
   6139 int
   6140 _bcm_xgs3_trunk_nh_store_set(int unit, bcm_trunk_t trunk_id, int nh_index)
   6141 {
   6142     _bcm_l3_bookkeeping_t *l3_bk_info = L3_INFO(unit);
   6143     int num_trunk;
   6144     soc_mem_t trunk_mem = TRUNK_GROUPm;
   6145 
   6146     if (soc_feature(unit, soc_feature_fastlag)) {
   6147         trunk_mem = FAST_TRUNK_GROUPm;
   6148     }
   6149 
   6150     num_trunk = soc_mem_index_count(unit, trunk_mem);
   6151 
   6152     if (l3_bk_info->l3_trunk_nh_store) {
   6153        if (trunk_id < num_trunk) {
   6154            l3_bk_info->l3_trunk_nh_store[trunk_id] = nh_index;
   6155        } else {
   6156            return BCM_E_PARAM;
   6157        }
   6158     }
   6159     return BCM_E_NONE;
   6160 }
   6161 
   6162 /*
   6163  * Function:
   6164  *      _bcm_xgs3_trunk_nh_store_get
   6165  * Purpose:
   6166  *      Get Trunk to NextHop Index Store entry
   6167  * Parameters:
   6168  *      unit    - (IN)  SOC unit number.
   6169  * Returns:
   6170  *      BCM_E_XXX
   6171  */
   6172 int
   6173 _bcm_xgs3_trunk_nh_store_get(int unit, bcm_trunk_t trunk_id, int *nh_index)
   6174 {
   6175     _bcm_l3_bookkeeping_t *l3_bk_info = L3_INFO(unit);
   6176     int num_trunk;
   6177     soc_mem_t trunk_mem = TRUNK_GROUPm;
   6178 
   6179     if (soc_feature(unit, soc_feature_fastlag)) {
   6180         trunk_mem = FAST_TRUNK_GROUPm;
   6181     }
   6182 
   6183     num_trunk = soc_mem_index_count(unit, trunk_mem);
   6184 
   6185     if (l3_bk_info->l3_trunk_nh_store) {
   6186        if (trunk_id < num_trunk) {
   6187            *nh_index = l3_bk_info->l3_trunk_nh_store[trunk_id];
   6188        } else {
   6189            return BCM_E_PARAM;
   6190        }
   6191     }
   6192     return BCM_E_NONE;
   6193 }
   6194 
   6195 /*
   6196  * Function:
   6197  *      _bcm_xgs3_trunk_nh_store_reset
   6198  * Purpose:
   6199  *      Reset Trunk to NextHop Index Store entry
   6200  * Parameters:
   6201  *      unit    - (IN)  SOC unit number.
   6202  * Returns:
   6203  *      BCM_E_XXX
   6204  */
   6205 int
   6206 _bcm_xgs3_trunk_nh_store_reset(int unit, bcm_trunk_t trunk_id, int nh_index)
   6207 {
   6208     _bcm_l3_bookkeeping_t *l3_bk_info = L3_INFO(unit);
   6209     int num_trunk;
   6210     soc_mem_t trunk_mem = TRUNK_GROUPm;
   6211 
   6212     if (soc_feature(unit, soc_feature_fastlag)) {
   6213         trunk_mem = FAST_TRUNK_GROUPm;
   6214     }
   6215 
   6216     num_trunk = soc_mem_index_count(unit, trunk_mem);
   6217 
   6218     if (l3_bk_info->l3_trunk_nh_store) {
   6219        if (trunk_id < num_trunk) {
   6220            if ((nh_index == -1) ||
   6221                (l3_bk_info->l3_trunk_nh_store[trunk_id] == nh_index)) {
   6222                l3_bk_info->l3_trunk_nh_store[trunk_id] = 0;
   6223            }
   6224        } else {
   6225            return BCM_E_PARAM;
   6226        }
   6227     }
   6228     return BCM_E_NONE;
   6229 }
   6230 
   6231 int
   6232 _bcm_xgs3_trunk_nh_store_unmap(int unit, bcm_trunk_t tid, int nh_index)
   6233 {
   6234     int          rv = BCM_E_NONE;
   6235     int          idx = 0;
   6236     bcm_port_t   local_ports[SOC_MAX_NUM_PORTS];
   6237     int          num_ports=0;
   6238     int          gport = 0;
   6239     int          modid = 0;
   6240 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   6241     bcm_trunk_member_t *tmp_member_gports_array = NULL;
   6242 #endif
   6243 
   6244     BCM_IF_ERROR_RETURN(
   6245         _bcm_xgs3_trunk_nh_store_reset(unit, tid, -1));
   6246 
   6247     rv = bcm_esw_trunk_get(unit, tid, NULL, 0, NULL, &num_ports);
   6248     if (BCM_FAILURE(rv)) {
   6249         return BCM_E_PORT;
   6250     }
   6251     if (num_ports == 0) {
   6252         return BCM_E_NONE;
   6253     }
   6254 
   6255 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   6256     if(soc_feature(unit, soc_feature_egr_modport_to_nhi)) {
   6257         tmp_member_gports_array = sal_alloc(
   6258             sizeof(bcm_trunk_member_t) * num_ports, "tmp_member_gports_arry");
   6259         if (tmp_member_gports_array == NULL) {
   6260             return BCM_E_MEMORY;
   6261         }
   6262         sal_memset(tmp_member_gports_array, 0,
   6263                    sizeof(bcm_trunk_member_t) * num_ports);
   6264         rv = bcm_esw_trunk_get(unit, tid, NULL,
   6265                      num_ports, tmp_member_gports_array, &num_ports);
   6266         if (BCM_FAILURE(rv)) {
   6267             goto clean_up;
   6268         }
   6269     } else
   6270 #endif
   6271     {
   6272         BCM_IF_ERROR_RETURN(_bcm_esw_trunk_local_members_get(unit, tid,
   6273             SOC_MAX_NUM_PORTS, local_ports, &num_ports));
   6274         BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &modid));
   6275     }
   6276 
   6277     for (idx = 0; idx < num_ports; idx++) {
   6278 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   6279         if(soc_feature(unit, soc_feature_egr_modport_to_nhi)) {
   6280             gport = tmp_member_gports_array[idx].gport;
   6281         } else
   6282 #endif
   6283         {
   6284             BCM_GPORT_MODPORT_SET(gport, modid, local_ports[idx]);
   6285         }
   6286 
   6287         rv = _bcm_trx_gport_to_nhi_set(unit, gport, 0);
   6288         if (BCM_FAILURE(rv)) {
   6289             goto clean_up;
   6290         }
   6291     }
   6292 
   6293 clean_up:
   6294 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   6295     if (NULL != tmp_member_gports_array) {
   6296         sal_free(tmp_member_gports_array);
   6297     }
   6298 #endif
   6299     return rv;
   6300 }
   6301 #endif /* BCM_TRIDENT_SUPPORT */
   6302 
   6303 /*
   6304  * Function:
   6305  *      _bcm_xgs3_l3_free_resource
   6306  * Purpose:
   6307  *      Free all allocated tables and memory
   6308  * Parameters:
   6309  *      unit - SOC unit number
   6310  * Returns:
   6311  *      Nothing
   6312  */
   6313 STATIC void
   6314 _bcm_xgs3_l3_free_resource(int unit)
   6315 {
   6316     int rv;        /* Operation return status. */
   6317 
   6318     /* If software tables were not allocated we are done. */
   6319     if (NULL == l3_module_data[unit]) {
   6320         return;
   6321     }
   6322 
   6323     /* Free next hop ref counts & hashes. */
   6324     if (BCM_XGS3_L3_TBL(unit, next_hop).ext_arr) {
   6325         sal_free(BCM_XGS3_L3_TBL(unit, next_hop).ext_arr);
   6326         BCM_XGS3_L3_TBL(unit, next_hop).ext_arr = NULL;
   6327     }
   6328 
   6329     /* Free VLAN VRF ref counts stored in ing_intf table */
   6330     if (BCM_XGS3_L3_TBL(unit, ing_intf).ext_arr) {
   6331         sal_free(BCM_XGS3_L3_TBL(unit, ing_intf).ext_arr);
   6332         BCM_XGS3_L3_TBL(unit, ing_intf).ext_arr = NULL;
   6333     }
   6334 
   6335     /* Free tunnel initiator ref counts & hashes. */
   6336     if (BCM_XGS3_L3_TBL(unit, tnl_init).ext_arr) {
   6337         sal_free(BCM_XGS3_L3_TBL(unit, tnl_init).ext_arr);
   6338         BCM_XGS3_L3_TBL(unit, tnl_init).ext_arr = NULL;
   6339     }
   6340 
   6341     /* Free route table. */
   6342     if (SOC_IS_FBX(unit)) {
   6343         rv = bcm_xgs3_l3_fbx_defip_deinit(unit);
   6344         if (BCM_FAILURE(rv)) {
   6345             LOG_ERROR(BSL_LS_BCM_L3,
   6346                       (BSL_META_U(unit,
   6347                                   "Route table free error %d\n"),
   6348                        rv));
   6349         }
   6350     }
   6351 
   6352     if (BCM_XGS3_L3_TBL(unit, ecmp).ext_arr) {
   6353         sal_free(BCM_XGS3_L3_TBL(unit, ecmp).ext_arr);
   6354         BCM_XGS3_L3_TBL(unit, ecmp).ext_arr = NULL;
   6355     }
   6356 
   6357     if(!soc_feature(unit, soc_feature_no_tunnel)) {
   6358         /* Tunnels terminator table  deinit. */
   6359         rv = soc_tunnel_term_deinit(unit);
   6360         if (BCM_FAILURE(rv)) {
   6361             LOG_ERROR(BSL_LS_BCM_L3,
   6362                       (BSL_META_U(unit,
   6363                                   "Tunnel terminator table free %d\n"),
   6364                        rv));
   6365         }
   6366     }
   6367 
   6368 #ifdef BCM_TRIUMPH2_SUPPORT
   6369     if (soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf) ||
   6370             soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) {
   6371         bcm_tr2_l3_ecmp_defragment_buffer_deinit(unit);
   6372     }
   6373     if(BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)) {
   6374         sal_free(BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit));
   6375         BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit) = NULL;
   6376     }
   6377 #endif /* BCM_TRIUMPH2_SUPPORT */
   6378 
   6379     /* Free ecmp groups ref counts & hashes. */
   6380     if (BCM_XGS3_L3_TBL(unit, ecmp_grp).ext_arr) {
   6381         sal_free(BCM_XGS3_L3_TBL(unit, ecmp_grp).ext_arr);
   6382         BCM_XGS3_L3_TBL(unit, ecmp_grp).ext_arr = NULL;
   6383     }
   6384 
   6385 #ifdef BCM_TRIDENT_SUPPORT
   6386             if (soc_feature(unit, soc_feature_trill) ||
   6387                 soc_feature(unit, soc_feature_l2gre) ||
   6388                 soc_feature(unit, soc_feature_vxlan)) {
   6389                 (void) _bcm_xgs3_trunk_nh_store_deinit(unit);
   6390             }
   6391 #endif /* BCM_TRIDENT_SUPPORT */
   6392 
   6393 #ifdef BCM_TRIUMPH3_SUPPORT
   6394     if (soc_feature(unit, soc_feature_ecmp_dlb)) {
   6395 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   6396         if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
   6397             _bcm_th2_ecmp_dlb_deinit(unit);
   6398         } else
   6399 #endif /* BCM_TOMAHAWK2_SUPPORT */
   6400         {
   6401             _bcm_tr3_ecmp_dlb_deinit(unit);
   6402         }
   6403     }
   6404 #endif /* BCM_TRIUMPH3_SUPPORT */
   6405 
   6406 #ifdef BCM_TRIDENT2_SUPPORT
   6407     if ((SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT3X(unit)) &&
   6408         soc_feature(unit, soc_feature_ecmp_resilient_hash)) {
   6409         bcm_td2_ecmp_rh_deinit(unit);
   6410     }
   6411 #endif /* BCM_TRIDENT2_SUPPORT */
   6412 
   6413 #ifdef BCM_TOMAHAWK_SUPPORT
   6414     if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) {
   6415         bcm_opt_ecmp_rh_deinit(unit);
   6416     }
   6417 #endif /* BCM_TOMAHAWK_SUPPORT */
   6418 
   6419 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   6420     if (soc_feature(unit, soc_feature_ipmc_defip)) {
   6421         bcm_td2p_l3_defip_deinit(unit);
   6422     }
   6423 #endif
   6424 
   6425     /* Free interface indexes usage bits. */
   6426     if (BCM_XGS3_L3_IF_INUSE(unit)) {
   6427         sal_free(BCM_XGS3_L3_IF_INUSE(unit));
   6428         BCM_XGS3_L3_IF_INUSE(unit) = NULL;
   6429     }
   6430 
   6431     /* Free egress interfaces indexes usage bits ever set in Next Hop table. */
   6432     if (BCM_XGS3_L3_INTF_USED_NH(unit)) {
   6433         sal_free(BCM_XGS3_L3_INTF_USED_NH(unit));
   6434         BCM_XGS3_L3_INTF_USED_NH(unit) = NULL;
   6435     }
   6436 
   6437     /* Free interface indexes usage bits. */
   6438     if (BCM_XGS3_L3_ING_IF_INUSE(unit)) {
   6439         sal_free(BCM_XGS3_L3_ING_IF_INUSE(unit));
   6440         BCM_XGS3_L3_ING_IF_INUSE(unit) = NULL;
   6441     }
   6442 
   6443 
   6444     /* Free interface address in ARL bits. */
   6445     if (BCM_XGS3_L3_IF_ADD2ARL(unit)) {
   6446         sal_free(BCM_XGS3_L3_IF_ADD2ARL(unit));
   6447         BCM_XGS3_L3_IF_ADD2ARL(unit) = NULL;
   6448     }
   6449 
   6450     /* Free dscp map indexes usage bits. */
   6451     if (BCM_XGS3_L3_TUNNEL_DSCP_MAP_INUSE(unit)) {
   6452         sal_free(BCM_XGS3_L3_TUNNEL_DSCP_MAP_INUSE(unit));
   6453         BCM_XGS3_L3_TUNNEL_DSCP_MAP_INUSE(unit) = NULL;
   6454     }
   6455 
   6456 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \
   6457     defined(BCM_HAWKEYE_SUPPORT)
   6458     if (soc_feature(unit, soc_feature_fp_based_routing)) {
   6459         _bcm_rp_l3_deinit(unit);
   6460     }
   6461 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */
   6462 
   6463 #if defined(BCM_TRIUMPH2_SUPPORT)
   6464     if (soc_feature(unit, soc_feature_gport_service_counters)) {
   6465         _bcm_esw_flex_stat_release_handles(unit, _bcmFlexStatTypeVrf);
   6466     }
   6467 #endif
   6468 
   6469 #if defined(BCM_TRIUMPH3_SUPPORT)
   6470     if (SOC_IS_TRIUMPH3(unit)) {
   6471         if(BCM_TR3_ESM_HOST_TBL_PRESENT(unit)) {
   6472             rv = _bcm_tr3_esm_host_tbl_deinit(unit);
   6473             if (BCM_FAILURE(rv)) {
   6474                 LOG_ERROR(BSL_LS_BCM_L3,
   6475                           (BSL_META_U(unit,
   6476                                       "Error in freeing ESM host tbl state %d\n"),
   6477                            rv));
   6478             }
   6479         }
   6480     }
   6481 #endif
   6482 
   6483 #ifdef BCM_TRIDENT2_SUPPORT
   6484     if (soc_feature(unit, soc_feature_l3_ip4_options_profile)) {
   6485        rv = _bcm_td2_l3_ip4_options_free_resources(unit);
   6486        if (BCM_FAILURE(rv)) {
   6487            LOG_ERROR(BSL_LS_BCM_L3,
   6488                      (BSL_META_U(unit,
   6489                                  "Error in freeing IP4 options profile %d\n"),
   6490                       rv));
   6491        }
   6492     }
   6493     if (soc_feature(unit, soc_feature_nat)) {
   6494         _bcm_esw_l3_nat_free_resource(unit);
   6495     }
   6496 #endif /* BCM_TRIDENT2_SUPPORT */
   6497 
   6498 #if defined(BCM_TRX_SUPPORT)
   6499     if (soc_feature(unit, soc_feature_virtual_switching)) {
   6500         rv = _bcm_virtual_deinit(unit);
   6501         if (BCM_FAILURE(rv)) {
   6502            LOG_ERROR(BSL_LS_BCM_L3,
   6503                      (BSL_META_U(unit,
   6504                                  "Error in freeing virtual %d\n"),
   6505                       rv));
   6506        }
   6507     }
   6508 #endif
   6509 
   6510 #if defined(BCM_RIOT_SUPPORT)
   6511     if (soc_feature(unit, soc_feature_riot)) {
   6512         _bcm_td2p_macda_oui_profile_deinit(unit);
   6513     }
   6514 #endif /* BCM_RIOT_SUPPORT */
   6515 
   6516     if (soc_feature(unit, soc_feature_hierarchical_protection)) {
   6517         sal_free(BCM_XGS3_L3_NH_MULTI_COUNT(unit));
   6518         BCM_XGS3_L3_NH_MULTI_COUNT(unit) = NULL;
   6519     }
   6520 #ifdef BCM_TOMAHAWK2_SUPPORT
   6521     if (BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit)) {
   6522         sal_free(BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit));
   6523         BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit) = NULL;
   6524     }
   6525 #endif /* BCM_TOMAHAWK2_SUPPORT */
   6526 
   6527 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   6528     if (BCM_XGS3_L3_ECMP_DLB_MEMBER_PTR(unit)) {
   6529         sal_free(BCM_XGS3_L3_ECMP_DLB_MEMBER_PTR(unit));
   6530         BCM_XGS3_L3_ECMP_DLB_MEMBER_PTR(unit) = NULL;
   6531     }
   6532 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT */
   6533 
   6534     /* Free module data. */
   6535     if (l3_module_data[unit]) {
   6536         sal_free(l3_module_data[unit]->l3_ecmp_info.ecmp_flags);
   6537     }
   6538     sal_free(l3_module_data[unit]);
   6539     l3_module_data[unit] = NULL;
   6540 
   6541     return;
   6542 }
   6543 
   6544 /*
   6545  * Function:
   6546  *      _bcm_xgs3_l3_get_tunnel_id
   6547  * Purpose:
   6548  *      Routine extracts tunnel id based on interface id.
   6549  * Parameters:
   6550  *      unit      -  (IN)StrataSwitch #.
   6551  *      ifindex   -  (IN)Interface index.
   6552  *      tunnel    -  (OUT) tunnel_id.
   6553  * Returns:
   6554  *      BCM_E_XXX
   6555  */
   6556 int
   6557 _bcm_xgs3_l3_get_tunnel_id(int unit, int ifindex, int *tunnel_id)
   6558 {
   6559     _bcm_l3_intf_cfg_t l3_intf; /* Buffer to read interface info. */
   6560     int rv = BCM_E_UNAVAIL;     /* Operation return status.       */
   6561 
   6562     /* Input parameters check. */
   6563     if (NULL == tunnel_id) {
   6564         return (BCM_E_PARAM);
   6565     }
   6566 
   6567     /* Initialization. */
   6568     sal_memset(&l3_intf, 0, sizeof(_bcm_l3_intf_cfg_t));
   6569     *tunnel_id = 0;
   6570 
   6571     /* Set interface index. */
   6572     BCM_XGS3_L3_INTF_IDX_SET(l3_intf, ifindex);
   6573 
   6574     /* Read interface information. */
   6575     if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_get)) {
   6576         BCM_XGS3_L3_MODULE_LOCK(unit);
   6577         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, &l3_intf);
   6578         BCM_XGS3_L3_MODULE_UNLOCK(unit);
   6579     }
   6580     /* Check hw operation status. */
   6581     BCM_IF_ERROR_RETURN(rv);
   6582 
   6583     /* Save interface tunnel index. */
   6584     *tunnel_id = l3_intf.l3i_tunnel_idx;
   6585 
   6586     return (BCM_E_NONE);
   6587 }
   6588 
   6589 /*
   6590  * Function:
   6591  *      _bcm_xgs3_nh_entry_init
   6592  * Purpose:
   6593  *      Routine fills next hop specific info
   6594  *      based on l3 configuration OR defip entry.
   6595  * Parameters:
   6596  *      unit      -  (IN) StrataSwitch #.
   6597  *      nh_entry  -  (OUT)Next hop pointer to fill.
   6598  *      l3cfg     -  (IN) L3 host entry.
   6599  *      lpm_cfg   -  (IN) Route entry.
   6600  * Returns:
   6601  *      BCM_E_XXX
   6602  */
   6603 STATIC int
   6604 _bcm_xgs3_nh_entry_init(int unit, bcm_l3_egress_t *nh_entry,
   6605                         _bcm_l3_cfg_t *l3cfg, _bcm_defip_cfg_t *lpm_cfg)
   6606 {
   6607     int port_tgid;           /* Port/trunk id.   */
   6608 #ifdef BCM_FIREBOLT_SUPPORT
   6609     _bcm_l3_intf_cfg_t l3_intf;
   6610 #endif /* BCM_FIREBOLT_SUPPORT  */
   6611 
   6612     if ((NULL == nh_entry) || ((NULL == l3cfg) && (NULL == lpm_cfg)) ||
   6613         ((NULL != l3cfg) && (NULL != lpm_cfg))) {
   6614         return (BCM_E_PARAM);
   6615     }
   6616 
   6617     /* Reset next hop entry. (We will use it for hash calc. */
   6618     bcm_l3_egress_t_init(nh_entry);
   6619 
   6620     /* Set next hop  interface index. */
   6621     nh_entry->intf = (l3cfg) ? l3cfg->l3c_intf : lpm_cfg->defip_intf;
   6622 
   6623     /* Set next hop flags.            */
   6624     nh_entry->flags = (l3cfg) ? l3cfg->l3c_flags : lpm_cfg->defip_flags;
   6625 
   6626 #ifdef BCM_TRIDENT3_SUPPORT
   6627     if (SOC_IS_TRIDENT3X(unit)) {
   6628         nh_entry->flags2 = (l3cfg) ? l3cfg->l3c_flags2 : lpm_cfg->defip_flags2;
   6629     }
   6630 #endif /* BCM_TRIDENT3_SUPPORT */
   6631     /* Set  port/trunk information.  */
   6632     port_tgid = (l3cfg) ? l3cfg->l3c_port_tgid : lpm_cfg->defip_port_tgid;
   6633     if (nh_entry->flags & BCM_L3_TGID) {
   6634         nh_entry->trunk = port_tgid;
   6635     }  else {
   6636         nh_entry->port = port_tgid;
   6637     }
   6638 
   6639     /* Set module id.                */
   6640     nh_entry->module = (l3cfg) ? l3cfg->l3c_modid : lpm_cfg->defip_modid;
   6641 
   6642     /* Set next hop mac address. */
   6643     sal_memcpy(nh_entry->mac_addr, (l3cfg) ? l3cfg->l3c_mac_addr :
   6644                lpm_cfg->defip_mac_addr, sizeof(bcm_mac_t));
   6645 
   6646 #ifdef BCM_FIREBOLT_SUPPORT
   6647     /* Firebolt devices need interface info to fill vid & tunnel next hop. */
   6648     if (SOC_IS_FBX(unit)) {
   6649         sal_memset(&l3_intf, 0, sizeof(_bcm_l3_intf_cfg_t));
   6650 
   6651         /* Read interface information. */
   6652         BCM_XGS3_L3_INTF_IDX_SET(l3_intf, nh_entry->intf);
   6653 
   6654         BCM_XGS3_L3_MODULE_LOCK(unit);
   6655         if (BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, &l3_intf) >= 0) {
   6656             /* Set vid & istunnel to next hop entry. */
   6657             nh_entry->vlan = l3_intf.l3i_vid;
   6658         }
   6659         BCM_XGS3_L3_MODULE_UNLOCK(unit);
   6660     }
   6661 #endif /* BCM_FIREBOLT_SUPPORT  */
   6662 
   6663     return (BCM_E_NONE);
   6664 }
   6665 
   6666 /*
   6667 * Purpose:
   6668 *	   Entry-0 Nexthop Entry is reserved for BLACK_HOLE
   6669 * Parameters:
   6670 *	   unit 	 -	(IN) StrataSwitch #.
   6671 * Returns:
   6672 *	   BCM_E_XXX
   6673 */
   6674 STATIC int
   6675 _bcm_xgs3_l3_black_hole_nh_setup(int unit)
   6676 {
   6677     bcm_l3_egress_t nh_entry; /* next hop entry. */
   6678     int rv;
   6679 
   6680     if (!SOC_WARM_BOOT(unit)) {
   6681         bcm_l3_egress_t_init(&nh_entry);
   6682         nh_entry.port = 0;
   6683         nh_entry.intf = 0;
   6684         nh_entry.flags = BCM_L3_DST_DISCARD;
   6685     
   6686         BCM_XGS3_L3_MODULE_LOCK(unit);
   6687         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, nh_add)(
   6688                  unit, BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit), &nh_entry, 0);
   6689         BCM_XGS3_L3_MODULE_UNLOCK(unit);
   6690         BCM_IF_ERROR_RETURN(rv);
   6691     }
   6692 
   6693     /* Set entry reference count. */
   6694     BCM_XGS3_L3_ENT_INIT((BCM_XGS3_L3_TBL_PTR(unit, next_hop)),
   6695                          BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit), _BCM_SINGLE_WIDE, 0);
   6696 
   6697 #ifdef BCM_RIOT_SUPPORT
   6698     if (BCMI_L3_NH_OVERLAY_VALID(unit)) {
   6699 
   6700         if (BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit) >
   6701             BCM_XGS3_L3_TBL(unit, next_hop).split_maxused) {
   6702 
   6703             BCM_XGS3_L3_TBL(unit, next_hop).split_maxused = 
   6704                 BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit);
   6705         }
   6706     } else 
   6707 #endif
   6708     {
   6709         if (BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit) >
   6710             BCM_XGS3_L3_TBL(unit, next_hop).idx_maxused) {
   6711 
   6712             BCM_XGS3_L3_TBL(unit, next_hop).idx_maxused = 
   6713                 BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit);
   6714         }
   6715     }
   6716 
   6717     return (BCM_E_NONE);
   6718 }
   6719 
   6720 /*
   6721  * Function:
   6722  *      _bcm_xgs3_l3_l2cpu_nh_setup
   6723  * Purpose:
   6724  *      The first Nexthop Entry is reserved for packet to be L2 switched
   6725  *      to the local CPU.  This is used when the BCM_L3_L2TOCPU flag is used
   6726  *      in host add; or when BCM_L3_DEFIP_LOCAL/BCM_L3_DEFIP_CPU flags
   6727  *      are used when adding routes.
   6728  * Parameters:
   6729  *      unit      -  (IN) StrataSwitch #.
   6730  * Returns:
   6731  *      BCM_E_XXX
   6732  */
   6733 STATIC int
   6734 _bcm_xgs3_l3_l2cpu_nh_setup(int unit)
   6735 {
   6736     bcm_l3_egress_t nh_entry; /* Trap to cpu next hop entry. */
   6737     _bcm_l3_intf_cfg_t intf_info;       /* Bridge to cpu interface.    */
   6738     int rv;
   6739 
   6740     if (!SOC_WARM_BOOT(unit)) {
   6741         /* Zero structures. */
   6742         bcm_l3_egress_t_init(&nh_entry);
   6743     
   6744         /* Set mac address to all ones. */
   6745         sal_memset(nh_entry.mac_addr, 0xff, sizeof(bcm_mac_t));
   6746     
   6747         /* Set module id to a local module. */
   6748         BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &nh_entry.module));
   6749     
   6750         /* Set port to be a cpu port. */
   6751         nh_entry.port = CMIC_PORT(unit);
   6752     
   6753         /* Set interface index. */
   6754         nh_entry.intf = BCM_XGS3_L3_L2CPU_INTF_IDX(unit);
   6755     
   6756         /* Add next hop entry to hw. */
   6757         if (!BCM_XGS3_L3_HWCALL_CHECK(unit, nh_add)) {
   6758             return (BCM_E_UNAVAIL);
   6759         }
   6760     
   6761         BCM_XGS3_L3_MODULE_LOCK(unit);
   6762         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, nh_add) (
   6763                  unit, BCM_XGS3_L3_L2CPU_NH_IDX(unit), &nh_entry, 0);
   6764         BCM_XGS3_L3_MODULE_UNLOCK(unit);
   6765         BCM_IF_ERROR_RETURN(rv);
   6766     }
   6767 
   6768     /* Set entry reference count. */
   6769     BCM_XGS3_L3_ENT_INIT((BCM_XGS3_L3_TBL_PTR(unit, next_hop)),
   6770                          BCM_XGS3_L3_L2CPU_NH_IDX(unit), _BCM_SINGLE_WIDE, 0);
   6771 
   6772 #ifdef BCM_RIOT_SUPPORT
   6773     if (BCMI_L3_NH_OVERLAY_VALID(unit)) {
   6774 
   6775         if (BCM_XGS3_L3_L2CPU_NH_IDX(unit) >
   6776             BCM_XGS3_L3_TBL(unit, next_hop).split_maxused) {
   6777 
   6778             BCM_XGS3_L3_TBL(unit, next_hop).split_maxused = 
   6779                 BCM_XGS3_L3_L2CPU_NH_IDX(unit);
   6780         }
   6781     } else 
   6782 #endif
   6783     {
   6784         if (BCM_XGS3_L3_L2CPU_NH_IDX(unit) >
   6785             BCM_XGS3_L3_TBL(unit, next_hop).idx_maxused) {
   6786 
   6787             BCM_XGS3_L3_TBL(unit, next_hop).idx_maxused = 
   6788                 BCM_XGS3_L3_L2CPU_NH_IDX(unit);
   6789         }
   6790     }
   6791 
   6792     if (!SOC_WARM_BOOT(unit)) {
   6793         /* Create trap to cpu interface entry. */
   6794         /* Set mac address to all ones. */
   6795         sal_memset(&intf_info, 0, sizeof(_bcm_l3_intf_cfg_t));
   6796         sal_memset(intf_info.l3i_mac_addr, 0xff, sizeof(bcm_mac_t));
   6797     
   6798         /* Set L2_SWITCHf flag to true. */
   6799         intf_info.l3i_flags = BCM_L3_L2ONLY;
   6800     
   6801         /* Set interface index. */
   6802         intf_info.l3i_index = BCM_XGS3_L3_L2CPU_INTF_IDX(unit);
   6803     
   6804         /* Add next hop entry to hw. */
   6805         if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_add)) {
   6806             BCM_XGS3_L3_MODULE_LOCK(unit);
   6807             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_add) (unit, &intf_info);
   6808             BCM_XGS3_L3_MODULE_UNLOCK(unit);
   6809             BCM_IF_ERROR_RETURN(rv);
   6810         } else {
   6811             return (BCM_E_UNAVAIL);
   6812         }
   6813     }
   6814 
   6815     /* Mark interface index "inuse" */
   6816     if (!BCM_L3_INTF_USED_GET(unit, BCM_XGS3_L3_L2CPU_INTF_IDX(unit))) {
   6817          BCM_L3_INTF_USED_SET(unit, BCM_XGS3_L3_L2CPU_INTF_IDX(unit));
   6818     }
   6819 
   6820     return (BCM_E_NONE);
   6821 }
   6822 
   6823 
   6824 
   6825 /*
   6826  * Function:
   6827  *      _bcm_xgs3_l3_l2cpu_nh_cb
   6828  * Purpose:
   6829  *      To update the first Nexthop Entry if modid has been changed after init
   6830  * Parameters:
   6831  *      unit      -  (IN) StrataSwitch #.
   6832  *      modid     -  (IN) Update modid
   6833  *      userdata  -  (IN) Pointer to any user data
   6834  * Returns:
   6835  *      NONE
   6836  */
   6837 STATIC void
   6838 _bcm_xgs3_l3_l2cpu_nh_cb(int unit, soc_switch_event_t  event, uint32 arg1,
   6839                    uint32 arg2, uint32 arg3, void* userdata)
   6840 {
   6841 
   6842     switch (event) {
   6843         case SOC_SWITCH_EVENT_MODID_CHANGE:
   6844     _bcm_xgs3_l3_l2cpu_nh_setup(unit);
   6845             break;
   6846         default:
   6847             break;
   6848     }
   6849 
   6850     return;
   6851 }
   6852 
   6853 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   6854 /*
   6855  * Function:
   6856  *      bcmi_xgs3_l3_ecmp_tbl_split_range_init
   6857  * Purpose:
   6858  *      Initialize split indexes in L3 ECMP tables.
   6859  * Parameters:
   6860  *      unit     - (IN)SOC unit number.
   6861  * Returns:
   6862  *      BCM_E_XXX.
   6863  */
   6864 
   6865 STATIC void 
   6866 bcmi_xgs3_l3_ecmp_tbl_split_range_init(int unit, _bcm_l3_tbl_t *tbl_ptr)
   6867 {
   6868 #if defined(BCM_TRIDENT3_SUPPORT)
   6869     _bcm_l3_bookkeeping_t *l3 = &_bcm_l3_bk_info[unit];
   6870     int num_banks;
   6871 #endif
   6872     /* Set up split table limits */
   6873     if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) {
   6874 #if defined(BCM_TRIDENT3_SUPPORT)
   6875         if (SOC_IS_TRIDENT3X(unit)) {
   6876             if ((tbl_ptr == BCM_XGS3_L3_TBL_PTR(unit, ecmp)) && l3->l3_ecmp_member_first_lkup_mem_size) {
   6877                 num_banks = l3->l3_ecmp_member_first_lkup_mem_size / BCMI_L3_ECMP_PER_BANK(unit) +
   6878                                      ((l3->l3_ecmp_member_first_lkup_mem_size % BCMI_L3_ECMP_PER_BANK(unit))?1:0);
   6879                 tbl_ptr->split_idx = num_banks * BCMI_L3_ECMP_PER_BANK(unit);
   6880             } else if ((tbl_ptr == BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp)) && l3->l3_ecmp_group_first_lkup_mem_size) {
   6881                 num_banks = l3->l3_ecmp_group_first_lkup_mem_size / BCMI_L3_ECMP_GROUP_PER_BANK(unit) +
   6882                                      ((l3->l3_ecmp_group_first_lkup_mem_size % BCMI_L3_ECMP_GROUP_PER_BANK(unit))?1:0);
   6883                 tbl_ptr->split_idx = num_banks * BCMI_L3_ECMP_GROUP_PER_BANK(unit);
   6884             } else {
   6885                 tbl_ptr->split_idx = (tbl_ptr->idx_max + 1)/2;
   6886             }
   6887         } else
   6888 #endif
   6889         {
   6890             tbl_ptr->split_idx = (tbl_ptr->idx_max + 1)/2;
   6891         }
   6892         tbl_ptr->split_maxused = tbl_ptr->idx_min;
   6893         tbl_ptr->idx_maxused   = tbl_ptr->split_idx;
   6894     } else {
   6895         tbl_ptr->split_idx     = 0;
   6896         tbl_ptr->split_maxused = 0;
   6897     }
   6898     return;
   6899 }
   6900 #endif /* BCM_RIOT_SUPPORT || BCM_MULTI_LEVEL_ECMP_SUPPORT */
   6901 
   6902 /*
   6903  * Function:
   6904  *      bcm_xgs3_l3_ecmp_group_init
   6905  * Purpose:
   6906  *      Initialize internal L3 ecmp groups table.
   6907  * Parameters:
   6908  *      unit - SOC unit number.
   6909  * Returns:
   6910  *      BCM_E_XXX.
   6911  */
   6912 STATIC int
   6913 _bcm_xgs3_l3_ecmp_group_init(int unit)
   6914 {
   6915     int mem_sz;                 /* Ecmp group info memory size.          */
   6916     int max_grp_sz;             /* Maximum number of paths in ecmp group. */
   6917     _bcm_l3_tbl_t *tbl_ptr;     /* Ecmp table pointer.                   */
   6918     int idx;
   6919 #ifdef BCM_TRIDENT2_SUPPORT
   6920     int vp_lag_idx_offset = 0;
   6921 #endif
   6922 
   6923     max_grp_sz = BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
   6924     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
   6925 
   6926     /*
   6927      *  Calculate number of ecmp groups.
   6928      */
   6929     tbl_ptr->idx_min = 0;
   6930     if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) {
   6931          tbl_ptr->idx_max = soc_mem_index_count(unit, L3_ECMP_COUNTm) - 1;
   6932     } else {
   6933          tbl_ptr->idx_max = (BCM_XGS3_L3_ECMP_TBL_SIZE(unit) / max_grp_sz) - 1;
   6934     }
   6935 
   6936     tbl_ptr->idx_maxused = tbl_ptr->idx_min;
   6937 
   6938 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   6939     /* if there is split in table then set split ranges */
   6940     bcmi_xgs3_l3_ecmp_tbl_split_range_init(unit, tbl_ptr);
   6941     vp_lag_idx_offset                  = tbl_ptr->split_idx;
   6942     BCMI_L3_ECMP_OVERLAY_ENTRIES(unit) = vp_lag_idx_offset; 
   6943 #endif
   6944 
   6945     /*
   6946      * Keep track of ECMP table usage
   6947      */
   6948     mem_sz = (tbl_ptr->idx_max + 1) * sizeof(_bcm_l3_tbl_ext_t);
   6949     BCM_XGS3_L3_ALLOC(tbl_ptr->ext_arr, mem_sz, "l3_ecmp");
   6950     if (NULL == tbl_ptr->ext_arr) {
   6951         return (BCM_E_MEMORY);
   6952     }
   6953 
   6954     for (idx=0; idx < tbl_ptr->idx_max+1; idx++) {
   6955          BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, idx) = 0;
   6956     }
   6957 
   6958 #ifdef BCM_TOMAHAWK3_SUPPORT
   6959     if (soc_feature(unit, soc_feature_th3_style_dlb)) {
   6960         WRITE_ECMP_GROUP_DLB_ID_OFFSETr(unit,
   6961                                         BCM_TH3_L3_ECMP_DLB_START(unit));
   6962     }
   6963     if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) {
   6964         tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp);
   6965 
   6966         /*
   6967          *  Calculate number of ecmp groups.
   6968          */
   6969         tbl_ptr->idx_min = soc_mem_index_min(unit, ECMP_GROUP_HIERARCHICALm);
   6970 
   6971         tbl_ptr->idx_max = soc_mem_index_max(unit, ECMP_GROUP_HIERARCHICALm);
   6972         mem_sz = (soc_mem_index_count(unit, ECMP_GROUP_HIERARCHICALm)) * sizeof(_bcm_l3_tbl_ext_t);
   6973         BCM_XGS3_L3_ALLOC(tbl_ptr->ext_arr, mem_sz, "l3_ecmp");
   6974         if (NULL == tbl_ptr->ext_arr) {
   6975             return (BCM_E_MEMORY);
   6976         }
   6977 
   6978         for (idx=tbl_ptr->idx_min; idx <= tbl_ptr->idx_max; idx++) {
   6979              BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, idx) = 0;
   6980         }
   6981     }
   6982 #endif
   6983 
   6984 #ifdef BCM_TRIDENT2_SUPPORT
   6985     /* In Trident2, VP LAGs share the same table as ECMP group table.
   6986      * The first N entries are reserved for VP LAGs, where N is the
   6987      * value of the config property max_vp_lags.
   6988      */
   6989     if (soc_feature(unit, soc_feature_vp_lag)) {
   6990         int max_vp_lags;
   6991 
   6992         max_vp_lags = soc_property_get(unit, spn_MAX_VP_LAGS,
   6993                 soc_mem_index_count(unit, EGR_VPLAG_GROUPm));
   6994         for (idx=vp_lag_idx_offset; idx < max_vp_lags + vp_lag_idx_offset; 
   6995             idx++) {
   6996 
   6997             BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, idx) = 1;
   6998         }
   6999         if (max_vp_lags > 0) {
   7000             tbl_ptr->idx_maxused = max_vp_lags + vp_lag_idx_offset - 1;
   7001         }
   7002     }
   7003 #endif /* BCM_TRIDENT2_SUPPORT */
   7004 
   7005     return BCM_E_NONE;
   7006 }
   7007 
   7008 #ifdef BCM_TRIDENT3_SUPPORT
   7009 STATIC int
   7010 bcmi_l3_hecmp_group_bank_sel(int unit, uint32 first_lkup_sz)
   7011 {
   7012     uint32 bank_sel_reg_val  = 0;
   7013     uint32 ol_bank_bit_value = 0;
   7014 
   7015     if (first_lkup_sz) {
   7016         if (first_lkup_sz <= BCM_XGS3_L3_ECMP_MAX_GROUPS(unit)) {
   7017             ol_bank_bit_value = ((1 <<
   7018                                   ((first_lkup_sz / BCMI_L3_ECMP_GROUP_PER_BANK(unit)) +
   7019                                    ((first_lkup_sz % BCMI_L3_ECMP_GROUP_PER_BANK(unit)) ?
   7020                                     1 : 0))) - 1);
   7021         } else {
   7022             LOG_ERROR(BSL_LS_BCM_L3,
   7023                       (BSL_META_U
   7024                        (unit,
   7025                         "ERROR : l3 ecmp group (%d) > total l3 ecmp group(%d).\n"),
   7026                        first_lkup_sz,
   7027                        BCM_XGS3_L3_ECMP_MAX_GROUPS(unit)));
   7028             return BCM_E_CONFIG;
   7029         }
   7030     } else {
   7031         /* Maximum number of ECMP group and member banks is 8 in TD3 and 4
   7032          * in HX5.
   7033          */
   7034         ol_bank_bit_value = ((1 <<
   7035                               (soc_reg_field_length
   7036                                (unit,
   7037                                 INITIAL_ING_L3_ECMP_GROUP_BANK_SELr,
   7038                                 BANK_SELf) / 2)) - 1);
   7039     }
   7040 
   7041     soc_reg_field_set(unit, ING_L3_ECMP_GROUP_BANK_SELr,
   7042                       &bank_sel_reg_val, BANK_SELf, ol_bank_bit_value);
   7043     SOC_IF_ERROR_RETURN(WRITE_ING_L3_ECMP_GROUP_BANK_SELr
   7044                         (unit, bank_sel_reg_val));
   7045     soc_reg_field_set(unit, INITIAL_ING_L3_ECMP_GROUP_BANK_SELr,
   7046                       &bank_sel_reg_val, BANK_SELf, ol_bank_bit_value);
   7047     SOC_IF_ERROR_RETURN(WRITE_INITIAL_ING_L3_ECMP_GROUP_BANK_SELr
   7048                         (unit, bank_sel_reg_val));
   7049 
   7050     return BCM_E_NONE;
   7051 }
   7052 
   7053 STATIC int
   7054 bcmi_l3_hecmp_bank_sel(int unit, uint32 first_lkup_sz)
   7055 {
   7056     uint32 bank_sel_reg_val  = 0;
   7057     uint32 ol_bank_bit_value = 0;
   7058 
   7059     if (first_lkup_sz) {
   7060         if (first_lkup_sz <= (soc_mem_index_count(unit, L3_ECMPm))) {
   7061             ol_bank_bit_value = ((1 <<
   7062                                   ((first_lkup_sz / BCMI_L3_ECMP_PER_BANK(unit)) +
   7063                                    ((first_lkup_sz % BCMI_L3_ECMP_PER_BANK(unit)) ?
   7064                                     1 : 0))) - 1);
   7065         } else {
   7066             LOG_ERROR(BSL_LS_BCM_L3,
   7067                       (BSL_META_U
   7068                        (unit,
   7069                         "ERROR : l3 ecmp group (%d) > total l3 ecmp group(%d).\n"),
   7070                        first_lkup_sz,
   7071                        BCM_XGS3_L3_ECMP_MAX(unit)));
   7072             return BCM_E_CONFIG;
   7073         }
   7074     } else {
   7075         ol_bank_bit_value = ((1 <<
   7076                               (soc_reg_field_length
   7077                                (unit,
   7078                                 INITIAL_ING_L3_ECMP_BANK_SELr,
   7079                                 BANK_SELf) / 2)) - 1);
   7080     }
   7081 
   7082     soc_reg_field_set(unit, ING_L3_ECMP_BANK_SELr,
   7083                       &bank_sel_reg_val, BANK_SELf, ol_bank_bit_value);
   7084     SOC_IF_ERROR_RETURN(WRITE_ING_L3_ECMP_BANK_SELr
   7085                         (unit, bank_sel_reg_val));
   7086     soc_reg_field_set(unit, INITIAL_ING_L3_ECMP_BANK_SELr,
   7087                       &bank_sel_reg_val, BANK_SELf, ol_bank_bit_value);
   7088     SOC_IF_ERROR_RETURN(WRITE_INITIAL_ING_L3_ECMP_BANK_SELr
   7089                         (unit, bank_sel_reg_val));
   7090 
   7091     return BCM_E_NONE;
   7092 }
   7093 #endif
   7094 /*
   7095  * Function:
   7096  *      _bcm_xgs3_l3_ecmp_table_init
   7097  * Purpose:
   7098  *      Initialize HW ECMP table
   7099  * Parameters:
   7100  *      unit    - (IN)  SOC unit number.
   7101  * Returns:
   7102  *      BCM_E_XXX
   7103  */
   7104 STATIC int
   7105 _bcm_xgs3_l3_ecmp_table_init(int unit)
   7106 {
   7107     int idx;
   7108     int ecmp_max, mem_sz;                 /* Ecmp entries info memory size. */
   7109     _bcm_l3_tbl_t *tbl_ptr;     /* Ecmp table pointer. */
   7110 #if defined(BCM_TRIDENT3_SUPPORT)
   7111     _bcm_l3_bookkeeping_t *l3;
   7112 #endif /* BCM_TRIDENT3_SUPPORT */
   7113 
   7114 #ifdef BCM_TOMAHAWK_SUPPORT
   7115     uint32 rval = 0;
   7116 #endif /* BCM_TOMAHAWK_SUPPORT */
   7117 
   7118 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
   7119     if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) {
   7120         ecmp_mode_hierarchical = BCM_TD3_L3_ECMP_MODE_HIERARCHICAL;
   7121         ecmp_mode_single = BCM_TD3_L3_ECMP_MODE_SINGLE;
   7122     }
   7123 #endif /* BCM_TRIDENT3_SUPPORT */
   7124 
   7125     /*
   7126      * Keep track of ECMP table usage.
   7127      */
   7128     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp);
   7129     tbl_ptr->idx_min = 0;
   7130 
   7131     if (SOC_MEM_IS_VALID(unit, L3_ECMPm)) {
   7132         tbl_ptr->idx_max = soc_mem_index_count(unit, L3_ECMPm) - 1;
   7133     } else {
   7134         tbl_ptr->idx_max = -1;
   7135         BCM_XGS3_L3_TBL(unit, ecmp_grp).idx_max = -1;
   7136     }
   7137     ecmp_max = tbl_ptr->idx_max;
   7138     tbl_ptr->idx_maxused = tbl_ptr->idx_min;
   7139 
   7140 
   7141 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   7142     /* if there is split in table then set split tables */
   7143     bcmi_xgs3_l3_ecmp_tbl_split_range_init(unit, tbl_ptr);
   7144 #endif
   7145 
   7146     if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, ecmp)) &&
   7147         soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, ecmp))) {
   7148         BCM_XGS3_L3_ECMP_TBL_SIZE(unit) =
   7149             soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, ecmp));
   7150     } else {
   7151         BCM_XGS3_L3_ECMP_TBL_SIZE(unit) = 0;
   7152     }
   7153 
   7154 #if defined(BCM_TRIDENT3_SUPPORT)
   7155     l3 = &_bcm_l3_bk_info[unit];
   7156 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
   7157     if (soc_esw_ecmp_protected_enabled(unit)) {
   7158         int table_sz = 0;
   7159         int first_lkup_sz = 0;
   7160         int max_banks = 0;
   7161 
   7162         /* One bank reserved for protection write/read. */
   7163         max_banks = (BCMI_L3_ECMP_MAX_BANKS(unit) - 1);
   7164         table_sz = (BCMI_L3_ECMP_PER_BANK(unit) * max_banks);
   7165         if (l3->l3_ecmp_member_first_lkup_mem_size == 0) {
   7166             first_lkup_sz = ((max_banks / 2) * BCMI_L3_ECMP_PER_BANK(unit));
   7167             table_sz = (first_lkup_sz * 2);
   7168         } else {
   7169             first_lkup_sz = l3->l3_ecmp_member_first_lkup_mem_size;
   7170         }
   7171         tbl_ptr->split_idx = first_lkup_sz;
   7172         tbl_ptr->idx_max = (table_sz - 1);
   7173         tbl_ptr->idx_maxused   = tbl_ptr->split_idx;
   7174         BCM_XGS3_L3_ECMP_TBL_SIZE(unit) = table_sz;
   7175     }
   7176 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
   7177 #endif /* BCM_TRIDENT3_SUPPORT */
   7178 
   7179     if (0 == BCM_XGS3_L3_ECMP_TBL_SIZE(unit)) {
   7180         return (BCM_E_NONE);
   7181     }
   7182 
   7183     /* Default max ECMP to max allowed by hw */
   7184 #ifdef BCM_TOMAHAWK_SUPPORT
   7185     if (soc_feature(unit, soc_feature_hierarchical_ecmp) ||
   7186           soc_feature(unit, soc_feature_multi_level_ecmp)) {
   7187         rval = 0; 
   7188         BCM_IF_ERROR_RETURN(READ_ECMP_CONFIGr(unit, &rval));
   7189         BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode = rval;
   7190         /*
   7191          * On TH, max path is 16k only for resilient hashing.
   7192          * Set it to default of 128/1024 and use 16K only for RH.
   7193          */
   7194         if ((BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 
   7195                                          ecmp_mode_hierarchical)) {
   7196 #ifdef BCM_TOMAHAWK3_SUPPORT
   7197             if (soc_feature(unit, soc_feature_l3_ecmp_weighted)) {
   7198                 BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_max_paths =
   7199                                          BCM_TH3_L3_ECMP_WEIGHTED_MAX_PATHS;
   7200             } else
   7201 #endif
   7202             {
   7203             BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_max_paths = 128;
   7204             }
   7205         } else
   7206 #ifdef BCM_TOMAHAWK3_SUPPORT
   7207         if (soc_feature(unit, soc_feature_post_ifp_single_stage_ecmp)) {
   7208             BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_max_paths =
   7209                                     BCM_TH3_L3_ECMP_WEIGHTED_MAX_PATHS;
   7210         } else
   7211 #endif
   7212         {
   7213             BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_max_paths = 1024;
   7214         }
   7215 #ifdef BCM_TOMAHAWK3_SUPPORT
   7216         if (SOC_IS_TOMAHAWK3(unit)) {
   7217             BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_rh_max_paths = 32768;
   7218         } else
   7219 #endif
   7220         if (SOC_IS_TOMAHAWK(unit)) {
   7221             BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_rh_max_paths = 16384;
   7222         } else {
   7223             BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_rh_max_paths = 32768;
   7224         }
   7225     } else 
   7226 #endif /* BCM_TOMAHAWK_SUPPORT */
   7227     {
   7228         BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_max_paths =
   7229             BCM_XGS3_L3_ECMP_MAX(unit);
   7230     }
   7231 
   7232 #ifdef BCM_TOMAHAWK_SUPPORT
   7233     if (soc_feature(unit, soc_feature_fast_ecmp)) {
   7234         BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_max_paths = 128;
   7235         BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_rh_max_paths = 8192;
   7236     }
   7237 #endif /* BCM_TOMAHAWK_SUPPORT */
   7238 
   7239     /* Ecmp is not in use until first ecmp route added. */
   7240     BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_inuse = 0;
   7241 
   7242     /*
   7243      * Keep track of ECMP table usage
   7244      */
   7245     mem_sz = (ecmp_max + 1) * sizeof(_bcm_l3_tbl_ext_t);
   7246     BCM_XGS3_L3_ALLOC(tbl_ptr->ext_arr, mem_sz, "l3_ecmp");
   7247     if (NULL == tbl_ptr->ext_arr) {
   7248         return (BCM_E_MEMORY);
   7249     }
   7250 
   7251     for (idx=0; idx < ecmp_max+1; idx++) {
   7252          BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, idx) = 0;
   7253     }
   7254 
   7255 #ifdef BCM_TRIUMPH2_SUPPORT
   7256     if (soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf) ||
   7257             soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) {
   7258         BCM_IF_ERROR_RETURN(bcm_tr2_l3_ecmp_defragment_buffer_init(unit));
   7259     }
   7260 #endif /* BCM_TRIUMPH2_SUPPORT */
   7261 
   7262 #ifdef BCM_TRIUMPH2_SUPPORT
   7263     BCM_XGS3_L3_MAX_ECMP_MODE(unit) = (SOC_IS_TRIUMPH3(unit)) ? TRUE :
   7264                       soc_property_get(unit, spn_L3_MAX_ECMP_MODE, 0);
   7265     if (SOC_IS_TRIUMPH3(unit) ||
   7266         BCM_XGS3_L3_MAX_ECMP_MODE(unit)) {
   7267         BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit),
   7268                           BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) *
   7269                           sizeof(uint16),
   7270                           "Array for max paths per ecmp group");
   7271         if (NULL == BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)) {
   7272             return (BCM_E_MEMORY);
   7273         }
   7274 
   7275         /* Max size of all groups initialized to zero */
   7276         sal_memset(BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit), 0,
   7277                    BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) * sizeof(uint16));
   7278     }
   7279 #endif
   7280 
   7281     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_init(unit));
   7282 
   7283 #ifdef BCM_TRIUMPH3_SUPPORT
   7284     if (soc_feature(unit, soc_feature_ecmp_dlb)) {
   7285 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   7286         if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
   7287 #if defined(BCM_TOMAHAWK3_SUPPORT)
   7288             if (soc_feature(unit, soc_feature_th3_style_dlb)) {
   7289                 BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_dlb_max_paths =
   7290                                         BCM_TH3_L3_ECMP_DLB_MAX_PATHS;
   7291             } else
   7292 #endif
   7293             {
   7294                 BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_dlb_max_paths =
   7295                     soc_mem_field_length(unit, DLB_ECMP_GROUP_PORT_TO_MEMBERm,
   7296                                          ECMP_MEMBER_BITMAPf);
   7297             }
   7298             BCM_XGS3_L3_ALLOC(
   7299                 BCM_XGS3_L3_ECMP_DLB_MEMBER_PTR(unit),
   7300                 SHR_BITALLOCSIZE(BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2) *
   7301                 BCM_XGS3_L3_ECMP_MAX_GROUPS(unit),
   7302                 "DLB member bitmap per ecmp group");
   7303             if (NULL == BCM_XGS3_L3_ECMP_DLB_MEMBER_PTR(unit)) {
   7304                 return (BCM_E_MEMORY);
   7305             }
   7306             BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_init(unit));
   7307         } else
   7308 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/
   7309         {
   7310             BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_init(unit));
   7311         }
   7312     }
   7313 #endif /* BCM_TRIUMPH3_SUPPORT */
   7314 
   7315 #ifdef BCM_TRIDENT2_SUPPORT
   7316     if ((SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT3X(unit)) &&
   7317         soc_feature(unit, soc_feature_ecmp_resilient_hash)) {
   7318         BCM_IF_ERROR_RETURN(bcm_td2_ecmp_rh_init(unit));
   7319     }
   7320 #endif /* BCM_TRIDENT2_SUPPORT */
   7321 
   7322 #ifdef BCM_TOMAHAWK_SUPPORT
   7323     if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) {
   7324         BCM_IF_ERROR_RETURN(bcm_opt_ecmp_rh_init(unit));
   7325     }
   7326 #endif /* BCM_TOMAHAWK_SUPPORT */
   7327 
   7328 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
   7329     if (soc_feature(unit, soc_feature_dgm)) {
   7330         BCM_XGS3_L3_ALLOC(BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit),
   7331                           BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) *
   7332                           sizeof(uint16),
   7333                           "Array for alternate count per ecmp group");
   7334         if (NULL == BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit)) {
   7335             return (BCM_E_MEMORY);
   7336         }
   7337 
   7338         /* Max size of all groups initialized to zero */
   7339         sal_memset(BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit), 0,
   7340                    BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) * sizeof(uint16));
   7341     }
   7342 #endif /* BCM_TOMAHAWK2_SUPPORT */
   7343 #ifdef BCM_TRIDENT3_SUPPORT
   7344     if (SOC_IS_TRIDENT3X(unit)) {
   7345 
   7346         if (l3->l3_ecmp_levels == 2) {
   7347             BCM_IF_ERROR_RETURN(
   7348                 bcmi_l3_hecmp_group_bank_sel(unit,
   7349                                              l3->l3_ecmp_group_first_lkup_mem_size));
   7350 
   7351             BCM_IF_ERROR_RETURN(
   7352                 bcmi_l3_hecmp_bank_sel(unit,
   7353                                        l3->l3_ecmp_member_first_lkup_mem_size));
   7354 
   7355             BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_max_paths = 128;
   7356         }
   7357 
   7358 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
   7359         if (soc_feature(unit, soc_feature_l3_ecmp_protected_access)) {
   7360             int first_lkup_sz;
   7361             uint32 reg_val;
   7362             uint32 bank_sel_bmp;
   7363 
   7364             if (l3->l3_ecmp_levels == 2) {
   7365                 first_lkup_sz = tbl_ptr->split_idx;
   7366             } else {
   7367                 first_lkup_sz = 0;
   7368             }
   7369             bank_sel_bmp =
   7370                 ((1 << ((first_lkup_sz / BCMI_L3_ECMP_PER_BANK(unit)) +
   7371                         ((first_lkup_sz % BCMI_L3_ECMP_PER_BANK(unit)) ?
   7372                          1 : 0))) - 1);
   7373 
   7374             reg_val = 0;
   7375             soc_reg_field_set(unit, ING_L3_ECMP_BANK_SELr,
   7376                               &reg_val, BANK_SELf, bank_sel_bmp);
   7377             SOC_IF_ERROR_RETURN(WRITE_ING_L3_ECMP_BANK_SELr
   7378                                 (unit, reg_val));
   7379             soc_reg_field_set(unit, INITIAL_ING_L3_ECMP_BANK_SELr,
   7380                               &reg_val, BANK_SELf, bank_sel_bmp);
   7381             SOC_IF_ERROR_RETURN(WRITE_INITIAL_ING_L3_ECMP_BANK_SELr
   7382                                 (unit, reg_val));
   7383         }
   7384 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
   7385     }
   7386 #endif /* BCM_TRIDENT3_SUPPORT */
   7387 
   7388     return (BCM_E_NONE);
   7389 }
   7390 
   7391 
   7392 /*
   7393  * Function:
   7394  *      bcm_xgs3_l3_tables_init
   7395  * Purpose:
   7396  *      Initialize internal L3 tables and enable L3.
   7397  * Parameters:
   7398  *      unit - SOC unit number.
   7399  * Returns:
   7400  *      BCM_E_XXX.
   7401  */
   7402 int
   7403 bcm_xgs3_l3_tables_init(int unit)
   7404 {
   7405     int rv;                     /* Operation status.              */
   7406 
   7407     /* Allocate/zero unit software tables. */
   7408     if (NULL == l3_module_data[unit]) {
   7409         BCM_XGS3_L3_ALLOC(l3_module_data[unit], sizeof(_bcm_l3_module_data_t),
   7410                           "l3_module_data");
   7411         if (NULL == l3_module_data[unit]) {
   7412             return (BCM_E_MEMORY);
   7413         }
   7414 
   7415         BCM_XGS3_L3_ALLOC(l3_module_data[unit]->l3_ecmp_info.ecmp_flags,
   7416                           sizeof(int) * BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit),
   7417                           "ECMP info flags");
   7418         if (NULL == l3_module_data[unit]->l3_ecmp_info.ecmp_flags) {
   7419             return (BCM_E_MEMORY);
   7420         }
   7421     } else {
   7422         l3_module_data[unit]->l3_op_flags = 0;
   7423         sal_memset(l3_module_data[unit]->l3_ecmp_info.ecmp_flags, 0,
   7424                    sizeof(int) * BCM_XGS3_L3_ECMP_MAX_GROUPS_2(unit));
   7425     }
   7426 
   7427     /*
   7428      * Get hardware tables size.
   7429      */
   7430     /* Init hw calls & memory addresses. */
   7431     rv = _bcm_xgs3_l3_hw_op_init(unit);
   7432     if (BCM_FAILURE(rv)) {
   7433         _bcm_xgs3_l3_free_resource(unit);
   7434         return rv;
   7435     }
   7436     /* Flush all the tables in hw. */
   7437     if (!SAL_BOOT_QUICKTURN) {
   7438         if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_clear_all)) {
   7439             BCM_XGS3_L3_MODULE_LOCK(unit);
   7440             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_clear_all) (unit);
   7441             BCM_XGS3_L3_MODULE_UNLOCK(unit);
   7442             if (BCM_FAILURE(rv)) {
   7443                 _bcm_xgs3_l3_free_resource(unit);
   7444                 return rv;
   7445             }
   7446         }
   7447     }
   7448 
   7449 #ifdef BCM_TRIDENT_SUPPORT
   7450             if (soc_feature(unit, soc_feature_trill) ||
   7451                 soc_feature(unit, soc_feature_l2gre) ||
   7452                 soc_feature(unit, soc_feature_vxlan)) {
   7453                    rv = _bcm_xgs3_trunk_nh_store_init (unit);
   7454                    if (BCM_FAILURE(rv)) {
   7455                       _bcm_xgs3_l3_free_resource(unit);
   7456                       return rv;
   7457                    }
   7458             }
   7459 #endif /* BCM_TRIDENT_SUPPORT */
   7460 
   7461 
   7462 
   7463 #ifdef BCM_TRIDENT2_SUPPORT
   7464     if (soc_feature(unit, soc_feature_l3_ip4_options_profile)) {
   7465        rv = _bcm_td2_l3_ip4_options_profile_init(unit);
   7466        if (BCM_FAILURE(rv)) {
   7467            _bcm_xgs3_l3_free_resource(unit);
   7468            return rv;
   7469        }
   7470     }
   7471     if (soc_feature(unit, soc_feature_nat)) {
   7472         rv = _bcm_esw_l3_nat_init(unit);
   7473         if (BCM_FAILURE(rv)) {
   7474             _bcm_xgs3_l3_free_resource(unit);
   7475             return rv;
   7476         }
   7477     }
   7478 #endif /* BCM_TRIDENT2_SUPPORT */
   7479 
   7480     /* Egress L3 interface table init. */
   7481     rv = _bcm_xgs3_l3_intf_init(unit);
   7482     if (BCM_FAILURE(rv)) {
   7483         _bcm_xgs3_l3_free_resource(unit);
   7484         return rv;
   7485     }
   7486 
   7487     /* Ingress L3 interface table init. */
   7488     rv = _bcm_xgs3_l3_ing_intf_init(unit);
   7489     if (BCM_FAILURE(rv)) {
   7490         _bcm_xgs3_l3_free_resource(unit);
   7491         return rv;
   7492     }
   7493 
   7494     /* Next hop table init.  */
   7495     rv = _bcm_xgs3_l3_nh_init(unit);
   7496     if (BCM_FAILURE(rv)) {
   7497         _bcm_xgs3_l3_free_resource(unit);
   7498         return rv;
   7499     }
   7500 
   7501     /* L3 host table init.   */
   7502     rv = _bcm_xgs3_l3_table_init(unit);
   7503     if (BCM_FAILURE(rv)) {
   7504         _bcm_xgs3_l3_free_resource(unit);
   7505         return rv;
   7506     }
   7507 
   7508     /* ECMP groups table init. */
   7509     rv = _bcm_xgs3_l3_ecmp_table_init(unit);
   7510     if (BCM_FAILURE(rv)) {
   7511         _bcm_xgs3_l3_free_resource(unit);
   7512         return rv;
   7513     }
   7514 
   7515     /* Defip table init. */
   7516     rv = _bcm_xgs3_defip_table_init(unit);
   7517     if (BCM_FAILURE(rv)) {
   7518         _bcm_xgs3_l3_free_resource(unit);
   7519         return rv;
   7520     }
   7521 
   7522     
   7523     if(!soc_feature(unit, soc_feature_no_tunnel)) {
   7524 
   7525         /* Tunnels terminator table  init. */
   7526         rv = soc_tunnel_term_init(unit);
   7527         if (BCM_FAILURE(rv)) {
   7528             _bcm_xgs3_l3_free_resource(unit);
   7529             return rv;
   7530         }
   7531 
   7532         /* Tunnels initiator table  init. */
   7533         rv = _bcm_xgs3_l3_tnl_initiator_init(unit);
   7534         if (BCM_FAILURE(rv)) {
   7535             _bcm_xgs3_l3_free_resource(unit);
   7536             return rv;
   7537         }
   7538         if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
   7539 #if defined(BCM_TOMAHAWK3_SUPPORT)
   7540             rv = _bcm_tnl_port_bitmap_profile_init(unit);
   7541             if (BCM_FAILURE(rv)) {
   7542                 _bcm_xgs3_l3_free_resource(unit);
   7543                 return rv;
   7544             }
   7545 #endif
   7546         }
   7547 
   7548 #if defined(BCM_TRIDENT3_SUPPORT)
   7549         if (SOC_IS_TRIDENT3X(unit)) {
   7550             rv = _bcm_td3_tunnel_default_vlan_profile_init(unit);
   7551             if (BCM_FAILURE(rv)) {
   7552                 _bcm_xgs3_l3_free_resource(unit);
   7553                 return rv;
   7554             }
   7555         }
   7556 #endif
   7557 
   7558     } else { /* !SOC_IS_HURRICANE && !SOC_IS_GREYHOUND */
   7559         if (soc_feature(unit, soc_feature_vxlan_lite)) {
   7560             /* Tunnels initiator table  init. */
   7561             rv = _bcm_xgs3_l3_tnl_initiator_init(unit);
   7562             if (BCM_FAILURE(rv)) {
   7563                 _bcm_xgs3_l3_free_resource(unit);
   7564                 return rv;
   7565             }
   7566         }
   7567     }
   7568 
   7569     /* Tunnels dscp table  init. */
   7570     rv = _bcm_xgs3_l3_tnl_dscp_init(unit);
   7571     if (BCM_FAILURE(rv)) {
   7572         _bcm_xgs3_l3_free_resource(unit);
   7573         return rv;
   7574     }
   7575 
   7576     /* Adjacent mac table init. */
   7577     rv = _bcm_xgs3_l3_adj_mac_init(unit);
   7578     if (BCM_FAILURE(rv)) {
   7579         _bcm_xgs3_l3_free_resource(unit);
   7580         return rv;
   7581     }
   7582 
   7583     /* Reset auxiliary counters. */
   7584     BCM_XGS3_L3_CNTRS_RESET(unit);
   7585 
   7586 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \
   7587     defined(BCM_HAWKEYE_SUPPORT)
   7588     if (soc_feature(unit, soc_feature_fp_based_routing)) {
   7589         rv = _bcm_rp_l3_init(unit);
   7590         if (BCM_FAILURE(rv)) {
   7591             _bcm_xgs3_l3_free_resource(unit);
   7592             return rv;
   7593         }
   7594     }
   7595 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */
   7596 
   7597     /* Reserve BLACK_HOLE entry to Drop packets */
   7598     rv = _bcm_xgs3_l3_black_hole_nh_setup(unit);
   7599     if (BCM_FAILURE(rv)) {
   7600         _bcm_xgs3_l3_free_resource(unit);
   7601         return rv;
   7602     }
   7603 
   7604     /*
   7605      * Reserve the entry in L3 NextHop table to L2 switch packet CPU
   7606      */
   7607     rv = _bcm_xgs3_l3_l2cpu_nh_setup(unit);
   7608     if (BCM_FAILURE(rv)) {
   7609         _bcm_xgs3_l3_free_resource(unit);
   7610         return rv;
   7611     }
   7612 
   7613     /* Register a call back function to update modid */
   7614     rv = soc_event_register(unit, _bcm_xgs3_l3_l2cpu_nh_cb, NULL);
   7615     if (BCM_FAILURE(rv)) {
   7616         _bcm_xgs3_l3_free_resource(unit);
   7617         return rv;
   7618     }
   7619 
   7620 #if defined(BCM_TRX_SUPPORT)
   7621     if (soc_feature(unit, soc_feature_virtual_switching)) {
   7622         rv = _bcm_virtual_init(unit, SOURCE_VPm, VFIm);
   7623         if (BCM_FAILURE(rv)) {
   7624             _bcm_xgs3_l3_free_resource(unit);
   7625             return rv;
   7626         }
   7627     }
   7628 #endif /* BCM_TRX_SUPPORT */
   7629 
   7630 #if defined(BCM_TRIDENT_SUPPORT)
   7631     if (SOC_IS_TRIDENT(unit)
   7632 #if defined(BCM_TRIDENT2_SUPPORT)
   7633        || SOC_IS_TRIDENT2X(unit)
   7634 #endif
   7635        || SOC_IS_TOMAHAWKX(unit)
   7636 #if defined(BCM_TRIDENT3_SUPPORT)
   7637        || SOC_IS_TRIDENT3X(unit)
   7638 #endif
   7639       ) {
   7640        rv = _bcm_td_l3_routed_int_pri_init(unit);
   7641        if (BCM_FAILURE(rv)) {
   7642            _bcm_xgs3_l3_free_resource(unit);
   7643            return rv;
   7644        }
   7645     }
   7646 #endif /* BCM_TRIDENT_SUPPORT */
   7647 
   7648 #if defined(BCM_TRIUMPH3_SUPPORT)
   7649     if (SOC_IS_TRIUMPH3(unit)) {
   7650         if (BCM_TR3_ESM_HOST_TBL_PRESENT(unit)) {
   7651             rv = _bcm_tr3_esm_host_tbl_init(unit);
   7652             if (BCM_FAILURE(rv)) {
   7653                 _bcm_xgs3_l3_free_resource(unit);
   7654                 return rv;
   7655             }
   7656         }
   7657        rv = _bcm_td_l3_routed_int_pri_init(unit);
   7658        if (BCM_FAILURE(rv)) {
   7659            _bcm_xgs3_l3_free_resource(unit);
   7660            return rv;
   7661        }
   7662     }
   7663 #endif /* BCM_TRIUMPH3_SUPPORT */
   7664 
   7665 #if defined(BCM_TOMAHAWK_SUPPORT)
   7666     if (BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) {
   7667         rv = _bcm_th_macda_oui_profile_init(unit);
   7668         if (BCM_FAILURE(rv)) {
   7669             _bcm_th_macda_oui_profile_deinit(unit);
   7670             _bcm_xgs3_l3_free_resource(unit);
   7671             return rv;
   7672         }
   7673         rv = _bcm_th_vntag_etag_profile_init(unit);
   7674         if (BCM_FAILURE(rv)) {
   7675             _bcm_th_vntag_etag_profile_deinit(unit);
   7676             _bcm_xgs3_l3_free_resource(unit);
   7677             return rv;
   7678         }
   7679     }
   7680 #endif /* BCM_TOMAHAWK_SUPPORT */
   7681 
   7682 #if defined(BCM_RIOT_SUPPORT)
   7683     if (soc_feature(unit, soc_feature_riot)) {
   7684         rv = _bcm_td2p_macda_oui_profile_init(unit);
   7685         if (BCM_FAILURE(rv)) {
   7686             _bcm_xgs3_l3_free_resource(unit);
   7687             return rv;
   7688         }
   7689     }
   7690 #endif /* BCM_RIOT_SUPPORT */
   7691 
   7692 #if defined(BCM_TRIDENT3_SUPPORT) && defined(BCM_WARM_BOOT_SUPPORT)
   7693     if (soc_feature(unit, soc_feature_vfi_switched_l2_change_fields)) {
   7694         if (SOC_WARM_BOOT(unit)) {
   7695             rv = _bcm_td3_l2_change_fields_reinit(unit);
   7696             if (BCM_FAILURE(rv)) {
   7697                 return rv;
   7698             }
   7699         }
   7700     }
   7701 #endif
   7702     /* Set "resources allocated" flag. */
   7703     BCM_XGS3_L3_INITIALIZED(unit) = TRUE;
   7704 
   7705     /* Enable routing on all ports. */
   7706     rv = bcm_xgs3_l3_enable(unit, TRUE);
   7707     if (BCM_FAILURE(rv)) {
   7708         _bcm_xgs3_l3_free_resource(unit);
   7709         return rv;
   7710     }
   7711 #ifdef BCM_TRIDENT3_SUPPORT
   7712     sal_memset(ecmp_grp_enhanced_hashing[unit], 0, 4096);
   7713 #endif
   7714 
   7715     return (BCM_E_NONE);
   7716 }
   7717 
   7718 /*
   7719  * Function:
   7720  *      bcm_xgs3_l3_tables_cleanup
   7721  * Purpose:
   7722  *      Disable L3 functionality and cleanup internal L3 tables.
   7723  * Parameters:
   7724  *      unit - SOC unit number.
   7725  * Returns:
   7726  *      BCM_E_XXX.
   7727  */
   7728 int
   7729 bcm_xgs3_l3_tables_cleanup(int unit)
   7730 {
   7731     /* Disable routing on all ports. */
   7732     if (0 == SOC_HW_ACCESS_DISABLE(unit)) {
   7733         bcm_xgs3_l3_enable(unit, FALSE);
   7734     }
   7735 
   7736 
   7737     /* Free allocated resources. */
   7738     if (BCM_XGS3_L3_INITIALIZED(unit)) {
   7739         _bcm_xgs3_l3_free_resource(unit);
   7740 
   7741         /* Reset auxiliary counters. */
   7742         BCM_XGS3_L3_CNTRS_RESET(unit);
   7743 
   7744         BCM_XGS3_L3_INITIALIZED(unit) = FALSE;
   7745 
   7746         /* Unregister call back function */
   7747          soc_event_unregister(unit, _bcm_xgs3_l3_l2cpu_nh_cb, NULL);
   7748     }
   7749     return (BCM_E_NONE);
   7750 }
   7751 
   7752 
   7753 
   7754 /*
   7755  * Function:
   7756  *      bcm_xgs3_l3_intf_get
   7757  * Purpose:
   7758  *      Get an entry from L3 interface table.
   7759  * Parameters:
   7760  *      unit - SOC unit number.
   7761  *      intf_info - Pointer to memory for interface information.
   7762  * Returns:
   7763  *      BCM_E_XXX
   7764  */
   7765 int
   7766 bcm_xgs3_l3_intf_get(int unit, _bcm_l3_intf_cfg_t *intf_info)
   7767 {
   7768     bcm_l2_addr_t l2_addr;       /* Layer 2 address for interface. */
   7769     int rv;
   7770 
   7771     /*  Make sure module was initialized. */
   7772     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   7773         return (BCM_E_INIT);
   7774     }
   7775 
   7776     /* Input parameters check. */
   7777     if (NULL == intf_info) {
   7778         return (BCM_E_PARAM);
   7779     }
   7780 
   7781     /* Make sure ifindex is valid & interface is used. */
   7782     if (intf_info->l3i_index >= BCM_XGS3_L3_IF_TBL_SIZE(unit) ||
   7783         !BCM_L3_INTF_USED_GET(unit, intf_info->l3i_index)) {
   7784         return (BCM_E_NOT_FOUND);
   7785     }
   7786 
   7787     /* Make sure hw call pointer was initialized. */
   7788     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, if_get)) {
   7789         return (BCM_E_UNAVAIL);
   7790     }
   7791 
   7792     /* Read interface from hardware. */
   7793     BCM_XGS3_L3_MODULE_LOCK(unit);
   7794     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, intf_info);
   7795     BCM_XGS3_L3_MODULE_UNLOCK(unit);
   7796     BCM_IF_ERROR_RETURN(rv);
   7797 
   7798     /* Restore 'BCM_L3_ADD_TO_ARL' flag if found in L2/MY_STATION tables */
   7799     bcm_l2_addr_t_init(&l2_addr, intf_info->l3i_mac_addr, intf_info->l3i_vid);
   7800     if (BCM_E_NONE == bcm_esw_l2_addr_get(unit, intf_info->l3i_mac_addr,
   7801                             intf_info->l3i_vid, &l2_addr)) {
   7802         if (l2_addr.flags & BCM_L2_L3LOOKUP) {
   7803             intf_info->l3i_flags |= BCM_L3_ADD_TO_ARL;
   7804         }
   7805     }
   7806 
   7807     /* Read vrf info from hardware. */
   7808     if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_vrf_get)) {
   7809 
   7810         BCM_XGS3_L3_MODULE_LOCK(unit);
   7811         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_vrf_get) (unit, intf_info);
   7812         BCM_XGS3_L3_MODULE_UNLOCK(unit);
   7813         BCM_IF_ERROR_RETURN(rv);
   7814 
   7815     }
   7816 
   7817     /* Get interface group id . */
   7818     if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_group_get)) {
   7819         BCM_XGS3_L3_MODULE_LOCK(unit);
   7820         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_group_get) (unit, intf_info);
   7821         BCM_XGS3_L3_MODULE_UNLOCK(unit);
   7822         BCM_IF_ERROR_RETURN(rv);
   7823     }
   7824 
   7825     return (BCM_E_NONE);
   7826 }
   7827 
   7828 /*
   7829  * Function:
   7830  *      _bcm_xgs3_l3_intf_lookup
   7831  * Purpose:
   7832  *      Get first entry from L3 interface table matching vlan id & mac.
   7833  * Parameters:
   7834  *      unit      - (IN)SOC unit number.
   7835  *      intf_info - (IN/OUT)Pointer to memory for interface information.
   7836  *      vid       - (IN) Key vlan id.
   7837  *      mac       - (IN) mac address.
   7838  * Returns:
   7839  *      BCM_E_XXX
   7840  */
   7841 int
   7842 _bcm_xgs3_l3_intf_lookup(int unit, _bcm_l3_intf_cfg_t *intf_info,
   7843                          bcm_vlan_t vid, bcm_mac_t mac)
   7844 {
   7845     int idx;                    /* Iteration index.             */
   7846     int max_lkup_cnt;           /* Number of active interfaces, */
   7847     int index_min;              /* First interface entry index. */
   7848     int index_max;              /* Last interface entry index.  */
   7849     int rv;
   7850     _bcm_l3_intf_cfg_t intf_info_in;
   7851 
   7852     /* Make sure hw call pointer was initialized. */
   7853     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, if_get)) {
   7854         return (BCM_E_UNAVAIL);
   7855     }
   7856     /* make a copy of input intf_info */
   7857     sal_memcpy(&intf_info_in, intf_info, sizeof(_bcm_l3_intf_cfg_t));
   7858 
   7859     /* Get interface table start & end index. */
   7860     index_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, intf));
   7861     index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, intf));
   7862 
   7863     /* Don't iterate beyond number of active interfaces. */
   7864     max_lkup_cnt = BCM_XGS3_L3_IF_COUNT(unit);
   7865     if (max_lkup_cnt <= 0) {
   7866         return (BCM_E_NOT_FOUND);
   7867     }
   7868 
   7869     /* Loop over all valid interfaces. */
   7870     for (idx = index_min; idx <= index_max; idx++) {
   7871         if (BCM_L3_INTF_USED_GET(unit, idx)) {
   7872             /* Read interface from hardware. */
   7873             sal_memcpy(intf_info, &intf_info_in, sizeof(_bcm_l3_intf_cfg_t));
   7874             intf_info->l3i_index = idx;
   7875             BCM_XGS3_L3_MODULE_LOCK(unit);
   7876             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, intf_info);
   7877             BCM_XGS3_L3_MODULE_UNLOCK(unit);
   7878             BCM_IF_ERROR_RETURN(rv);
   7879 
   7880             /* Check for match. */
   7881             if (intf_info->l3i_vid == vid) {
   7882                 /* Search by VID only. */
   7883                 if (NULL == mac) {
   7884                     break;
   7885                 }
   7886                 /* Search by MAC & VID */
   7887                 if (sal_memcmp(mac, intf_info->l3i_mac_addr,
   7888                                sizeof(bcm_mac_t)) == 0) {
   7889                     break;
   7890                 }               /* Mac match. */
   7891             }
   7892             /* Vid match. */
   7893             /* Decrement number of interface to search. */
   7894             max_lkup_cnt--;
   7895             if (!max_lkup_cnt) {
   7896                 break;
   7897             }
   7898         }                       /* Interface is active. */
   7899     }                           /* Loop over interface table. */
   7900 
   7901     if (!max_lkup_cnt || (idx == BCM_XGS3_L3_IF_TBL_SIZE(unit))) {
   7902         return (BCM_E_NOT_FOUND);
   7903     }
   7904 
   7905     /* Get vrf info if available. */
   7906     if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_vrf_get)) {
   7907         BCM_XGS3_L3_MODULE_LOCK(unit);
   7908         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_vrf_get) (unit, intf_info);
   7909         BCM_XGS3_L3_MODULE_UNLOCK(unit);
   7910         BCM_IF_ERROR_RETURN(rv);
   7911     }
   7912     return (BCM_E_NONE);
   7913 }
   7914 
   7915 /*
   7916  * Function:
   7917  *      bcm_xgs3_l3_intf_get_by_vid
   7918  * Purpose:
   7919  *      Get first entry from L3 interface table matching vlan id.
   7920  * Parameters:
   7921  *      unit      - (IN)SOC unit number.
   7922  *      intf_info - (IN/OUT)Pointer to memory for interface information.
   7923  * Returns:
   7924  *      BCM_E_XXX
   7925  */
   7926 int
   7927 bcm_xgs3_l3_intf_get_by_vid(int unit, _bcm_l3_intf_cfg_t *intf_info)
   7928 {
   7929     /*  Make sure module was initialized. */
   7930     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   7931         return (BCM_E_INIT);
   7932     }
   7933 
   7934     /* Input parameters check. */
   7935     if (NULL == intf_info) {
   7936         return (BCM_E_PARAM);
   7937     }
   7938     /*  Perform lookup by VID. */
   7939     return _bcm_xgs3_l3_intf_lookup(unit, intf_info, intf_info->l3i_vid, NULL);
   7940 }
   7941 
   7942 
   7943 /*
   7944  * Function:
   7945  *      _bcm_xgs3_l3_intf_l2_addr_set
   7946  * Purpose:
   7947  *      Set interface mac address in l2 table.
   7948  * Parameters:
   7949  *      unit      - (IN) SOC unit number.
   7950  *      intf_info - (IN) Interface information.
   7951  * Returns:
   7952  *      BCM_E_XXX
   7953  */
   7954 STATIC int
   7955 _bcm_xgs3_l3_intf_l2_addr_set(int unit, _bcm_l3_intf_cfg_t *intf_info)
   7956 {
   7957     bcm_l2_addr_t l2addr;       /* Layer 2 address for interface. */
   7958     int rv = BCM_E_NONE;                     /* Operation return status.       */
   7959 
   7960     /* Set l2 address info. */
   7961     bcm_l2_addr_t_init(&l2addr, intf_info->l3i_mac_addr, intf_info->l3i_vid);
   7962 
   7963 #if defined(BCM_MIRAGE_SUPPORT)
   7964     if (soc_feature(unit, soc_feature_fp_routing_mirage)) {
   7965         /* Set l2 entry flags. */
   7966         l2addr.flags = BCM_L2_STATIC | BCM_L2_REPLACE_DYNAMIC;
   7967 
   7968         /* Set l2 entry port to CPU port. */
   7969         l2addr.port = BCM_MIRAGE_L3_PORT;
   7970     } else
   7971 #endif /* BCM_MIRAGE_SUPPORT */
   7972     {
   7973         /* Set l2 entry flags. */
   7974         l2addr.flags = BCM_L2_L3LOOKUP | BCM_L2_STATIC | BCM_L2_REPLACE_DYNAMIC;
   7975 
   7976         /* Set l2 entry port to CPU port. */
   7977         l2addr.port = CMIC_PORT(unit);
   7978     }
   7979 
   7980     /* Set l2 entry module id to local module. */
   7981     BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &l2addr.modid));
   7982 
   7983     /* Overwrite existing entry if any. */
   7984     bcm_esw_l2_addr_delete(unit, intf_info->l3i_mac_addr, intf_info->l3i_vid);
   7985 
   7986     /* Add entry to l2 table. */
   7987     rv = bcm_esw_l2_addr_add(unit, &l2addr);
   7988 
   7989     /* Set mac address installed indicator. */
   7990     if (rv == BCM_E_NONE) {
   7991         BCM_L3_INTF_ARL_SET(unit, intf_info->l3i_index);
   7992     }
   7993     return rv;
   7994 }
   7995 
   7996 /*
   7997  * Function:
   7998  *      _bcm_xgs3_l3_intf_create
   7999  * Purpose:
   8000  *      Create l3 interface.
   8001  * Parameters:
   8002  *      unit      - (IN) SOC unit number.
   8003  *      intf_info - (IN) Interface information.
   8004  * Returns:
   8005  *      BCM_E_XXX
   8006  */
   8007 
   8008 STATIC int
   8009 _bcm_xgs3_l3_intf_create(int unit, _bcm_l3_intf_cfg_t *intf_info)
   8010 {
   8011     int rv, rv1;
   8012     int ingress_map_mode = 0;
   8013     int inc_vlan_vrf_ref_count = FALSE;
   8014 
   8015     /* Add interface to hardware. */
   8016     if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_add)) {
   8017         BCM_XGS3_L3_MODULE_LOCK(unit);
   8018         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_add) (unit, intf_info);
   8019         BCM_XGS3_L3_MODULE_UNLOCK(unit);
   8020         BCM_IF_ERROR_RETURN(rv);
   8021     }
   8022 
   8023     /* Write to interface group table. */
   8024     if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_group_set)) {
   8025         BCM_XGS3_L3_MODULE_LOCK(unit);
   8026         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_group_set) (unit, intf_info);
   8027         BCM_XGS3_L3_MODULE_UNLOCK(unit);
   8028         BCM_IF_ERROR_RETURN(rv);
   8029     }
   8030 
   8031     /* Set VRF_VFI table for primary interfaces. */
   8032     if ((!(intf_info->l3i_flags & BCM_L3_SECONDARY)) &&
   8033          (intf_info->l3i_vrf != BCM_L3_VRF_INVALID)) {
   8034         if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_vrf_bind)) {
   8035             BCM_XGS3_L3_MODULE_LOCK(unit);
   8036             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_vrf_bind) (unit, intf_info);
   8037             BCM_XGS3_L3_MODULE_UNLOCK(unit);
   8038             BCM_IF_ERROR_RETURN(rv);
   8039             inc_vlan_vrf_ref_count = TRUE;
   8040         }
   8041     }
   8042 
   8043 #if defined(BCM_TRIDENT2_SUPPORT)
   8044     if (soc_feature(unit, soc_feature_nat) 
   8045 #ifdef BCM_RIOT_SUPPORT
   8046         && (!(BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)))
   8047 #endif
   8048     ) {
   8049         rv = _bcm_fb_l3_intf_nat_realm_id_set(unit, intf_info);
   8050         BCM_IF_ERROR_RETURN(rv);
   8051         
   8052         if (intf_info->l3i_flags & BCM_L3_SRC_DST_NAT_REALM_ID) {
   8053             BCM_IF_ERROR_RETURN(
   8054                 _bcm_td2_nh_nat_id_update_by_l3_intf(
   8055                     unit, intf_info->l3i_index, intf_info->l3i_nat_realm_id));
   8056         }
   8057     }
   8058 
   8059     if (!(BCM_XGS3_L3_INGRESS_MODE_ISSET(unit) &&
   8060           BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit))) {
   8061         if (soc_feature(unit, soc_feature_l3_ip4_options_profile)
   8062 #ifdef BCM_RIOT_SUPPORT
   8063             && (!(BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)))
   8064 #endif 
   8065         ) {
   8066             rv = _bcm_td2_l3_iif_ip4_options_profile_index_set(unit, intf_info);
   8067             BCM_IF_ERROR_RETURN(rv);
   8068         }
   8069     }
   8070 #endif
   8071 #if defined(BCM_TRIUMPH_SUPPORT)
   8072     /* Check if L3 Ingress Interface mode not set */
   8073     if (!(BCM_XGS3_L3_INGRESS_MODE_ISSET(unit))) {
   8074         if (SOC_MEM_FIELD_VALID(unit, L3_IIFm, ALLOW_GLOBAL_ROUTEf) &&
   8075             intf_info->l3i_vid != 0) {
   8076             /* Check if L3 Ingress Interface Map mode not set */
   8077             if (!(BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit))) {
   8078                 rv = _bcm_tr_l3_intf_global_route_enable_set(unit,
   8079                                                              intf_info->l3i_vid,
   8080                                                              1);
   8081                 BCM_IF_ERROR_RETURN(rv);
   8082             }
   8083         }
   8084     }
   8085 #endif /* BCM_TRIUMPH_SUPPORT */
   8086 
   8087     /* Add interface layer 2 address if required. */
   8088     if (intf_info->l3i_flags & BCM_L3_ADD_TO_ARL) {
   8089         if (BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_DISABLE_ADD_TO_ARL)) {
   8090             LOG_ERROR(BSL_LS_BCM_L3,
   8091                       (BSL_META_U(unit,
   8092                                   "Use of BCM_L3_ADD_TO_ARL flag is not allowed in l3 intf create \n")));
   8093             return BCM_E_CONFIG;
   8094         }
   8095         rv = _bcm_xgs3_l3_intf_l2_addr_set(unit, intf_info);
   8096 
   8097         if (BCM_FAILURE(rv)) { /* Add to ARL failed, cleanup L3 intf */
   8098             if ((!(intf_info->l3i_flags & BCM_L3_SECONDARY))
   8099                 && (intf_info->l3i_vrf != BCM_L3_VRF_INVALID)) {
   8100                 if (!BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, 
   8101                                 ing_intf), intf_info->l3i_vid)) {
   8102                     /* Ref count on VLAN VRF is zero, hence
   8103                      * Clear VRF_VFI table for primary interfaces. */
   8104                     if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_vrf_unbind)) {
   8105                         BCM_XGS3_L3_MODULE_LOCK(unit);
   8106                         rv1 = BCM_XGS3_L3_HWCALL_EXEC(unit, 
   8107                                 if_vrf_unbind) (unit, intf_info);
   8108                         BCM_XGS3_L3_MODULE_UNLOCK(unit);
   8109                         BCM_IF_ERROR_RETURN(rv1);
   8110                     }
   8111                 }
   8112             }
   8113 
   8114             /* Clear ingress & egress filter interface group table. */
   8115             if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_group_set)) {
   8116                 intf_info->l3i_group = 0;
   8117                 BCM_XGS3_L3_MODULE_LOCK(unit);
   8118                 rv1 = BCM_XGS3_L3_HWCALL_EXEC(unit, if_group_set) (unit, intf_info);
   8119                 BCM_XGS3_L3_MODULE_UNLOCK(unit);
   8120                 BCM_IF_ERROR_RETURN(rv1);
   8121             }
   8122 
   8123             /* Remove the interface. */
   8124             if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_del)) {
   8125                 BCM_XGS3_L3_MODULE_LOCK(unit);
   8126                 rv1 = BCM_XGS3_L3_HWCALL_EXEC(unit, if_del) (unit, intf_info->l3i_index);
   8127                 BCM_XGS3_L3_MODULE_UNLOCK(unit);
   8128                 BCM_IF_ERROR_RETURN(rv1);
   8129             }
   8130 
   8131             return rv;
   8132         }
   8133     }
   8134 
   8135     /* Mark interface "inuse" in bitmap. */
   8136     if (!BCM_L3_INTF_USED_GET(unit, intf_info->l3i_index)) {
   8137         BCM_L3_INTF_USED_SET(unit, intf_info->l3i_index);
   8138     }
   8139 
   8140     if (inc_vlan_vrf_ref_count) {
   8141 #ifdef BCM_TRIUMPH_SUPPORT
   8142         if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
   8143             BCM_IF_ERROR_RETURN
   8144                 (bcm_xgs3_l3_ingress_intf_map_get(unit, &ingress_map_mode));
   8145         }
   8146 #endif
   8147         if (!ingress_map_mode ||
   8148                 SOC_MEM_FIELD_VALID(unit, VLAN_TABm, VRF_IDf)) {
   8149             /* Increment ref count on related VLAN VRF here */
   8150             BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ing_intf),
   8151                     intf_info->l3i_vid, _BCM_SINGLE_WIDE);
   8152         }
   8153     }
   8154     return (BCM_E_NONE);
   8155 }
   8156 
   8157 /*
   8158  * Function:
   8159  *      _bcm_xgs3_egress_l3_intf_id_free
   8160  * Purpose:
   8161  *      Free egress l3 interface id.
   8162  * Parameters:
   8163  *      unit   - (IN) SOC unit number.
   8164  *      id     - (IN) Interface id
   8165  * Returns:
   8166  *      BCM_E_XXX
   8167  */
   8168 int
   8169 _bcm_xgs3_egress_l3_intf_id_free(int unit, int id)
   8170 {
   8171     /* Input parameters check. */
   8172     if ((id < 0) || (id >= BCM_XGS3_L3_IF_TBL_SIZE(unit))) {
   8173         return (BCM_E_PARAM);
   8174     }
   8175 
   8176     /* Free interface index. */
   8177     L3_LOCK(unit);
   8178     BCM_L3_INTF_USED_CLR(unit, id);
   8179     L3_UNLOCK(unit);
   8180 
   8181     return  (BCM_E_NONE);
   8182 }
   8183 
   8184 /*
   8185  * Function:
   8186  *      _bcm_xgs3_egress_l3_intf_id_alloc
   8187  * Purpose:
   8188  *      Allocate egress l3 interface id.
   8189  * Parameters:
   8190  *      unit   - (IN) SOC unit number.
   8191  *      id     - (OUT) Allocated interface id
   8192  * Returns:
   8193  *      BCM_E_XXX
   8194  */
   8195 int
   8196 _bcm_xgs3_egress_l3_intf_id_alloc(int unit, _bcm_l3_intf_cfg_t *intf_info)
   8197 {
   8198     int idx;                    /* Iteration index.           */
   8199     int min_idx, max_idx;
   8200     _bcm_l3_tbl_t *tbl_ptr; /* L3 egress intf table pointer. */
   8201 #ifdef BCM_RIOT_SUPPORT
   8202     _bcm_l3_bookkeeping_t *l3_bk = L3_INFO(unit);
   8203 #endif
   8204 
   8205     /* get minimum and max values from table pointer. */
   8206     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, intf);
   8207 
   8208     /* Input parameters check. */
   8209     if (NULL == intf_info) {
   8210         return (BCM_E_PARAM);
   8211     }
   8212 
   8213     /*  Make sure module was initialized. */
   8214     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   8215         return (BCM_E_INIT);
   8216     }
   8217 
   8218 #ifdef BCM_RIOT_SUPPORT
   8219     if (BCMI_L3_INTF_OVERLAY_VALID(unit)) {
   8220         if (l3_bk->l3_intf_overlay_alloc_mode > 0) {
   8221             if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)) {
   8222                 min_idx = tbl_ptr->idx_max - l3_bk->l3_intf_overlay_entries + 1;
   8223                 max_idx = tbl_ptr->idx_max;
   8224             } else if(BCM_VLAN_VALID(intf_info->l3i_vid)) {
   8225                 min_idx = tbl_ptr->idx_min;
   8226                 max_idx = tbl_ptr->idx_max - l3_bk->l3_intf_overlay_entries;
   8227             } else {
   8228                 return BCM_E_PARAM;
   8229             }
   8230         } else {
   8231           if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)) {
   8232                 min_idx = tbl_ptr->idx_min;
   8233                 max_idx = l3_bk->l3_intf_overlay_entries -1;
   8234             } else if(BCM_VLAN_VALID(intf_info->l3i_vid)) {
   8235                 min_idx = l3_bk->l3_intf_overlay_entries;
   8236                 max_idx = tbl_ptr->idx_max;
   8237             } else {
   8238                 return BCM_E_PARAM;
   8239             }
   8240         }
   8241     } else if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)) {
   8242         LOG_ERROR(BSL_LS_BCM_L3, (BSL_META_U(unit,
   8243         "VFI is sent without allocating overlay interface memory size\n")));
   8244 
   8245         return (BCM_E_PARAM);
   8246     } else 
   8247 #endif
   8248     {
   8249         min_idx = tbl_ptr->idx_min;
   8250         max_idx = tbl_ptr->idx_max;
   8251     }
   8252 
   8253     L3_LOCK(unit);
   8254 
   8255     /* Search for unused index. */
   8256     for (idx = min_idx; idx <= max_idx; idx++) {
   8257         /* Skip cpu interface. */
   8258         if (idx == BCM_XGS3_L3_L2CPU_INTF_IDX(unit)) {
   8259             continue;
   8260         }
   8261 
   8262 #ifdef BCM_TRIDENT2_SUPPORT
   8263         if (idx == 0) {
   8264             if (BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit) &&
   8265                 soc_feature(unit, soc_feature_l3_iif_zero_invalid)) {
   8266                 /* L3 egress interface ID 0 cannot be used if
   8267                  * both the following conditions are true:
   8268                  * (1) L3_INGRESS_INTF_MAP_MODE is set, enabling identical
   8269                  * mapping between L3 ingress interface and L3 egress
   8270                  * interface IDs.
   8271                  * (2) L3 ingress interface ID 0 cannot be used.
   8272                  */
   8273                 continue;
   8274             }
   8275         }
   8276 #endif /* BCM_TRIDENT2_SUPPORT */
   8277 
   8278         /* Check if interface index is used. */
   8279         if (!BCM_L3_INTF_USED_GET(unit, idx)) {
   8280             /* Free index found. */
   8281             BCM_L3_INTF_USED_SET(unit, idx);
   8282             intf_info->l3i_index = idx;
   8283             break;
   8284         }
   8285     }
   8286 
   8287     L3_UNLOCK(unit);
   8288 
   8289     return  (idx <= max_idx) ? BCM_E_NONE : BCM_E_FULL;
   8290 }
   8291 
   8292 
   8293 /*
   8294  * Function:
   8295  *      bcm_xgs3_l3_intf_create
   8296  * Purpose:
   8297  *      Create L3 interface
   8298  * Parameters:
   8299  *      unit      - (IN) SOC unit number.
   8300  *      intf_info - (IN) Interface information.
   8301  * Returns:
   8302  *      BCM_E_XXX
   8303  */
   8304 int
   8305 bcm_xgs3_l3_intf_create(int unit, _bcm_l3_intf_cfg_t *intf_info)
   8306 {
   8307     int rv;                     /* Interface creation status. */
   8308 
   8309     /*  Make sure module was initialized. */
   8310     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   8311         return (BCM_E_INIT);
   8312     }
   8313 
   8314     /* Input parameters check. */
   8315     if (NULL == intf_info) {
   8316         return (BCM_E_PARAM);
   8317     }
   8318 
   8319     /* Make sure there are empty slots. */
   8320     if (BCM_XGS3_L3_IF_COUNT(unit) == BCM_XGS3_L3_IF_MAX_COUNT(unit)) {
   8321         return (BCM_E_FULL);
   8322     }
   8323 
   8324     /* Allocate interface id. */
   8325     rv = _bcm_xgs3_egress_l3_intf_id_alloc(unit, intf_info); 
   8326     BCM_IF_ERROR_RETURN(rv);
   8327 
   8328     /* Create interface */
   8329     rv = _bcm_xgs3_l3_intf_create(unit, intf_info);
   8330 
   8331     if (BCM_FAILURE(rv)) {
   8332         /* Unreserve interface id. */
   8333         BCM_IF_ERROR_RETURN(_bcm_xgs3_egress_l3_intf_id_free(unit,
   8334                                                  intf_info->l3i_index));
   8335     }
   8336 
   8337     return rv;
   8338 }
   8339 
   8340 /*
   8341  * Function:
   8342  *      bcm_xgs3_l3_intf_id_create
   8343  * Purpose:
   8344  *      Create L3 interface with a specified index
   8345  * Parameters:
   8346  *      unit      - (IN) SOC unit number.
   8347  *      intf_info - (IN) Interface information.
   8348  * Returns:
   8349  *      BCM_E_XXX
   8350  */
   8351 int
   8352 bcm_xgs3_l3_intf_id_create(int unit, _bcm_l3_intf_cfg_t *intf_info)
   8353 {
   8354     int min_idx, max_idx;
   8355     _bcm_l3_tbl_t *tbl_ptr;
   8356 #ifdef BCM_RIOT_SUPPORT
   8357     _bcm_l3_bookkeeping_t *l3_bk = L3_INFO(unit);
   8358 #endif
   8359     /*  Make sure module was initialized. */
   8360     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   8361         return (BCM_E_INIT);
   8362     }
   8363 
   8364     /* Input parameters check. */
   8365     if (NULL == intf_info) {
   8366         return (BCM_E_PARAM);
   8367     }
   8368 
   8369     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, intf);
   8370 
   8371 #ifdef BCM_RIOT_SUPPORT
   8372     if (BCMI_L3_INTF_OVERLAY_VALID(unit)) {
   8373         if (l3_bk->l3_intf_overlay_alloc_mode > 0) {
   8374             if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)) {
   8375                 min_idx = tbl_ptr->idx_max - l3_bk->l3_intf_overlay_entries + 1;
   8376                 max_idx = tbl_ptr->idx_max;
   8377             } else if(BCM_VLAN_VALID(intf_info->l3i_vid)) {
   8378                 min_idx = tbl_ptr->idx_min;
   8379                 max_idx = tbl_ptr->idx_max - l3_bk->l3_intf_overlay_entries;
   8380             } else {
   8381                 return BCM_E_PARAM;
   8382             }
   8383         } else {
   8384             if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)) {
   8385                 min_idx = tbl_ptr->idx_min;
   8386                 max_idx = l3_bk->l3_intf_overlay_entries -1;
   8387             } else if(BCM_VLAN_VALID(intf_info->l3i_vid)) {
   8388                 min_idx = l3_bk->l3_intf_overlay_entries;
   8389                 max_idx = tbl_ptr->idx_max;
   8390             } else {
   8391                 return BCM_E_PARAM;
   8392             }
   8393         }
   8394     } else if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)) {
   8395         LOG_ERROR(BSL_LS_BCM_L3, (BSL_META_U(unit,
   8396         "VFI is sent without allocating overlay interface memory size\n")));
   8397 
   8398         return (BCM_E_PARAM);
   8399     } else
   8400 #endif
   8401     {   
   8402         min_idx = tbl_ptr->idx_min;
   8403         max_idx = tbl_ptr->idx_max;
   8404     }
   8405     /* Interface index sanity check. */
   8406     if ((intf_info->l3i_index < min_idx) ||
   8407         (intf_info->l3i_index > max_idx) ||
   8408         (intf_info->l3i_index == BCM_XGS3_L3_L2CPU_INTF_IDX(unit))) {
   8409         return (BCM_E_PARAM);
   8410     }
   8411 
   8412 #ifdef BCM_TRIDENT2_SUPPORT
   8413     if (intf_info->l3i_index == 0) {
   8414         if (BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit) &&
   8415             soc_feature(unit, soc_feature_l3_iif_zero_invalid)) {
   8416             /* L3 egress interface ID 0 cannot be used if
   8417              * both the following conditions are true:
   8418              * (1) L3_INGRESS_INTF_MAP_MODE is set, enabling identical
   8419              * mapping between L3 ingress interface and L3 egress
   8420              * interface IDs.
   8421              * (2) L3 ingress interface ID 0 cannot be used.
   8422              */
   8423             return (BCM_E_PARAM);
   8424         }
   8425     }
   8426 #endif /* BCM_TRIDENT2_SUPPORT */
   8427 
   8428     /* Create interface */
   8429     return _bcm_xgs3_l3_intf_create(unit, intf_info);
   8430 }
   8431 
   8432 /*
   8433  * Function:
   8434  *      bcm_xgs3_l3_intf_lookup
   8435  * Purpose:
   8436  *      See if an L3 interface exists by VID and MAC.
   8437  * Parameters:
   8438  *      unit      - (IN) SOC unit number.
   8439  *      intf_info - (IN) Interface information.
   8440  * Returns:
   8441  *      BCM_E_NONE if entry exists and is found;
   8442  *      BCM_E_NOT_FOUND if the entry is not found.
   8443  * Notes:
   8444  *      Returns the L3 interface info if found
   8445  */
   8446 
   8447 int
   8448 bcm_xgs3_l3_intf_lookup(int unit, _bcm_l3_intf_cfg_t *intf_info)
   8449 {
   8450     bcm_mac_t mac;              /* Key mac. */
   8451 
   8452     /*  Make sure module was initialized. */
   8453     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   8454         return (BCM_E_INIT);
   8455     }
   8456 
   8457     /* Input parameters check. */
   8458     if (NULL == intf_info) {
   8459         return (BCM_E_PARAM);
   8460     }
   8461 
   8462     /* Set lookup key. */
   8463     sal_memcpy(mac, intf_info->l3i_mac_addr, sizeof(bcm_mac_t));
   8464 
   8465     /* Perform search by MAC & VID. */
   8466     return _bcm_xgs3_l3_intf_lookup(unit, intf_info, intf_info->l3i_vid, mac);
   8467 
   8468 }
   8469 
   8470 /*
   8471  * Function:
   8472  *      bcm_xgs3_l3_intf_del
   8473  * Purpose:
   8474  *      Delete L3 interface.
   8475  * Parameters:
   8476  *      unit      - (IN) SOC unit number.
   8477  *      intf_info - (IN) Interface information.
   8478  * Returns:
   8479  *      BCM_E_XXX
   8480  */
   8481 int
   8482 bcm_xgs3_l3_intf_del(int unit, _bcm_l3_intf_cfg_t *intf_info)
   8483 {
   8484     int rv = BCM_E_UNAVAIL;     /* Operation status.   */
   8485     int first_error = BCM_E_NONE;       /* First error occured. */
   8486     int ingress_map_mode = 0;
   8487 #ifdef BCM_RIOT_SUPPORT
   8488     soc_mem_t mem;                 /* Interface table memory.        */
   8489     l3_max_entry_t l3_if_entry;    /* Buffer to read interface info. */
   8490     uint32  *l3_if_entry_p;        /* Interface read buffer address. */
   8491     int profiled_mac = 0;
   8492     int macda_index = -1;
   8493 #endif
   8494 
   8495     /*  Make sure module was initialized. */
   8496     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   8497         return (BCM_E_INIT);
   8498     }
   8499 
   8500     if (BCM_XGS3_L3_IF_COUNT(unit) == 0) {
   8501         return (BCM_E_NOT_FOUND);
   8502     }
   8503 
   8504 
   8505     /* Verify interface index range. */
   8506     if ((intf_info->l3i_index < 0) ||
   8507         (intf_info->l3i_index >= BCM_XGS3_L3_IF_TBL_SIZE(unit))) {
   8508         return (BCM_E_PARAM);
   8509     }
   8510 
   8511     /* Check that ifindex corresponds to an active interface. */
   8512     if (!BCM_L3_INTF_USED_GET(unit, intf_info->l3i_index)) {
   8513         return (BCM_E_NOT_FOUND);
   8514     }
   8515 
   8516     /* Reserved interface entry, should not be touched. */
   8517     if (intf_info->l3i_index == BCM_XGS3_L3_L2CPU_INTF_IDX(unit)) {
   8518         return (BCM_E_NONE);
   8519     }
   8520 
   8521 #ifdef BCM_RIOT_SUPPORT
   8522     if (soc_feature(unit,soc_feature_egr_intf_vlan_vfi_deoverlay)) {
   8523         /* Get interface table memory. */
   8524         mem = BCM_XGS3_L3_MEM(unit, intf);
   8525 
   8526         /* Zero read buffer. */
   8527         l3_if_entry_p = (uint32 *)&l3_if_entry;
   8528         sal_memset(l3_if_entry_p, 0, sizeof(l3_max_entry_t));
   8529 
   8530         /* Read interface table entry by index. */
   8531         BCM_IF_ERROR_RETURN
   8532             (BCM_XGS3_MEM_READ (unit, mem, intf_info->l3i_index, l3_if_entry_p));
   8533         profiled_mac = soc_mem_field32_get(unit, mem, l3_if_entry_p,
   8534                            MAC_ADDRESS_OVERLAY_TYPEf);
   8535         macda_index = soc_mem_field32_get(unit, mem, l3_if_entry_p,
   8536                           MAC_ADDRESS_PROFILE_IDXf);
   8537         if ((profiled_mac) && (macda_index != -1)) {
   8538             _bcm_mac_da_profile_entry_delete(unit, macda_index);
   8539         }
   8540     }
   8541 #endif
   8542     /* Get interface info. */
   8543     if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_get)) {
   8544         BCM_XGS3_L3_MODULE_LOCK(unit);
   8545         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, intf_info);
   8546         BCM_XGS3_L3_MODULE_UNLOCK(unit);
   8547     }
   8548     BCM_IF_ERROR_RETURN(rv);
   8549 
   8550     /* Remove interface layer 2 address if required. */
   8551     if (BCM_L3_INTF_ARL_GET(unit, intf_info->l3i_index)) {
   8552         rv = bcm_esw_l2_addr_delete(unit, intf_info->l3i_mac_addr,
   8553                                     intf_info->l3i_vid);
   8554         if ((rv < 0) && (first_error == BCM_E_NONE) && (rv != BCM_E_NOT_FOUND) ) {
   8555             first_error = rv;
   8556         }
   8557         BCM_L3_INTF_ARL_CLR(unit, intf_info->l3i_index);
   8558     }
   8559 
   8560     /* Clear ingress & egress filter interface group table. */
   8561     if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_group_set)) {
   8562         intf_info->l3i_group = 0;
   8563         BCM_XGS3_L3_MODULE_LOCK(unit);
   8564         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_group_set) (unit, intf_info);
   8565         BCM_XGS3_L3_MODULE_UNLOCK(unit);
   8566         if ((rv < 0) && (first_error == BCM_E_NONE)) {
   8567             first_error = rv;
   8568         }
   8569     }
   8570 
   8571     /* Remove the interface. */
   8572     if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_del)) {
   8573         BCM_XGS3_L3_MODULE_LOCK(unit);
   8574         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_del) (unit, intf_info->l3i_index);
   8575         BCM_XGS3_L3_MODULE_UNLOCK(unit);
   8576         if ((rv < 0) && (first_error == BCM_E_NONE)) {
   8577             first_error = rv;
   8578         }
   8579     }
   8580 
   8581     if (BCM_SUCCESS(first_error) &&
   8582            !(intf_info->l3i_flags & BCM_L3_SECONDARY)) {
   8583 
   8584         /* Decrement ref count on VRF tied to this VLAN */
   8585 #ifdef BCM_TRIUMPH_SUPPORT
   8586         if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
   8587             BCM_IF_ERROR_RETURN
   8588                 (bcm_xgs3_l3_ingress_intf_map_get(unit, &ingress_map_mode));
   8589         }
   8590 #endif
   8591         if (!ingress_map_mode ||
   8592                 SOC_MEM_FIELD_VALID(unit, VLAN_TABm, VRF_IDf)) {
   8593             /* Decrement ref count on related VLAN VRF here */
   8594             BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ing_intf),
   8595                     intf_info->l3i_vid, _BCM_SINGLE_WIDE);
   8596 
   8597             if (!BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, 
   8598                             ing_intf), intf_info->l3i_vid)) {
   8599                 /* Ref count on related VLAN VRF is zero, so
   8600                  * clear VRF_VFI table for primary interfaces. */
   8601                 if ((BCM_XGS3_L3_HWCALL_CHECK(unit, if_vrf_unbind))
   8602                      && (intf_info->l3i_vrf != BCM_L3_VRF_INVALID)) {
   8603                     BCM_XGS3_L3_MODULE_LOCK(unit);
   8604                     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_vrf_unbind) (unit, 
   8605                             intf_info);
   8606                     BCM_XGS3_L3_MODULE_UNLOCK(unit);
   8607                     if ((rv < 0) && (first_error == BCM_E_NONE)) {
   8608                         first_error = rv;
   8609                     }
   8610                 }
   8611             }
   8612         }
   8613     }
   8614 
   8615     /* Unreserve interface id. */
   8616     rv = _bcm_xgs3_egress_l3_intf_id_free(unit, intf_info->l3i_index);
   8617     return first_error;
   8618 }
   8619 
   8620 /*
   8621  * Function: bcm_xgs3_l3_intf_del_all
   8622  * Purpose:
   8623  *      Delete all L3 interfaces.
   8624  * Parameters:
   8625  *      unit - (IN) SOC unit number.
   8626  * Returns:
   8627  *      BCM_E_XXX
   8628  */
   8629 int
   8630 bcm_xgs3_l3_intf_del_all(int unit)
   8631 {
   8632     int idx;                    /* Interface index.             */
   8633     _bcm_l3_intf_cfg_t intf;    /* Interface info structure.    */
   8634     int max_lkup_cnt;           /* Number of active interfaces. */
   8635 
   8636     sal_memset(&intf, 0, sizeof(_bcm_l3_intf_cfg_t));
   8637 
   8638     /*  Make sure module was initialized. */
   8639     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   8640         return (BCM_E_INIT);
   8641     }
   8642 
   8643     /* Don't iterate beyond number of active interfaces. */
   8644     max_lkup_cnt = BCM_XGS3_L3_IF_COUNT(unit);
   8645     if (max_lkup_cnt <= 0) {
   8646         return (BCM_E_NONE);
   8647     }
   8648 
   8649     /* Iterate over all active interfaces. */
   8650     for (idx = 0; idx < BCM_XGS3_L3_IF_TBL_SIZE(unit); idx++) {
   8651         if (BCM_L3_INTF_USED_GET(unit, idx)) {
   8652             max_lkup_cnt--;
   8653             if (!max_lkup_cnt) {
   8654                 break;
   8655             }
   8656 
   8657             /* Remove interface. */
   8658             intf.l3i_index = idx;
   8659             BCM_IF_ERROR_RETURN(bcm_xgs3_l3_intf_del(unit, &intf));
   8660         }
   8661     }
   8662     return (BCM_E_NONE);
   8663 }
   8664 
   8665 /*
   8666  * Function:
   8667  *      _bcm_xgs3_l3_flags_to_shr
   8668  * Purpose:
   8669  *      Translate l3 specific flags to shared (table management) flags.
   8670  * Parameters:
   8671  *    l3_flags   - (IN)  l3 table flags.
   8672  *    shr_flags  - (OUT) Shared flags.
   8673  * Returns:
   8674  *    BCM_E_XXX
   8675  */
   8676 STATIC INLINE int
   8677 _bcm_xgs3_l3_flags_to_shr(uint32 l3_flags, uint32 *shr_flags)
   8678 {
   8679     uint32 flag = 0;
   8680 
   8681     if (NULL == shr_flags) {
   8682         return (BCM_E_PARAM);
   8683     }
   8684 
   8685     if (l3_flags & BCM_L3_REPLACE) {
   8686        flag |= _BCM_L3_SHR_UPDATE;
   8687     }
   8688 
   8689     if (l3_flags & BCM_L3_WITH_ID) {
   8690        flag |= _BCM_L3_SHR_WITH_ID;
   8691     }
   8692 
   8693     *shr_flags = flag;
   8694 
   8695     return (BCM_E_NONE);
   8696 }
   8697 
   8698 /*
   8699  * Function:
   8700  *      _bcm_xgs3_l3_flags_to_egr_obj
   8701  * Purpose:
   8702  *      Translate l3 specific flags to Egress Object flags.
   8703  * Parameters:
   8704  *    l3_flags   - (IN)  l3 table flags.
   8705  *    egr_obj  - (OUT) Egress Object
   8706  * Returns:
   8707  *    BCM_E_XXX
   8708  */
   8709 
   8710 STATIC INLINE int
   8711 _bcm_xgs3_l3_flags_to_egr_obj (uint32 l3_flags, bcm_l3_egress_t *egr)
   8712 {
   8713     /* Input parameters check. */
   8714     if (NULL == egr) {
   8715         return (BCM_E_PARAM);
   8716     }
   8717 
   8718     if (l3_flags & BCM_L3_KEEP_SRCMAC) {
   8719        egr->flags |= BCM_L3_KEEP_SRCMAC;
   8720     }
   8721 
   8722     if (l3_flags & BCM_L3_KEEP_DSTMAC) {
   8723        egr->flags |= BCM_L3_KEEP_DSTMAC;
   8724     }
   8725 
   8726     if (l3_flags & BCM_L3_KEEP_VLAN) {
   8727        egr->flags |= BCM_L3_KEEP_VLAN;
   8728     }
   8729 
   8730     if (l3_flags & BCM_L3_KEEP_TTL) {
   8731        egr->flags |= BCM_L3_KEEP_TTL;
   8732     }
   8733 
   8734 #ifdef BCM_GREYHOUND_SUPPORT
   8735     /* Greyhound's L3 egress process need BCM_L3_IPMC for IPMC logic */
   8736     if (l3_flags & BCM_L3_IPMC) {
   8737         egr->flags |= BCM_L3_IPMC;
   8738     }
   8739 #endif /* BCM_GREYHOUND_SUPPORT */
   8740 
   8741     return (BCM_E_NONE);
   8742 
   8743 }
   8744 
   8745 /*
   8746  * Function:
   8747  *      _bcm_xgs3_tunnel_flags_to_shr
   8748  * Purpose:
   8749  *      Translate tunnel specific flags to shared (table management) flags.
   8750  * Parameters:
   8751  *    tnl_flags  - (IN)  Tunnel table flags.
   8752  *    shr_flags  - (OUT) Shared flags.
   8753  * Returns:
   8754  *    BCM_E_XXX
   8755  */
   8756 STATIC INLINE int
   8757 _bcm_xgs3_tunnel_flags_to_shr(uint32 tnl_flags, uint32 *shr_flags)
   8758 {
   8759     /*
   8760      * Reserve entry Zero in EGR_IP_TUNNEL memory. This reserved entry
   8761      * will not be allocated. The purpose of this entry is that
   8762      * any interface which points to this entry will be treated
   8763      * as a tunnel with no encapsulation or 'NO-protocol" tunnel.
   8764      */
   8765     uint32 flag = _BCM_L3_SHR_SKIP_INDEX_ZERO;
   8766 
   8767     if (NULL == shr_flags) {
   8768         return (BCM_E_PARAM);
   8769     }
   8770 
   8771     if (tnl_flags & BCM_TUNNEL_REPLACE) {
   8772        flag |= _BCM_L3_SHR_UPDATE;
   8773     }
   8774 
   8775     *shr_flags = flag;
   8776     return (BCM_E_NONE);
   8777 }
   8778 
   8779 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   8780 /*
   8781 * Function:
   8782 *      bcmi_xgs3_tbl_alloc_mode_get
   8783 * Purpose:
   8784 *       get allocation configuration.
   8785 * Parameters:
   8786 *      unit        - (IN)SOC unit number.
   8787 *      data        - (IN) Software table operation entry .
   8788 *      alloc_mode  - (OUT) allocation mode.
   8789 * Returns:
   8790 *    BCM_E_NONE
   8791 */
   8792 STATIC int
   8793 bcmi_xgs3_tbl_alloc_mode_get(int unit, _bcm_l3_tbl_op_t *data,
   8794                             int *alloc_mode)
   8795 {
   8796 #if defined(BCM_RIOT_SUPPORT)
   8797     _bcm_l3_bookkeeping_t *l3_bk_info = &_bcm_l3_bk_info[unit];
   8798 #endif
   8799 
   8800     *alloc_mode = 0;
   8801     if ( BCM_XGS3_L3_TBL_PTR(unit, next_hop) == data->tbl_ptr) {
   8802 #if defined(BCM_RIOT_SUPPORT)
   8803         *alloc_mode = l3_bk_info->l3_nh_overlay_alloc_mode;
   8804 #endif
   8805     }
   8806 
   8807     return BCM_E_NONE;
   8808 }
   8809 #endif
   8810 
   8811 /*
   8812  * Function:
   8813  *      bcmi_xgs3_tbl_idx_range_get
   8814  * Purpose:
   8815  *       Generic table get range for table.
   8816  * Parameters:
   8817  *      unit        - (IN)SOC unit number.
   8818  *      idx_min     - (OUT) ptr of min index.
   8819  *      idx_max     - (OUT) ptr of max index.
   8820  *      used_idx    - (OUT) ptr of used entries.
   8821  *      data        - (IN/OUT) Software table operation entry .
   8822  * Returns:
   8823  *    BCM_E_NONE   
   8824  */
   8825 
   8826 STATIC int  
   8827 bcmi_xgs3_tbl_idx_range_get(int unit, int *idx_min, int *idx_max, 
   8828                             int **used_idx, _bcm_l3_tbl_op_t *data)
   8829 {
   8830     _bcm_l3_tbl_t *tbl_ptr;                   /* Software table pointer. */
   8831 #if defined(BCM_TRIDENT2_SUPPORT)
   8832     _bcm_l3_bookkeeping_t *l3;
   8833 #endif
   8834 
   8835     tbl_ptr = data->tbl_ptr;    
   8836     /* Set up the limits for indexes */
   8837     *idx_min     = tbl_ptr->idx_min;
   8838     *idx_max     = tbl_ptr->idx_max;
   8839     *used_idx    = &tbl_ptr->idx_maxused;
   8840 #if defined(BCM_TRIDENT2_SUPPORT)
   8841     l3 = &_bcm_l3_bk_info[unit];
   8842     if (l3->l3_nh_reserve_for_ecmp &&
   8843         (tbl_ptr == BCM_XGS3_L3_TBL_PTR(unit, next_hop))) {
   8844         *idx_min = BCM_XGS3_L3_ECMP_MAX_GROUPS(unit);
   8845     }
   8846 #endif
   8847 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   8848     /* Set up indexes if there is split in table.
   8849      * Overlay and underlay domains are configurable for some tables.
   8850      * By default, overlay entry is allocated from lower portion of table.
   8851      * If "alloc mode" is 1, overlay entry is allocated from higher
   8852      * portion of table
   8853      */
   8854     if (tbl_ptr->split_idx > 0) {
   8855         int alloc_mode = 1;
   8856 
   8857         bcmi_xgs3_tbl_alloc_mode_get(unit, data, &alloc_mode);
   8858         if (alloc_mode) {
   8859             if ((data->oper_flags & _BCM_L3_SHR_OVERLAY_OBJECT) ) {
   8860                 *idx_min  = tbl_ptr->split_idx;
   8861             } else {
   8862                 *idx_max  = tbl_ptr->split_idx - 1;
   8863                 *used_idx = &tbl_ptr->split_maxused;
   8864             }
   8865         } else {
   8866             if ((data->oper_flags & _BCM_L3_SHR_OVERLAY_OBJECT) ) {
   8867                 *idx_max  = tbl_ptr->split_idx - 1;
   8868                 *used_idx = &tbl_ptr->split_maxused;
   8869             } else {
   8870                 *idx_min  = tbl_ptr->split_idx;
   8871             }
   8872         }
   8873     }
   8874 #endif
   8875 
   8876 #if defined(BCM_TOMAHAWK_SUPPORT)
   8877     if (soc_feature(unit, soc_feature_th_nh_no_overlap_ecmp) &&
   8878         (data->oper_flags & _BCM_L3_SHR_NO_ECMP_OVERLAP)) {
   8879         /* SW WAR for IFP qualifier bcmFieldQualifyDstL3Egress
   8880            Let NHI won't overlap ECMP indexes */
   8881         *idx_min = soc_mem_index_max(unit, L3_ECMP_COUNTm) + 1;
   8882     }
   8883 #endif /* BCM_TOMAHAWK_SUPPORT */
   8884 
   8885     return BCM_E_NONE;
   8886 }
   8887 
   8888 /*
   8889  * Function:
   8890  *      _bcm_xgs3_tbl_free_idx_get
   8891  * Purpose:
   8892  *       Generic table get unused table entry index.
   8893  * Parameters:
   8894  *      unit        - (IN)SOC unit number.
   8895  *      data        - (IN/OUT) Software table operation entry .
   8896  * Returns:
   8897  *    BCM_E_NONE - if free entry was found.
   8898  *    BCM_E_FULL - if no free entry found.
   8899  */
   8900 int
   8901 _bcm_xgs3_tbl_free_idx_get(int unit, _bcm_l3_tbl_op_t *data)
   8902 {
   8903     _bcm_l3_tbl_t *tbl_ptr; /* Software table pointer. */
   8904     int  width;            /* Entry width.            */
   8905     int lkup_idx;           /* Iteration index.        */
   8906     int idx;                /* Iteration index 2       */
   8907     int idx_min, idx_max, *maxused_idx;
   8908 
   8909     tbl_ptr = data->tbl_ptr;
   8910     width = data->width;
   8911 
   8912     /* get range for min and max indexes */
   8913     bcmi_xgs3_tbl_idx_range_get(unit, &idx_min, &idx_max, &maxused_idx, data);
   8914 
   8915     if (!(data->oper_flags & _BCM_L3_SHR_TABLE_TRAVERSE_CONTROL)) {
   8916         /* Try to identify matching/free entry */
   8917         for (lkup_idx = idx_min;
   8918              lkup_idx <= idx_max; lkup_idx += width) {
   8919 
   8920             if (!lkup_idx && (data->oper_flags & _BCM_L3_SHR_SKIP_INDEX_ZERO)) {
   8921                 continue;
   8922             }
   8923 
   8924             if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, lkup_idx)) {
   8925                 idx = width;
   8926                 while (--idx) {
   8927                     /* Check if free slots can accomodate wide entry. */
   8928                     if (BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, lkup_idx + idx)) {
   8929                         break;
   8930                     }
   8931                 }
   8932                 if (idx) {
   8933                     /* There is no room to accomodate wide entry. */
   8934                     continue;
   8935                 }
   8936                 data->entry_index = lkup_idx;
   8937                 return (BCM_E_NONE);
   8938             }
   8939         }
   8940     } else {
   8941         for (lkup_idx = idx_min;
   8942              lkup_idx <= idx_max; lkup_idx++) {
   8943 
   8944             if (!lkup_idx && (data->oper_flags & _BCM_L3_SHR_SKIP_INDEX_ZERO)) {
   8945                 continue;
   8946             }
   8947 
   8948             if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, lkup_idx)) {
   8949                 /* Check if a contiguous chunk of 'data.width'
   8950                  * entries are available starting from lkup_idx */
   8951                 for (idx = lkup_idx;
   8952                     (idx < (lkup_idx + width)) && (idx <= idx_max);
   8953                      idx++) {
   8954 
   8955                     if(BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, idx)) {
   8956                          break;
   8957                     }
   8958                 }
   8959 
   8960                 if (idx == (lkup_idx + width)) {
   8961                     /* Empty slot with 'data.width' entries available */
   8962                     data->entry_index = lkup_idx;
   8963                     return (BCM_E_NONE);
   8964                 }
   8965             }
   8966         }
   8967     }
   8968     return (BCM_E_FULL);
   8969 }
   8970 
   8971 /*
   8972  * Function:
   8973  *      _bcm_xgs3_tbl_match
   8974  * Purpose:
   8975  *       Generic table match routine.
   8976  *       Identify identical entry in the table if exists or return
   8977  *       first free entry available for write.
   8978  * Parameters:
   8979  *      unit        - (IN)SOC unit number.
   8980  *      data        - (IN/OUT)Table entry operation info.
   8981  * Returns:
   8982  *    BCM_E_NONE      - if matching entry was found.
   8983  *    BCM_E_NOT_FOUND - if no matching entry found.
   8984  *    BCM_E_FULL      - if no unused entry found.
   8985  */
   8986 STATIC int
   8987 _bcm_xgs3_tbl_match(int unit, _bcm_l3_tbl_op_t *data)
   8988 {
   8989     int lkup_idx = BCM_XGS3_L3_INVALID_INDEX;   /* Iteration index.      */
   8990     int unused_idx =  BCM_XGS3_L3_INVALID_INDEX;/* Unused table index.   */
   8991     _bcm_l3_tbl_t *tbl_ptr;                   /* Software table pointer. */
   8992     uint16 entry_hash;                        /* Entry hash.             */
   8993     int cmp_result;                           /* Comparison result.      */
   8994     int width;                              /* Entry width.            */
   8995     int idx;                                  /* Iteration index 2       */
   8996     int rv;                                   /* Return status.          */
   8997     int idx_min, idx_max, *maxused_idx;
   8998 
   8999     tbl_ptr = data->tbl_ptr;
   9000     width = data->width;
   9001 
   9002     /* Calculate entry data hash. */
   9003     (*(data->hash_func)) (unit, data->entry_buffer, &entry_hash);
   9004     /* get range for min and max indexes */
   9005     idx_min     = tbl_ptr->idx_min;
   9006     idx_max     = tbl_ptr->idx_max;
   9007     maxused_idx = &tbl_ptr->idx_maxused;
   9008 
   9009     /* Try to identify matching/free entry */
   9010     for (lkup_idx = idx_min;
   9011          lkup_idx <= *maxused_idx; lkup_idx += width) {
   9012 
   9013         if (!lkup_idx && (data->oper_flags & _BCM_L3_SHR_SKIP_INDEX_ZERO)) {
   9014             continue;
   9015         }
   9016 
   9017         if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, lkup_idx)) {
   9018             /* If entry is unused preserve free index. */
   9019             if (unused_idx == BCM_XGS3_L3_INVALID_INDEX) {
   9020                 idx = width;
   9021                 while (--idx) {
   9022                     /* Check if free slots can accomodate wide entry. */
   9023                     if (BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, lkup_idx + idx)) {
   9024                         break;
   9025                     }
   9026                 }
   9027                 if (idx) {
   9028                     /* There is no room to accomodate wide entry. */
   9029                     continue;
   9030                 }
   9031                 unused_idx = lkup_idx;
   9032             }
   9033             continue;
   9034         }
   9035 
   9036         /* Compare valid entry hash(signature). */
   9037         if (!BCM_XGS3_L3_ENT_HASH_CMP(tbl_ptr, lkup_idx, entry_hash)) {
   9038             continue;
   9039         }
   9040 
   9041         /* If hash matches  compare the entry itself.  */
   9042         rv = ((*(data->cmp_func))(unit, data->entry_buffer,
   9043                                   lkup_idx, &cmp_result));
   9044         if (rv == BCM_E_NOT_FOUND) {
   9045             continue;
   9046         } else if (rv < 0) {
   9047             return rv;
   9048         }
   9049 
   9050         /* Check comparison result. */
   9051         if (cmp_result == BCM_L3_CMP_EQUAL) {
   9052             data->entry_index = lkup_idx;
   9053             return (BCM_E_NONE);
   9054         }
   9055     }  /* Loop over all the entries. */
   9056 
   9057     /* Return free entry if found. */
   9058     bcmi_xgs3_tbl_idx_range_get(unit, &idx_min, &idx_max, &maxused_idx, data);
   9059 
   9060     if (!((idx_min == tbl_ptr->idx_min) && (idx_max == tbl_ptr->idx_max))) {
   9061        unused_idx = BCM_XGS3_L3_INVALID_INDEX;
   9062     }
   9063     if (BCM_XGS3_L3_INVALID_INDEX != unused_idx) {
   9064         data->entry_index = unused_idx;
   9065     } else {
   9066         /* Set the lkup index so that it can get index from proper range. */
   9067         if ((idx_min == 0) &&
   9068              (data->oper_flags & _BCM_L3_SHR_SKIP_INDEX_ZERO)) {
   9069             /* index 0 is reserved */
   9070             idx_min = idx_min + width;
   9071         }
   9072         lkup_idx = idx_min;
   9073 
   9074         /*
   9075          * If last entry in table is multi wide entry then maxused will point
   9076          * to first index of multi wide entry. But rest of the indexes of
   9077          * full entry are also ref-counted during ADD. Make sure that in
   9078          * the next entry ADD, we dont return the index which is already used.
   9079          */
   9080         while ((lkup_idx  <= idx_max) &&
   9081                 (BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, lkup_idx))) {
   9082             lkup_idx += width;
   9083         }
   9084         /* Check if we have run out of space for required entry width. */
   9085         if ((idx_max - lkup_idx) >= (width - 1)) {
   9086             data->entry_index = lkup_idx;
   9087         } else {
   9088             return (BCM_E_FULL);
   9089         }
   9090     }
   9091     return (BCM_E_NOT_FOUND);
   9092 }
   9093 
   9094 /*
   9095  * Function:
   9096  *      _bcm_xgs3_tbl_add
   9097  * Purpose:
   9098  *       Generic table add routine.
   9099  *       Allocate table index & write an entry to into it.
   9100  *       Routine trying to match new entry to an existing one,
   9101  *       if match found reference cound is incremented, otherwise
   9102  *       new index allocated & entry added to hw.
   9103  * Parameters:
   9104  *      unit    - (IN)SOC unit number.
   9105  *      data    - (IN/OUT)Table entry operation info.
   9106  *
   9107 
   9108  * Returns:
   9109  *    BCM_E_XXX
   9110  */
   9111 int
   9112 _bcm_xgs3_tbl_add(int unit, _bcm_l3_tbl_op_t *data)
   9113 {
   9114     _bcm_l3_tbl_t *tbl_ptr;                   /* Software table pointer. */
   9115     int l3_match_disable;                     /* L3 match disable flag.  */
   9116     uint16 entry_hash;                        /* Entry hash.             */
   9117     int rv;                                   /* Return status.          */
   9118     int tmpidx;
   9119     int idx_min, idx_max, *maxused_idx;
   9120 #ifdef BCM_TOMAHAWK_SUPPORT
   9121     _bcm_l3_tbl_t *ecmp_tbl_ptr = NULL;
   9122 #endif /* BCM_TOMAHAWK_SUPPORT */
   9123 
   9124     /* Input parameters check. */
   9125     if (NULL == data) {
   9126         return (BCM_E_PARAM);
   9127     }
   9128 
   9129     if ((NULL == data->entry_buffer) ||  (NULL == data->tbl_ptr) ||
   9130         (NULL == data->hash_func) || (NULL == data->cmp_func) ||
   9131         (NULL == data->add_func)) {
   9132         return (BCM_E_PARAM);
   9133     }
   9134 
   9135     tbl_ptr = data->tbl_ptr;
   9136     /* Get l3 switch mode from module flags. */
   9137     l3_match_disable =  data->oper_flags & _BCM_L3_SHR_MATCH_DISABLE;
   9138 
   9139     /* Calculate entry data hash. */
   9140     (*(data->hash_func)) (unit, data->entry_buffer, &entry_hash);
   9141     BCM_XGS3_L3_MODULE_LOCK(unit);
   9142     /* get range for min and max indexes */
   9143     bcmi_xgs3_tbl_idx_range_get(unit, &idx_min, &idx_max, &maxused_idx, data);
   9144 
   9145     if(data->oper_flags & _BCM_L3_SHR_WITH_ID) {
   9146 
   9147         /* Check index range */
   9148         if ((data->entry_index < idx_min) ||
   9149             (data->entry_index > idx_max)) {
   9150             BCM_XGS3_L3_MODULE_UNLOCK(unit);
   9151             return (BCM_E_PARAM);
   9152         }
   9153 
   9154         /* Entry is currently used make sure replace flag is set. */
   9155         if (BCM_XGS3_L3_ENT_REF_CNT(data->tbl_ptr, data->entry_index))  {
   9156             if (!(data->oper_flags & _BCM_L3_SHR_UPDATE)) {
   9157                 BCM_XGS3_L3_MODULE_UNLOCK(unit);
   9158                 return (BCM_E_EXISTS);
   9159             }
   9160         }
   9161     } else {
   9162         if (l3_match_disable) {
   9163             /* Get free index to write the entry. */
   9164             rv = _bcm_xgs3_tbl_free_idx_get(unit, data);
   9165             if (BCM_FAILURE(rv)) {
   9166                 BCM_XGS3_L3_MODULE_UNLOCK(unit);
   9167                 return rv;
   9168             }
   9169 
   9170 #ifdef BCM_TOMAHAWK3_SUPPORT
   9171             /* When Tomahawk3 Failover with fixed egress nh offset is enable,
   9172                all free allocated index (for primary nh) must be < prot_offset.
   9173                Protected nh will be created by _BCM_L3_SHR_WITH_ID and
   9174                egr->failover_id = _FAILOVER_FIXED_NH_OFFSET_ON */
   9175             if ((data->tbl_ptr == BCM_XGS3_L3_TBL_PTR(unit, next_hop)) &&
   9176                 (FAILOVER_INFO(unit)->prot_offset > 0) &&
   9177                 (data->entry_index >= FAILOVER_INFO(unit)->prot_offset)) {
   9178                 BCM_XGS3_L3_MODULE_UNLOCK(unit);
   9179                 return BCM_E_FULL; /* primary nh index FULL */
   9180             }
   9181 #endif
   9182 
   9183         } else {
   9184             /* Try to identify matching/free entry */
   9185             rv = _bcm_xgs3_tbl_match(unit, data);
   9186             if ((rv < 0) && (BCM_E_NOT_FOUND != rv)) {
   9187                 BCM_XGS3_L3_MODULE_UNLOCK(unit);
   9188                 return rv;
   9189             }
   9190 
   9191             /* If identical entry found -> just increment reference count */
   9192             if (BCM_E_NONE == rv) {
   9193                 BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_ptr, data->entry_index,
   9194                                             data->width);
   9195                 BCM_XGS3_L3_MODULE_UNLOCK(unit);
   9196                 return (BCM_E_NONE);
   9197             }
   9198         }
   9199     }
   9200 
   9201     /* Update table maxused index. */
   9202     tmpidx = *maxused_idx;
   9203     if (*maxused_idx < data->entry_index) {
   9204         *maxused_idx = data->entry_index;
   9205     }
   9206 
   9207 #ifdef BCM_TOMAHAWK_SUPPORT
   9208     if (soc_feature(unit, soc_feature_hierarchical_ecmp) &&
   9209         (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
   9210                                             ecmp_mode_hierarchical) &&
   9211         ((data->tbl_ptr == BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp))
   9212 #ifdef BCM_TOMAHAWK3_SUPPORT
   9213         || (data->tbl_ptr == BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp))
   9214 #endif
   9215         )) {
   9216         ecmp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp);
   9217         /*
   9218          * In Hierarchical ECMP mode, ECMP groups in the 2nd half of group 
   9219          * table cannot have members in the first half of member table
   9220          */
   9221         if ((data->entry_index >= (soc_mem_index_count(unit, L3_ECMP_COUNTm) / 2)) && 
   9222             (ecmp_tbl_ptr->idx_min == 0)) {
   9223             ecmp_tbl_ptr->idx_min = (ecmp_tbl_ptr->idx_max/2) + 1;
   9224         }
   9225     }
   9226 #endif /* BCM_TOMAHAWK_SUPPORT */
   9227 
   9228     if (!(data->oper_flags & _BCM_L3_SHR_WRITE_DISABLE)) {
   9229         /* Set the entry to hw. */
   9230 
   9231         rv = (*(data->add_func)) (unit, data->entry_index, data->entry_buffer, data->info);
   9232 
   9233         if (rv < 0) {
   9234             *maxused_idx = tmpidx;
   9235             BCM_XGS3_L3_MODULE_UNLOCK(unit);
   9236             return rv;
   9237         }
   9238     }
   9239 
   9240     if ((data->oper_flags & _BCM_L3_SHR_WITH_ID) && (BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, data->entry_index) > 1)) {
   9241         /* Update hash */
   9242         BCM_XGS3_L3_ENT_HASH_UPDATE(tbl_ptr, data->entry_index, data->width, entry_hash);
   9243     } else {
   9244        /* Update hash & reference count info. */
   9245        BCM_XGS3_L3_ENT_INIT(tbl_ptr, data->entry_index, data->width, entry_hash);
   9246     }
   9247     
   9248     BCM_XGS3_L3_MODULE_UNLOCK(unit);
   9249     return (BCM_E_NONE);
   9250 }
   9251 
   9252 
   9253 void
   9254 _bcm_xgs3_nh_ref_cnt_incr(int unit, unsigned idx)
   9255 {
   9256     BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, next_hop),
   9257 				idx, _BCM_SINGLE_WIDE);
   9258 }
   9259 
   9260 void
   9261 _bcm_xgs3_nh_ref_cnt_get(int unit, uint32 idx, int ecmp, uint32 *ref_count)
   9262 {
   9263     /*
   9264      * By default, when an egress object is created, the reference count will be
   9265      * 1 to indicate that the entry is valid. So, when this object is referenced
   9266      * by a route, the ref count shall be increemented. So, 1 is decremented
   9267      * here
   9268      */
   9269 
   9270     if (ecmp != 0) {
   9271 #ifdef BCM_TOMAHAWK3_SUPPORT
   9272         if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) &&
   9273             (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
   9274                                                 ecmp_mode_hierarchical) &&
   9275             (idx < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) {
   9276             *ref_count =
   9277                 BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp),
   9278                                     idx) - 1;
   9279         } else
   9280 #endif
   9281         {
   9282             *ref_count =
   9283                 BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp),
   9284                                         idx) - 1;
   9285         }
   9286     } else {
   9287         *ref_count =
   9288             BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, next_hop),
   9289                                     idx) - 1;
   9290     }
   9291 }
   9292 
   9293 
   9294 /*
   9295  * Function:
   9296  *      _bcm_xgs3_tbl_del
   9297  * Purpose:
   9298  *       Generic table delete routine.
   9299  *       Entry kept if reference counter is not equal to 1 (other
   9300  *       instances still reference the same entry).
   9301  * Parameters:
   9302  *      unit      - (IN)SOC unit number.
   9303  *      data        - (IN/OUT)Table entry operation info.
   9304  *
   9305  * Returns:
   9306  *    BCM_E_XXX
   9307  */
   9308 int
   9309 _bcm_xgs3_tbl_del(int unit,  _bcm_l3_tbl_op_t *data)
   9310 {
   9311     int index;                    /* Temp index.             */
   9312     _bcm_l3_tbl_t *tbl_ptr;       /* Software table pointer. */
   9313     int idx_min, *maxused_idx;
   9314 
   9315     /* Input parameters check. */
   9316     if (NULL == data) {
   9317         return (BCM_E_PARAM);
   9318     }
   9319 
   9320     if (NULL == data->delete_func) {
   9321         return (BCM_E_PARAM);
   9322     }
   9323 
   9324     tbl_ptr = data->tbl_ptr;
   9325     /* Set up the limits for indexes */
   9326     idx_min     = tbl_ptr->idx_min;
   9327     maxused_idx = &tbl_ptr->idx_maxused;
   9328 
   9329 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   9330     if ((tbl_ptr->split_idx > 0)) {
   9331         if ((data->entry_index < tbl_ptr->split_idx)) {
   9332             maxused_idx  = &tbl_ptr->split_maxused;
   9333         } else {
   9334             idx_min      = tbl_ptr->split_idx;
   9335         }
   9336     } 
   9337 #endif
   9338 
   9339     /* Preserve next hop index */
   9340     index = data->entry_index;
   9341     /* Check index sanity. */
   9342     if ((index < idx_min) || (index > tbl_ptr->idx_max)) {
   9343         return (BCM_E_NONE);
   9344     }
   9345 
   9346     /* If entry is not currently used return. */
   9347     if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, index)) {
   9348         return (BCM_E_NONE);
   9349     }
   9350 
   9351     /* if not just clean but also need to delete entry, handle ref count */
   9352     if (!(data->oper_flags & _BCM_L3_SHR_CLEAN)) {
   9353     /* If entry used by other hosts/routes just decrement ref count. */
   9354     if (BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, index) > 1) {
   9355         BCM_XGS3_L3_ENT_REF_CNT_DEC(tbl_ptr, index, data->width);
   9356         return (BCM_E_NONE);
   9357     }
   9358 
   9359     /* Use count is exactly one, remove the entry. */
   9360 
   9361     /* Reset entry usecount & hash. */
   9362     BCM_XGS3_L3_ENT_RESET(tbl_ptr, index, data->width);
   9363 
   9364     /* Back up idx_maxused if needed. */
   9365     if (index == *maxused_idx) {
   9366         while ((!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, index)) &&
   9367                index > idx_min) {
   9368             index -= 1;
   9369         }
   9370         *maxused_idx = index;
   9371     }
   9372     }
   9373 
   9374     if (data->oper_flags & _BCM_L3_SHR_WRITE_DISABLE) {
   9375         return (BCM_E_NONE);
   9376     }
   9377 
   9378     return (*(data->delete_func)) (unit, data->entry_index, data->info);
   9379 }
   9380 
   9381 /*
   9382  * Function:
   9383  *      bcm_xgs3_nh_get
   9384  * Purpose:
   9385  * Parameters:
   9386  *      unit      - (IN)SOC unit number.
   9387  *      nh_idx    - (IN)Next hop index.
   9388  *      nh_info   - (OUT)Buffer to fill next hop info.
   9389  * Returns:
   9390  *    BCM_E_XXX
   9391  */
   9392 int
   9393 bcm_xgs3_nh_get(int unit, int nh_idx, bcm_l3_egress_t *nh_info)
   9394 {
   9395     int rv = BCM_E_UNAVAIL;     /* Operation return status.    */
   9396 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT)
   9397     uint32  entry_type=0;              /* Next Hop Entry_type */
   9398     uint32 label_action=-1;          /* MPLS Label Action */
   9399 #endif /* BCM_TRIUMPH_SUPPORT  && BCM_MPLS_SUPPORT */
   9400 
   9401     /*  Make sure module was initialized. */
   9402     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   9403         return (BCM_E_INIT);
   9404     }
   9405 
   9406     /* Input parameters check. */
   9407     if (NULL == nh_info) {
   9408         return (BCM_E_PARAM);
   9409     } else {
   9410         bcm_l3_egress_t_init (nh_info);
   9411     }
   9412 
   9413     /* Make sure entry is inuse. */
   9414     if (!BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, next_hop), nh_idx)) {
   9415         return (BCM_E_NOT_FOUND);
   9416     }
   9417 
   9418     /* Get next hop entry from hw. */
   9419     if (BCM_XGS3_L3_HWCALL_CHECK(unit, nh_get)) {
   9420         BCM_XGS3_L3_MODULE_LOCK(unit);
   9421         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, nh_get) (unit, nh_idx, nh_info);
   9422         BCM_XGS3_L3_MODULE_UNLOCK(unit);
   9423         BCM_IF_ERROR_RETURN(rv);
   9424     }
   9425 #if defined(BCM_TRIDENT2_SUPPORT)
   9426     if ( soc_feature(unit, soc_feature_vxlan)) {
   9427          rv = bcm_td2_vxlan_egress_get(unit, nh_info, nh_idx);
   9428          BCM_IF_ERROR_RETURN(rv);
   9429     }
   9430 #endif /* BCM_TRIDENT2_SUPPORT */
   9431 #if defined(BCM_GREYHOUND2_SUPPORT)
   9432     if (soc_feature(unit, soc_feature_vxlan_lite)) {
   9433         rv = bcmi_gh2_vxlan_egress_get(unit, nh_info, nh_idx);
   9434         BCM_IF_ERROR_RETURN(rv);
   9435     }
   9436 #endif /* BCM_GREYHOUND2_SUPPORT */
   9437 #if defined(BCM_TRIUMPH3_SUPPORT)
   9438     if ( soc_feature(unit, soc_feature_l2gre)) {
   9439          rv = bcm_tr3_l2gre_egress_get(unit, nh_info, nh_idx);
   9440          BCM_IF_ERROR_RETURN(rv);
   9441     }
   9442 #endif /* BCM_TRIUMPH3_SUPPORT */
   9443 
   9444 #if defined(BCM_TRIDENT_SUPPORT)
   9445     if ( soc_feature(unit, soc_feature_trill)) {
   9446          rv = bcm_td_trill_egress_get(unit, nh_info, nh_idx);
   9447          BCM_IF_ERROR_RETURN(rv);
   9448     }
   9449 #endif /* BCM_TRIDENT_SUPPORT */
   9450 
   9451 #if defined(BCM_TRIDENT3_SUPPORT)
   9452     if ( soc_feature(unit, soc_feature_flex_flow)) {
   9453          rv = _bcm_td3_flow_egress_get(unit, nh_info, nh_idx);
   9454          BCM_IF_ERROR_RETURN(rv);
   9455     }
   9456 #endif /* BCM_TRIDENT3_SUPPORT */
   9457 
   9458 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT)
   9459     if (SOC_IS_TR_VL(unit) && (soc_feature(unit, soc_feature_mpls))) {
   9460         BCM_IF_ERROR_RETURN(
   9461                bcm_tr_mpls_get_entry_type(unit, nh_idx, &entry_type));
   9462         if (entry_type == 1) {
   9463               BCM_IF_ERROR_RETURN(
   9464                      bcm_tr_mpls_get_label_action(unit, nh_idx, &label_action));
   9465 
   9466               switch (label_action) {
   9467                   case _BCM_MPLS_ACTION_NOOP:
   9468                   case _BCM_MPLS_ACTION_PUSH:
   9469 
   9470                       BCM_IF_ERROR_RETURN(
   9471                            bcm_tr_mpls_l3_label_get (unit, nh_idx, nh_info));
   9472                       break;
   9473 
   9474                   case _BCM_MPLS_ACTION_SWAP:
   9475                   case _BCM_MPLS_ACTION_PRESERVED:
   9476 #if defined(BCM_TOMAHAWK3_SUPPORT)
   9477                        if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
   9478                            BCM_IF_ERROR_RETURN(
   9479                                 bcm_th3_mpls_swap_nh_info_get (unit, nh_info, nh_idx));
   9480                        } else
   9481 #endif
   9482                        {
   9483 
   9484                            BCM_IF_ERROR_RETURN(
   9485                                 bcm_tr_mpls_swap_nh_info_get (unit, nh_info, nh_idx));
   9486                        }
   9487                       break;
   9488 
   9489                   default:
   9490                       break;
   9491               }
   9492         }
   9493     }
   9494 #endif /* BCM_TRX_SUPPORT  && BCM_MPLS_SUPPORT */
   9495 
   9496 #if defined(BCM_TRIUMPH2_SUPPORT)
   9497     if (soc_feature(unit, soc_feature_failover))  {
   9498          int prot_nh_index =-1;
   9499          int prot_mc_group=-1;
   9500          rv = _bcm_esw_failover_prot_nhi_get (unit, nh_idx,
   9501                     &nh_info->failover_id, &prot_nh_index, &prot_mc_group);
   9502          if ( rv != BCM_E_NONE ) {
   9503               return rv;
   9504          } else {
   9505               if (prot_nh_index != -1) {
   9506                   if (nh_info->failover_id != 0) {
   9507                       nh_info->failover_if_id = prot_nh_index + BCM_XGS3_EGRESS_IDX_MIN(unit);
   9508                   }
   9509               }
   9510               if (prot_mc_group != -1) {
   9511                   nh_info->failover_mc_group = prot_mc_group;
   9512               }
   9513          }
   9514     }
   9515 #endif /* BCM_TRIUMPH2_SUPPORT  */
   9516     return rv;
   9517 }
   9518 
   9519 /*
   9520  * Function:
   9521  *      _bcm_xgs3_nh_ent_cmp
   9522  * Purpose:
   9523  *      Routine compares next hop entry with entry in the chip
   9524  *      with specified index.
   9525  *      NOTE: It is safer to compare entries in hw format after
   9526  *            proper validation & mapping of api data.
   9527  *            Hence next hop entry expected to be in HW format!
   9528  *            Please see  _bcm_xgs3_nh_map_api_data_to_hw.
   9529  *
   9530  * Parameters:
   9531  *      unit       - (IN) SOC unit number.
   9532  *      buf        - (IN) First nh entry to compare.
   9533  *      index      - (IN) Entry index in the chip to compare.
   9534  *      cmp_result - (OUT)Compare result.
   9535  * Returns:
   9536  *      BCM_E_XXX
   9537  */
   9538 STATIC int
   9539 _bcm_xgs3_nh_ent_cmp(int unit, void *buf, int index, int *cmp_result)
   9540 {
   9541     bcm_l3_egress_t nh_hw;    /* Next hop entry from hw.  */
   9542     bcm_l3_egress_t *nh_entry;        /* Next hop entry from api. */
   9543 
   9544     if ((NULL == buf) || (NULL == cmp_result))
   9545         return (BCM_E_PARAM);
   9546 
   9547     /* Get api entry info. */
   9548     nh_entry = (bcm_l3_egress_t *) buf;
   9549 
   9550     /* Get next hop entry from hw. */
   9551     BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, index, &nh_hw));
   9552 
   9553 #ifdef BCM_GREYHOUND_SUPPORT
   9554     if (soc_feature(unit, soc_feature_l3mc_use_egress_next_hop)){
   9555         if (nh_entry->flags & BCM_L3_IPMC) {
   9556 
   9557             /* Entry type */
   9558             if (!(nh_hw.flags & BCM_L3_IPMC)) {
   9559                 *cmp_result = BCM_L3_CMP_NOT_EQUAL;
   9560                 return (BCM_E_NONE);
   9561             }
   9562 
   9563             /* INTF_NUM */
   9564             if (nh_hw.intf != nh_entry->intf) {
   9565                 *cmp_result = BCM_L3_CMP_NOT_EQUAL;
   9566                 return (BCM_E_NONE);
   9567             }
   9568 
   9569             /* L3MC_USE_CONFIGURED_MAC */
   9570             if ((nh_hw.flags ^ nh_entry->flags) & BCM_L3_KEEP_DSTMAC) {
   9571                 *cmp_result = BCM_L3_CMP_NOT_EQUAL;
   9572                 return (BCM_E_NONE);
   9573             }
   9574 
   9575             /* MAC_ADDRESS */
   9576             if (sal_memcmp(nh_hw.mac_addr, nh_entry->mac_addr,
   9577                     sizeof(bcm_mac_t))) {
   9578                 *cmp_result = BCM_L3_CMP_NOT_EQUAL;
   9579                 return (BCM_E_NONE);
   9580             }
   9581 
   9582             *cmp_result = BCM_L3_CMP_EQUAL;
   9583             return (BCM_E_NONE);
   9584         }
   9585     }
   9586 #endif /* BCM_GREYHOUND_SUPPORT */
   9587 
   9588     /*
   9589      *  Compare entries in hw format. Should never fail, we just read it.
   9590      *  NOTE  bcm_xgs3_nh_get returns entry in API format.
   9591      */
   9592     _bcm_xgs3_nh_map_api_data_to_hw(unit, &nh_hw);
   9593 
   9594     /* Compare trunk flag */
   9595     if ((nh_hw.flags & BCM_L3_TGID) != (nh_entry->flags & BCM_L3_TGID)) {
   9596         *cmp_result = BCM_L3_CMP_NOT_EQUAL;
   9597         return (BCM_E_NONE);
   9598     }
   9599 
   9600     /* Compare port/trunk id. */
   9601     if (nh_hw.port != nh_entry->port) {
   9602         *cmp_result = BCM_L3_CMP_NOT_EQUAL;
   9603         return (BCM_E_NONE);
   9604     }
   9605 
   9606     /* Module Id. */
   9607     if (nh_hw.module != nh_entry->module) {
   9608         *cmp_result = BCM_L3_CMP_NOT_EQUAL;
   9609         return (BCM_E_NONE);
   9610     }
   9611 
   9612     /* Interface compare. */
   9613     if (nh_hw.intf != nh_entry->intf) {
   9614         *cmp_result = BCM_L3_CMP_NOT_EQUAL;
   9615         return (BCM_E_NONE);
   9616     }
   9617 
   9618     /* Mac compare */
   9619     if (sal_memcmp(nh_hw.mac_addr, nh_entry->mac_addr, sizeof(bcm_mac_t))) {
   9620         *cmp_result = BCM_L3_CMP_NOT_EQUAL;
   9621         return (BCM_E_NONE);
   9622     }
   9623 #ifdef BCM_FIREBOLT_SUPPORT
   9624     /* Tunnel type compare. */
   9625     if (SOC_IS_FBX(unit)) {
   9626         /* If the intf is reserved, bypass vlan check */
   9627         if (nh_hw.intf != BCM_XGS3_L3_L2CPU_INTF_IDX(unit) && 
   9628                 !BCM_XGS3_L3_INTF_VLAN_SPLIT_EGRESS_MODE_ISSET(unit)) {
   9629             /* Vlan id compare. */
   9630             if (nh_hw.vlan != nh_entry->vlan) {
   9631                 *cmp_result = BCM_L3_CMP_NOT_EQUAL;
   9632                 return (BCM_E_NONE);
   9633             }
   9634         }
   9635     }
   9636 #endif /* BCM_FIREBOLT_SUPPORT */
   9637 
   9638     /* Encap ID compare */
   9639     if (nh_hw.encap_id != nh_entry->encap_id) {
   9640         *cmp_result = BCM_L3_CMP_NOT_EQUAL;
   9641         return (BCM_E_NONE);
   9642     }
   9643 
   9644     /* BCM_L3_IPMC flag compare */
   9645     if ((nh_hw.flags & BCM_L3_IPMC) != (nh_entry->flags & BCM_L3_IPMC)) {
   9646         *cmp_result = BCM_L3_CMP_NOT_EQUAL;
   9647         return (BCM_E_NONE);
   9648     }
   9649 
   9650     /* Multicast group. */
   9651     if (((nh_hw.flags2 & BCM_L3_FLAGS2_MC_GROUP) != (nh_entry->flags2 & BCM_L3_FLAGS2_MC_GROUP)) ||
   9652         ((nh_hw.flags2 & BCM_L3_FLAGS2_MC_GROUP) && (nh_hw.mc_group != nh_entry->mc_group))) {
   9653         *cmp_result = BCM_L3_CMP_NOT_EQUAL;
   9654         return (BCM_E_NONE);
   9655     }
   9656 
   9657     *cmp_result = BCM_L3_CMP_EQUAL;
   9658     return (BCM_E_NONE);
   9659 }
   9660 
   9661 #ifdef BCM_TRIDENT3_SUPPORT
   9662 STATIC int
   9663 _bcm_l3_get_flex_entry_width (int unit, bcm_l3_egress_t *nh_info, uint32 *width) {
   9664 
   9665     uint32 view_id;
   9666     soc_flow_db_mem_view_info_t mem_view_info;
   9667 
   9668     BCM_IF_ERROR_RETURN(
   9669         soc_flow_db_ffo_to_mem_view_id_get(unit,
   9670                           nh_info->flow_handle,
   9671                           nh_info->flow_option_handle,
   9672                           SOC_FLOW_DB_FUNC_EGRESS_OBJ_ID,
   9673                           &view_id));
   9674 
   9675     BCM_IF_ERROR_RETURN(
   9676         soc_flow_db_mem_view_info_get(unit,
   9677                           view_id,
   9678                           &mem_view_info));
   9679 
   9680     if (mem_view_info.width > 2*BCMI_TD3_EGR_L3_NEXTHOP_WIDTH) {
   9681         return BCM_E_INTERNAL;
   9682     }
   9683     else if (mem_view_info.width > BCMI_TD3_EGR_L3_NEXTHOP_WIDTH) {
   9684         *width = _BCM_DOUBLE_WIDE;
   9685     }
   9686     else {
   9687         *width = _BCM_SINGLE_WIDE;
   9688     }
   9689     return BCM_E_NONE;
   9690 }
   9691 #endif
   9692 
   9693 /*
   9694  * Function:
   9695  *      bcm_xgs3_nh_add
   9696  * Purpose:
   9697  *       Allocate NextHop table index & Write NextHop entry.
   9698  *       Routine trying to match new entry to an existing one,
   9699  *       if match found reference cound is incremented, otherwise
   9700  *       new index allocated & entry added to hw.
   9701  * Parameters:
   9702  *      unit      - (IN)SOC unit number.
   9703  *      flags     - (IN)Egress object flags.
   9704  *      nh_info   - (IN)Next hop  entry info.
   9705  *      index     - (OUT)Next hop index.
   9706  * Returns:
   9707  *    BCM_E_XXX
   9708  */
   9709 int
   9710 bcm_xgs3_nh_add(int unit, uint32 flags, bcm_l3_egress_t *nh_info, int *index)
   9711 {
   9712     _bcm_l3_tbl_op_t data;        /* Operation data. */
   9713 
   9714 #ifdef BCM_MULTI_LEVEL_FAILOVER_SUPPORT
   9715     uint32 *nh_multi_count;
   9716     int backup_min_index;
   9717     ing_l3_next_hop_entry_t ing_nh;
   9718     int i = 0;
   9719     int rv = BCM_E_NONE;
   9720 #endif
   9721 
   9722     /*  Make sure module was initialized. */
   9723     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   9724         return (BCM_E_INIT);
   9725     }
   9726 
   9727     /* Input parameters check. */
   9728     if (NULL == nh_info) {
   9729         return (BCM_E_PARAM);
   9730     }
   9731 
   9732     if (!(flags & _BCM_L3_SHR_WRITE_DISABLE)) {
   9733         /* Make sure hw call is defined. */
   9734         if (!BCM_XGS3_L3_HWCALL_CHECK(unit, nh_add)) {
   9735             return (BCM_E_UNAVAIL);
   9736         }
   9737 
   9738         /* Convert API next hop entry to HW space format. */
   9739         BCM_IF_ERROR_RETURN(_bcm_xgs3_nh_map_api_data_to_hw(unit, nh_info));
   9740     }
   9741 
   9742     /* Initialization */
   9743     sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t));
   9744     data.tbl_ptr =  BCM_XGS3_L3_TBL_PTR(unit, next_hop);
   9745     data.width = _BCM_SINGLE_WIDE;
   9746     data.oper_flags = flags;
   9747     data.entry_buffer = (void *)nh_info;
   9748     data.hash_func = _bcm_xgs3_nh_hash_calc;
   9749     data.cmp_func  = _bcm_xgs3_nh_ent_cmp;
   9750     data.add_func  = BCM_XGS3_L3_HWCALL(unit, nh_add);
   9751     if (flags & _BCM_L3_SHR_WITH_ID) {
   9752         data.entry_index = *index;
   9753     }
   9754 #ifdef BCM_MULTI_LEVEL_FAILOVER_SUPPORT
   9755     backup_min_index     = data.tbl_ptr->idx_min;
   9756     if (_BCM_FAILOVER_IS_MULTI_LEVEL(nh_info->failover_id)) {
   9757         if (((BCM_XGS3_L3_EGRESS_IDX_VALID(unit, nh_info->failover_if_id) ||
   9758             BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, nh_info->failover_if_id )) &&
   9759             (bcmi_l3_nh_multi_count_get(unit, *index) < 4)) ||
   9760              (nh_info->failover_mc_group > 0)) {
   9761             /* if user wants to create a failover nhi with
   9762              * a multi level failover and different NH, then we
   9763              * will have to reserve two NHs as we will point to
   9764              * a separate prot nhi table of double wide entry.
   9765              */
   9766 
   9767             data.width = _BCM_DOUBLE_WIDE;
   9768             /* Set up the limits for indexes */
   9769             backup_min_index     = data.tbl_ptr->idx_min;
   9770             data.tbl_ptr->idx_min = 2;
   9771         }
   9772     }
   9773 #endif
   9774 #ifdef BCM_TRIDENT3_SUPPORT
   9775     /* Get view id corresponding to the specified flow. */
   9776 
   9777     if (soc_feature(unit, soc_feature_flex_flow) &&
   9778         nh_info->flow_handle != 0) {
   9779 
   9780         BCM_IF_ERROR_RETURN(
   9781             _bcm_l3_get_flex_entry_width(unit, nh_info, (uint32 *) &data.width));
   9782     }
   9783 #endif
   9784     /* Add next hop table entry. */
   9785     BCM_IF_ERROR_RETURN(_bcm_xgs3_tbl_add(unit, &data));
   9786     *index = data.entry_index;
   9787 #ifdef BCM_TRIDENT_SUPPORT
   9788     if (soc_feature(unit, soc_feature_trill) &&
   9789         (nh_info->flags & BCM_L3_TRILL_ONLY)) {
   9790         BCM_XGS3_L3_ENT_FLAG_SET(data.tbl_ptr, data.entry_index,
   9791                                  data.width, _BCM_L3_TRILL_ONLY);
   9792     }
   9793 #endif /* BCM_TRIDENT_SUPPORT */
   9794 #ifdef BCM_TRIUMPH3_SUPPORT
   9795     if (soc_feature(unit, soc_feature_l2gre) &&
   9796         (nh_info->flags & BCM_L3_L2GRE_ONLY)) {
   9797         BCM_XGS3_L3_ENT_FLAG_SET(data.tbl_ptr, data.entry_index,
   9798                                  data.width, _BCM_L3_L2GRE_ONLY);
   9799     }
   9800 #endif /* BCM_TRIUMPH3_SUPPORT */
   9801 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)
   9802     if ((soc_feature(unit, soc_feature_vxlan) ||
   9803         soc_feature(unit, soc_feature_vxlan_lite)) &&
   9804         (nh_info->flags & BCM_L3_VXLAN_ONLY)) {
   9805         BCM_XGS3_L3_ENT_FLAG_SET(data.tbl_ptr, data.entry_index,
   9806                                  data.width, _BCM_L3_VXLAN_ONLY);
   9807     }
   9808 #endif /* BCM_TRIDENT2_SUPPORT || BCM_GREYHOUND2_SUPPORT */
   9809 #ifdef BCM_TRIDENT3_SUPPORT
   9810     if (soc_feature(unit, soc_feature_flex_flow) &&
   9811         (nh_info->flags2 & BCM_L3_FLOW_ONLY)) {
   9812         BCM_XGS3_L3_ENT_FLAG_SET(data.tbl_ptr, data.entry_index,
   9813                                  data.width, _BCM_L3_FLOW_ONLY);
   9814     }
   9815 #endif /* BCM_TRIDENT3_SUPPORT */
   9816 #ifdef BCM_TRIDENT_SUPPORT
   9817     if (soc_feature(unit, soc_feature_nh_for_ifp_actions) && 
   9818         (nh_info->flags2 & BCM_L3_FLAGS2_FIELD_ONLY)) {
   9819         BCM_XGS3_L3_ENT_FLAG_SET(data.tbl_ptr, data.entry_index,
   9820                                  data.width, _BCM_L3_FIELD_ONLY);
   9821     }        
   9822 #endif
   9823 #ifdef BCM_TRIDENT2_SUPPORT
   9824         if (soc_feature(unit, soc_feature_redirect_nh_to_ecmp_for_mpls_php) &&
   9825             (nh_info->flags2 & BCM_L3_FLAGS2_MPLS_PHP)) {
   9826             BCM_XGS3_L3_ENT_FLAG_SET(data.tbl_ptr, data.entry_index,
   9827                                      data.width, _BCM_L3_MPLS_PHP);
   9828         }
   9829 #endif /* BCM_TRIDENT2_SUPPORT */
   9830 #ifdef BCM_TRIDENT2_SUPPORT
   9831         if (soc_feature(unit, soc_feature_fcoe) &&
   9832             (nh_info->flags2 & BCM_L3_FLAGS2_FCOE_ONLY)) {
   9833             BCM_XGS3_L3_ENT_FLAG_SET(data.tbl_ptr, data.entry_index,
   9834                                      data.width, _BCM_L3_FCOE_ONLY);
   9835         }
   9836 #endif
   9837 
   9838     if ((BCM_XGS3_L3_ENT_REF_CNT(data.tbl_ptr, data.entry_index) == 1) &&
   9839         !((data.oper_flags & _BCM_L3_SHR_WITH_ID) &&
   9840         (data.oper_flags & _BCM_L3_SHR_UPDATE))) {
   9841         BCM_XGS3_L3_NH_CNT(unit)+= data.width;
   9842     }
   9843 
   9844 #ifdef BCM_MULTI_LEVEL_FAILOVER_SUPPORT
   9845     data.tbl_ptr->idx_min = backup_min_index;
   9846     if (soc_feature(unit, soc_feature_hierarchical_protection)) {
   9847         if (bcmi_l3_nh_multi_count_get(unit, *index) < 4) {
   9848             nh_multi_count = BCM_XGS3_L3_NH_MULTI_COUNT(unit);
   9849             nh_multi_count[*index] = data.width;
   9850         }
   9851         /*
   9852          *  In the allocated NHs, we will have to write some info.
   9853          *  Otherwise, we may neglect this NH while recovering from
   9854          *  warmboot thinking that this is null entry.
   9855          */
   9856         if (data.width > 1) {
   9857             soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, DROPf, 1);
   9858             for (i=1; i<data.width; i++) {
   9859                 rv = soc_mem_write (unit, ING_L3_NEXT_HOPm,
   9860                             MEM_BLOCK_ALL, data.entry_index + i, &ing_nh);
   9861                 if (BCM_FAILURE(rv)) {
   9862                     return rv;
   9863                 }
   9864             }
   9865         }
   9866     }
   9867 #endif
   9868     return (BCM_E_NONE);
   9869 }
   9870 
   9871 /*
   9872  * Function:
   9873  *      bcm_xgs3_nh_del
   9874  * Purpose:
   9875  *      Delete NextHop entry.
   9876  *      Entry kept if reference counter not equals to 1(Other hosts/routes
   9877  *      reference the same entry).
   9878  *
   9879  * Parameters:
   9880  *      unit      - (IN)SOC unit number.
   9881  *      flags     - (IN)Egress object flags.
   9882  *      nh_index  - (IN)next hop index.
   9883  * Returns:
   9884  *    BCM_E_XXX
   9885  */
   9886 int
   9887 bcm_xgs3_nh_del(int unit, uint32 flags, int nh_index)
   9888 {
   9889     _bcm_l3_tbl_op_t data;        /* Operation data. */
   9890     int rv = BCM_E_NONE;
   9891     int no_of_elements = 1;
   9892     int i = 0;
   9893 #ifdef BCM_MULTI_LEVEL_FAILOVER_SUPPORT
   9894     uint32 *nh_multi_count;
   9895 #endif
   9896 
   9897     /*  Make sure module was initialized. */
   9898     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   9899         return (BCM_E_INIT);
   9900     }
   9901 
   9902     /* For egress mode, nh_index could be BCM_XGS3_L3_INVALID_INDEX */
   9903     if (nh_index < 0) {
   9904         return (BCM_E_NONE);
   9905     }
   9906 
   9907     if (!(flags & _BCM_L3_SHR_WRITE_DISABLE)) {
   9908         /*  Make sure hw call is registred. */
   9909         if (!BCM_XGS3_L3_HWCALL_CHECK(unit, nh_del)) {
   9910             return (BCM_E_UNAVAIL);
   9911         }
   9912     }
   9913 #ifdef BCM_MULTI_LEVEL_FAILOVER_SUPPORT
   9914    if (soc_feature(unit, soc_feature_hierarchical_protection)) {
   9915         nh_multi_count = BCM_XGS3_L3_NH_MULTI_COUNT(unit);
   9916         no_of_elements = nh_multi_count[nh_index];;
   9917     }
   9918     no_of_elements = ((no_of_elements > 1)? no_of_elements : 1);
   9919 #endif
   9920 
   9921 #if defined(BCM_TRIDENT3_SUPPORT)
   9922     if (soc_feature(unit, soc_feature_flex_flow) &&
   9923        (flags & _BCM_L3_SHR_WIDE_FLEX_ENTRY)) {
   9924         no_of_elements = 2;
   9925     }
   9926 #endif
   9927     /* Initialization */
   9928     sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t));
   9929     data.tbl_ptr =  BCM_XGS3_L3_TBL_PTR(unit, next_hop);
   9930     data.entry_index = nh_index;
   9931     data.width = _BCM_SINGLE_WIDE;
   9932     data.oper_flags = flags;
   9933     data.delete_func = BCM_XGS3_L3_HWCALL(unit, nh_del);
   9934 
   9935     /* Don't touch reserved trap to cpu entry. */
   9936     if (nh_index == BCM_XGS3_L3_L2CPU_NH_IDX(unit)) {
   9937         if (BCM_XGS3_L3_ENT_REF_CNT(data.tbl_ptr, nh_index) > 1) {
   9938             BCM_XGS3_L3_ENT_REF_CNT_DEC(data.tbl_ptr, nh_index,
   9939                                         _BCM_SINGLE_WIDE);
   9940         }
   9941         return (BCM_E_NONE);
   9942     }
   9943     for (i=0; i<no_of_elements; i++) {
   9944         /* Delete next hop table entry. */
   9945         data.entry_index = nh_index + i;
   9946         if (BCM_XGS3_L3_ENT_REF_CNT(data.tbl_ptr, nh_index+i) == 1) {
   9947             BCM_XGS3_L3_NH_CNT(unit)--;
   9948         }
   9949 
   9950         /* Delete next hop table entry. */
   9951         rv = _bcm_xgs3_tbl_del(unit, &data) ;
   9952         if (BCM_FAILURE(rv)) {
   9953             return rv;
   9954         }
   9955     }
   9956     return BCM_E_NONE;
   9957 }
   9958 
   9959 /*
   9960  * Function:
   9961  *      bcm_xgs3_get_nh_from_egress_object
   9962  * Purpose:
   9963  *       Extract next hop id/Ecmp group id from egress object.
   9964  *       Increment next hop/ecmp group  reference count
   9965  * Parameters:
   9966  *      unit      - (IN)SOC unit number.
   9967  *      intf      - (IN)L3 egress object id.
   9968  *      mpath_flag     - (OUT) multipath indicator
   9969  *      ref_count - (IN) Flag to increment reference_count.
   9970  *      index     - (OUT)Next hop index.
   9971  * Returns:
   9972  *    BCM_E_XXX
   9973  */
   9974 int
   9975 bcm_xgs3_get_nh_from_egress_object(int unit, bcm_if_t intf,
   9976                                     uint32 *mpath_flag, int ref_count, int *index)
   9977 {
   9978     int width;
   9979 
   9980     if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf) ||
   9981         BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) {
   9982 
   9983         /* Extract next hop index from unipath egress object. */
   9984         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) {
   9985             *index = intf - BCM_XGS3_EGRESS_IDX_MIN(unit);
   9986         } else {
   9987             *index = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   9988         }
   9989         *mpath_flag = 0;
   9990 
   9991         /* Make sure next hop is in use. */
   9992         if (!BCM_XGS3_L3_ENT_REF_CNT
   9993                  (BCM_XGS3_L3_TBL_PTR(unit, next_hop), *index)) {
   9994             return (BCM_E_PARAM);
   9995         }
   9996 
   9997         /* Increment next hop reference count. */
   9998         if (ref_count) {
   9999             BCM_XGS3_L3_ENT_REF_CNT_INC
  10000                 (BCM_XGS3_L3_TBL_PTR(unit, next_hop), *index, _BCM_SINGLE_WIDE);
  10001         }
  10002     } else if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf)) {
  10003 
  10004         /* Extract ecmp group index from multipath egress object. */
  10005         *index = intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  10006 
  10007         *mpath_flag = BCM_L3_MULTIPATH;
  10008 
  10009         /* Make sure ecmp group is in use. */
  10010 #ifdef BCM_TOMAHAWK3_SUPPORT
  10011         if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) &&
  10012             (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  10013             ecmp_mode_hierarchical) && (*index <
  10014                    (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) {
  10015             if (!BCM_XGS3_L3_ENT_REF_CNT
  10016                      (BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp), *index)) {
  10017                 return (BCM_E_PARAM);
  10018             }
  10019         } else
  10020 #endif
  10021         if (!BCM_XGS3_L3_ENT_REF_CNT
  10022                  (BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), *index)) {
  10023             return (BCM_E_PARAM);
  10024         }
  10025 
  10026         if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  10027             width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  10028                     _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  10029         } else {
  10030             width = _BCM_SINGLE_WIDE;
  10031         }
  10032 
  10033         if (SOC_IS_SCORPION(unit)) {
  10034             BCM_IF_ERROR_RETURN(
  10035                 bcm_xgs3_l3_egress_ecmp_max_paths_get(unit, intf, &width, NULL));
  10036         }
  10037 
  10038         /* Increment ecmp group reference count. */
  10039         if (ref_count) {
  10040 #if defined(BCM_TOMAHAWK3_SUPPORT)
  10041             if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) &&
  10042                 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  10043                 ecmp_mode_hierarchical) && (*index <
  10044                 (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) {
  10045                 BCM_XGS3_L3_ENT_REF_CNT_INC
  10046                     (BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp), *index, width);
  10047             } else
  10048 #endif
  10049             {
  10050                 BCM_XGS3_L3_ENT_REF_CNT_INC
  10051                     (BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), *index, width);
  10052             }
  10053         }
  10054     } else if (BCM_XGS3_PROXY_EGRESS_IDX_VALID(unit, intf)) {
  10055         /* Extract ecmp group index from multipath egress object. */
  10056         *index = intf - BCM_XGS3_PROXY_EGRESS_IDX_MIN(unit);
  10057 
  10058         *mpath_flag = 0;
  10059         /* Make sure next hop is in use. */
  10060         if (!BCM_XGS3_L3_ENT_REF_CNT
  10061                  (BCM_XGS3_L3_TBL_PTR(unit, next_hop), *index)) {
  10062             return (BCM_E_PARAM);
  10063         }
  10064 
  10065         /* Increment next hop reference count. */
  10066         if (ref_count) {
  10067             BCM_XGS3_L3_ENT_REF_CNT_INC
  10068                 (BCM_XGS3_L3_TBL_PTR(unit, next_hop), *index, _BCM_SINGLE_WIDE);
  10069         }
  10070     } else {
  10071         if (soc_feature(unit, soc_feature_l3_extended_host_entry)) {
  10072             /* This is a valid for TR3 and TD2, i.e., egress mode is set, but
  10073              * the intf passed does not correspond to an egress object
  10074              * indicating that a host entry with embedded next hop has
  10075              * been specified */
  10076              if (intf >= BCM_XGS3_L3_IF_TBL_SIZE(unit)) {
  10077                  return BCM_E_PARAM;
  10078              }
  10079              *index = BCM_XGS3_L3_INVALID_INDEX;
  10080              return (BCM_E_NONE);
  10081         } else {
  10082             /* Invalid egress object id specified. */
  10083             return (BCM_E_PARAM);
  10084         }
  10085     }
  10086     return (BCM_E_NONE);
  10087 }
  10088 
  10089 /*
  10090  * Function:
  10091  *      bcm_xgs3_get_ref_count_from_nhi
  10092  * Purpose:
  10093  *       Extract  egress/multipath object from next hop id/Ecmp group
  10094  *       Decrement next hop/ecmp group  reference count
  10095  * Parameters:
  10096  *      unit      - (IN)SOC unit number.
  10097  *      flags     - (IN)Caller flags (eg Multipath route).
  10098  *      ref_count - (IN) pointer to reference_count.
  10099  *      index     - (OUT)Next hop index.
  10100  * Returns:
  10101  *    BCM_E_XXX
  10102  */
  10103 int
  10104 bcm_xgs3_get_ref_count_from_nhi(int unit, uint32 flags, int *ref_count, int nh_ecmp_index)
  10105 {
  10106    int count=0;
  10107    int width;
  10108    _bcm_l3_tbl_t *tbl_ptr;      /* ECMP table pointer. */
  10109 
  10110     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  10111 
  10112     if ((flags & BCM_L3_MULTIPATH)) {
  10113 
  10114         /* Make sure ecmp group is in use. */
  10115 #if defined(BCM_TOMAHAWK3_SUPPORT)
  10116         if ((BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  10117              ecmp_mode_hierarchical) && (nh_ecmp_index <
  10118                (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2)) &&
  10119                (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl))) {
  10120             tbl_ptr =  BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp);
  10121         }
  10122 #endif
  10123         count = BCM_XGS3_L3_ENT_REF_CNT
  10124                  (tbl_ptr, nh_ecmp_index);
  10125 
  10126         if (count <= 1) {
  10127             *ref_count = count;
  10128             return (BCM_E_NONE);
  10129         }
  10130         
  10131         width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ? 
  10132         _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  10133         
  10134         /* Decrement ecmp group reference count. */
  10135         BCM_XGS3_L3_ENT_REF_CNT_DEC
  10136                 (tbl_ptr, nh_ecmp_index, width);
  10137         *ref_count = BCM_XGS3_L3_ENT_REF_CNT
  10138                  (tbl_ptr, nh_ecmp_index);
  10139 
  10140     } else {
  10141 
  10142         /* Make sure next hop is in use. */
  10143         count = BCM_XGS3_L3_ENT_REF_CNT
  10144                  (BCM_XGS3_L3_TBL_PTR(unit, next_hop), nh_ecmp_index);
  10145 
  10146         if (count <= 1) {
  10147             *ref_count = count;
  10148             return (BCM_E_NONE);
  10149         }
  10150 
  10151         /* Decrement next hop reference count. */
  10152         BCM_XGS3_L3_ENT_REF_CNT_DEC
  10153                 (BCM_XGS3_L3_TBL_PTR(unit, next_hop), nh_ecmp_index, _BCM_SINGLE_WIDE);
  10154 
  10155         *ref_count = BCM_XGS3_L3_ENT_REF_CNT
  10156                  (BCM_XGS3_L3_TBL_PTR(unit, next_hop), nh_ecmp_index);
  10157 
  10158     }
  10159     return (BCM_E_NONE);
  10160 }
  10161 
  10162 /*
  10163  * Function:
  10164  *      _bcm_xgs3_nh_init_add
  10165  * Purpose:
  10166  *       Initialize next hop entry.
  10167  *       Allocate NextHop table index & Write NextHop entry.
  10168  *       Routine trying to match new entry to an existing one,
  10169  *       if match found reference cound is incremented, otherwise
  10170  *       new index allocated & entry added to hw.
  10171  * Parameters:
  10172  *      unit      - (IN)SOC unit number.
  10173  *      l3cfg     - (IN)L3 host entry.
  10174  *  OR  <- We always get next hop index either for host OR for a route.
  10175  *      lpm_cfg   - (IN)Route entry.
  10176  *      index     - (OUT)Next hop index.
  10177  * Returns:
  10178  *    BCM_E_XXX
  10179  */
  10180 
  10181 int
  10182 _bcm_xgs3_nh_init_add(int unit, _bcm_l3_cfg_t *l3cfg,
  10183                       _bcm_defip_cfg_t *lpm_cfg, int *index)
  10184 {
  10185     bcm_if_t intf;            /* Egress interface index. */
  10186     uint32 flags=0;             /* Next hop entry flags.   */
  10187     bcm_l3_egress_t nh_entry; /* Next hop entry.         */
  10188 
  10189     /* Input parameters check. */
  10190     if ((NULL == index) || ((NULL == l3cfg) && (NULL == lpm_cfg)) ||
  10191         ((NULL != l3cfg) && (NULL != lpm_cfg))) {
  10192         return (BCM_E_PARAM);
  10193     }
  10194 
  10195 
  10196 
  10197     /* Check if egress switching mode is enabled. */
  10198     if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  10199         /* Get egress object id. */
  10200         intf = (NULL != l3cfg) ? l3cfg->l3c_intf : lpm_cfg->defip_intf;
  10201         flags = (NULL != lpm_cfg) ? (lpm_cfg->defip_flags & BCM_L3_MULTIPATH)
  10202                                   : (l3cfg->l3c_flags & BCM_L3_MULTIPATH);
  10203         if (l3cfg != NULL) {
  10204             if (l3cfg->l3c_flags & BCM_L3_L2TOCPU) {
  10205                 *index = BCM_XGS3_L3_L2CPU_NH_IDX(unit);
  10206             } else {
  10207                 return bcm_xgs3_get_nh_from_egress_object(unit, intf, &flags, 1, index);
  10208             }
  10209         } else {
  10210             if (lpm_cfg->defip_flags & BCM_L3_DEFIP_LOCAL) {
  10211                 *index = BCM_XGS3_L3_L2CPU_NH_IDX(unit);
  10212             } else {
  10213                 return bcm_xgs3_get_nh_from_egress_object(unit, intf, &flags, 1,
  10214                                                           index);
  10215             }
  10216         }
  10217     }
  10218 
  10219     *index = BCM_XGS3_L3_INVALID_INDEX;
  10220     /* Check if traffic should be trapped to cpu. */
  10221     if (l3cfg) {
  10222         if (l3cfg->l3c_flags & BCM_L3_L2TOCPU) {
  10223             *index = BCM_XGS3_L3_L2CPU_NH_IDX(unit);
  10224         }
  10225     } else if (lpm_cfg->defip_flags & BCM_L3_DEFIP_LOCAL) {
  10226         *index = BCM_XGS3_L3_L2CPU_NH_IDX(unit);
  10227     }
  10228     /* If packet should be trapped increment reference count and return. */
  10229     if (*index == BCM_XGS3_L3_L2CPU_NH_IDX(unit)) {
  10230         BCM_XGS3_L3_ENT_REF_CNT_INC((BCM_XGS3_L3_TBL_PTR(unit, next_hop)),
  10231                                     BCM_XGS3_L3_L2CPU_NH_IDX(unit), _BCM_SINGLE_WIDE);
  10232         *index = BCM_XGS3_L3_L2CPU_NH_IDX(unit);
  10233         return (BCM_E_NONE);
  10234     }
  10235 
  10236     /* Real entry required -> init next hop entry. */
  10237     BCM_IF_ERROR_RETURN
  10238         (_bcm_xgs3_nh_entry_init(unit, &nh_entry, l3cfg, lpm_cfg));
  10239 
  10240     /* Add next hop entry. */
  10241     /*    coverity[negative_returns : FALSE]    */
  10242     return bcm_xgs3_nh_add(unit, 0, &nh_entry, index);
  10243 }
  10244 
  10245 /*
  10246  * Function:
  10247  *      _bcm_xgs3_l3_get_nh_info
  10248  * Purpose:
  10249  *      Fill next hop info for l3 entry.
  10250  * Parameters:
  10251  *      unit   - SOC unit number.
  10252  *      l3cfg  - L3 entry to fill.
  10253  *      nh_idx - Next hop index.
  10254  * Returns:
  10255  *      BCM_E_XXX
  10256  */
  10257 int
  10258 _bcm_xgs3_l3_get_nh_info(int unit, _bcm_l3_cfg_t *l3cfg, int nh_idx)
  10259 {
  10260     bcm_l3_egress_t nh_info;  /* Next hop info buffer.    */
  10261 
  10262     /* In egress switching mode - set egress object id only. */
  10263     /* Depends on whether it is a regular L3 next hop or a WLAN DVP */
  10264     if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  10265 #ifdef BCM_TRIUMPH2_SUPPORT
  10266         egr_l3_next_hop_entry_t next_hop;
  10267         int entry_type;
  10268         if (soc_feature(unit, soc_feature_l3_extended_host_entry) &&
  10269             nh_idx == BCM_XGS3_L3_INVALID_INDEX) {
  10270             /* Embedded next hop entry, NH idx is not valid */
  10271             return (BCM_E_NONE);
  10272         }
  10273 
  10274         if (soc_feature(unit, soc_feature_wlan)) {
  10275             BCM_IF_ERROR_RETURN
  10276                 (READ_EGR_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY, nh_idx, &next_hop));
  10277             entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &next_hop,
  10278                                                           nh_entry_type_field[unit]);
  10279             if (entry_type == 4) {
  10280                 l3cfg->l3c_intf = nh_idx + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  10281             } else {
  10282                 l3cfg->l3c_intf = nh_idx + BCM_XGS3_EGRESS_IDX_MIN(unit);
  10283             }
  10284         } else
  10285 #endif
  10286         if(l3cfg->l3c_flags & BCM_L3_MULTIPATH) {
  10287             l3cfg->l3c_intf = nh_idx + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  10288         } else {
  10289             BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, nh_idx, &nh_info));
  10290             if ((nh_info.encap_id > 0 &&
  10291                 nh_info.encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit))
  10292 #ifdef BCM_RIOT_SUPPORT
  10293                 || (BCMI_RIOT_IS_ENABLED(unit) &&
  10294                     _bcm_vp_is_vfi_type(unit, nh_info.port))
  10295 #endif /* BCM_RIOT_SUPPORT */
  10296             ) {
  10297                 l3cfg->l3c_intf = nh_idx + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  10298             } else {
  10299                 l3cfg->l3c_intf = nh_idx + BCM_XGS3_EGRESS_IDX_MIN(unit);
  10300             }
  10301         }
  10302         return (BCM_E_NONE);
  10303     }
  10304 
  10305     /* If next hop is trap to cpu - don't read nh table. */
  10306     if (nh_idx == BCM_XGS3_L3_L2CPU_NH_IDX(unit)) {
  10307         /* Set flags to bridge to cpu. */
  10308         l3cfg->l3c_flags |= BCM_L3_L2TOCPU;
  10309         /* Set interface index to last one in the table. */
  10310         l3cfg->l3c_intf = BCM_XGS3_L3_L2CPU_INTF_IDX(unit);
  10311         /* Set module id to a local module. */
  10312         BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &l3cfg->l3c_modid));
  10313         /* No vlan/interface info. */
  10314         l3cfg->l3c_vid = 0;
  10315         l3cfg->l3c_tunnel = 0;
  10316         /* Set port to be a cpu port. */
  10317         l3cfg->l3c_port_tgid = CMIC_PORT(unit);
  10318         /* Reset mac address. */
  10319         sal_memset(l3cfg->l3c_mac_addr, 0, sizeof(bcm_mac_t));
  10320         /* Set host flags to trap to cpu. */
  10321         l3cfg->l3c_flags |= BCM_L3_L2TOCPU;
  10322         return (BCM_E_NONE);
  10323     }
  10324 
  10325     /* Get next hop entry from hw. */
  10326     BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, nh_idx, &nh_info));
  10327 
  10328     /* Fill next hop info to l3 entry. */
  10329     if (nh_info.flags & BCM_L3_TGID) {       /* Trunk */
  10330         l3cfg->l3c_flags |= BCM_L3_TGID;
  10331     }
  10332     /* Set module id. */
  10333     l3cfg->l3c_modid = nh_info.module;
  10334     /* Set trunk/port info. */
  10335     l3cfg->l3c_port_tgid =
  10336         (nh_info.flags & BCM_L3_TGID) ? nh_info.trunk : nh_info.port;
  10337     /* Set interface index. */
  10338     l3cfg->l3c_intf = nh_info.intf;
  10339     /* Set physical address. */
  10340     sal_memcpy(l3cfg->l3c_mac_addr, nh_info.mac_addr, sizeof(bcm_mac_t));
  10341     /* Get tunnel id info. */
  10342     BCM_IF_ERROR_RETURN
  10343         (_bcm_xgs3_l3_get_tunnel_id(unit, nh_info.intf, &l3cfg->l3c_tunnel));
  10344 #ifdef BCM_FIREBOLT_SUPPORT
  10345     if (SOC_IS_FBX(unit)) {
  10346         l3cfg->l3c_vid = nh_info.vlan;
  10347     }
  10348 #endif /* BCM_FIREBOLT_SUPPORT */
  10349     return (BCM_E_NONE);
  10350 }
  10351 
  10352 /*
  10353  * Function:
  10354  *      _bcm_xgs3_l3_ecmp_1k_groups_info_get
  10355  * Purpose:
  10356  *      Get ecmp group size and base idx for the chips with 1K ecmp groups,
  10357  *      especially for TD+ with configurable 256/1k ecmp groups meantime.
  10358  * Parameters:
  10359  *      unit          - (IN) SOC unit number.
  10360  *      grp_idx       - (IN) ECMP group idx.
  10361  *      l3_ecmp_count - (IN) Buffer for l3_ecmp_count hw entry.
  10362  *      group_size    - (OUT) Ecmp group size.
  10363  *      base_idx      - (OUT) Ecmp base entry
  10364  * Returns:
  10365  *      BCM_E_XXX.
  10366  */
  10367 STATIC int
  10368 _bcm_xgs3_l3_ecmp_1k_groups_info_get(int unit, int grp_idx, void *l3_ecmp_count,
  10369                                      int *group_size, int *base_idx)
  10370 {
  10371     uint32 ing_config_2;
  10372     uint8 ecmp_hash_16bits = 1; /*1k ecmp groups by default*/
  10373 #if defined(BCM_TOMAHAWK3_SUPPORT)
  10374     int lb_mode;
  10375 #endif
  10376 #if defined(BCM_TOMAHAWK_SUPPORT)
  10377     int weighted = 0;
  10378 #endif
  10379     soc_mem_t mem = L3_ECMP_COUNTm;
  10380 
  10381 #if defined(BCM_TOMAHAWK3_SUPPORT)
  10382     if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) &&
  10383        (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  10384              ecmp_mode_hierarchical) && (grp_idx <
  10385                (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) {
  10386         mem = ECMP_GROUP_HIERARCHICALm;
  10387     }
  10388 #endif
  10389 
  10390     if (!l3_ecmp_count){
  10391         return BCM_E_PARAM;
  10392     }
  10393 
  10394     if ((!group_size) && (!base_idx)){
  10395         return BCM_E_PARAM;
  10396     }
  10397 
  10398     /*for TD+*/
  10399     if (SOC_IS_TRIDENT(unit)) {
  10400         ecmp_hash_16bits = 0;
  10401         if (SOC_REG_IS_VALID(unit, ING_CONFIG_2r)) {
  10402             SOC_IF_ERROR_RETURN(READ_ING_CONFIG_2r(unit, &ing_config_2));
  10403             ecmp_hash_16bits =
  10404                 soc_reg_field_get(unit, ING_CONFIG_2r, ing_config_2,
  10405                                   ECMP_HASH_16BITSf);
  10406         }
  10407         if (!ecmp_hash_16bits) {
  10408             if (group_size) {
  10409                 *group_size = soc_mem_field32_get(unit, mem, l3_ecmp_count, COUNT_0f);
  10410             }
  10411             if (base_idx) {
  10412                 *base_idx = soc_mem_field32_get(unit, mem, l3_ecmp_count, BASE_PTR_0f);
  10413             }
  10414         }
  10415     }
  10416 
  10417     if (ecmp_hash_16bits) {
  10418         if (group_size) {
  10419             *group_size = soc_mem_field32_get(unit, mem,
  10420                                               l3_ecmp_count, COUNTf);
  10421 #if defined(BCM_TOMAHAWK3_SUPPORT)
  10422             if (soc_feature(unit, soc_feature_l3_ecmp_weighted)) {
  10423                 lb_mode = soc_L3_ECMP_COUNTm_field32_get(unit, l3_ecmp_count,
  10424                                                          LB_MODEf);
  10425                 switch (lb_mode) {
  10426                     case BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_256:
  10427                         *group_size = 256 - 1;
  10428                         weighted = 1;
  10429                         break;
  10430                     case BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_512:
  10431                         *group_size = 512 - 1;
  10432                         weighted = 1;
  10433                         break;
  10434                     case BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_1024:
  10435                         *group_size = 1024 - 1;
  10436                         weighted = 1;
  10437                         break;
  10438                     case BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_2048:
  10439                         *group_size = 2048 - 1;
  10440                         weighted = 1;
  10441                         break;
  10442                     case BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_4096:
  10443                         *group_size = 4096 - 1;
  10444                         weighted = 1;
  10445                         break;
  10446                }
  10447             }
  10448 #endif
  10449 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  10450             if (soc_feature(unit, soc_feature_dgm)) {
  10451                 *group_size += BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit)[grp_idx];
  10452             }
  10453 #endif
  10454         }
  10455         if (base_idx) {
  10456             *base_idx = soc_mem_field32_get(unit, mem, l3_ecmp_count, BASE_PTRf);
  10457         }
  10458     }
  10459 
  10460 #ifdef BCM_TOMAHAWK_SUPPORT
  10461     if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) &&
  10462         group_size) {
  10463         if (!weighted && (bcm_opt_ecmp_group_is_rh(unit, grp_idx) ||
  10464             (!BCM_XGS3_L3_MAX_ECMP_MODE(unit) && (grp_idx & 0x1) &&
  10465               bcm_opt_ecmp_group_is_rh(unit, grp_idx - 1)))) {
  10466             int min = 6; int max = 14;
  10467             if ((SOC_IS_TOMAHAWK2(unit)) ||
  10468                 (SOC_IS_TOMAHAWK3(unit))) {
  10469                 max = 15;
  10470             }
  10471             if (*group_size > max || *group_size < min) {
  10472                 return BCM_E_INTERNAL;
  10473             } else {
  10474                 *group_size = 1 << *group_size;
  10475             }
  10476             /* will be added back outside */
  10477             (*group_size)--;
  10478         }
  10479     }
  10480 #endif
  10481     return BCM_E_NONE;
  10482 }
  10483 
  10484 /*
  10485  * Function:
  10486  *      _bcm_xgs3_l3_ecmp_grp_info_set
  10487  * Purpose:
  10488  *      Set ecmp group size and base_idx for the chips with 1k ecmp groups,
  10489  *      especially for TD+ with configurable 256/1k ecmp groups meantime.
  10490  * Parameters:
  10491  *      unit      - (IN)SOC unit number.
  10492  *      grp_idx   - (IN)ECMP group idx.
  10493  *      l3_ecmp_count - (IN)Buffer for  l3_ecmp_count hw entry.
  10494  *      initial_l3_ecmp_group - (IN)Buffer for initial_l3_ecmp_group hw entry.
  10495  *      initial_l3_ecmp_flag- (IN)If set initial_l3_ecmp_group hw entry.
  10496  *      group_size - (IN)ecmp group size.
  10497  *      base_idx- (IN)ecmp base entry.
  10498  *      alternate_cnt- (IN)alternate_cnt for DGM.
  10499  *      ecmp_flags - (IN) ecmp flags
  10500  * Returns:
  10501  *      BCM_E_XXX.
  10502  */
  10503 int
  10504 _bcm_xgs3_l3_ecmp_grp_info_set(int unit, int grp_idx,
  10505                                void *l3_ecmp_count,
  10506                                void *initial_l3_ecmp_group,
  10507                                int initial_l3_ecmp_flag,
  10508                                int group_size, int base_idx,
  10509                                int alternate_cnt,
  10510                                uint32 ecmp_flags)
  10511 {
  10512     uint32 ing_config_2;
  10513     uint8 ecmp_hash_16bits = 1; /*1k ecmp groups by default*/
  10514     soc_mem_t  mem = L3_ECMP_COUNTm;
  10515 #ifdef BCM_TOMAHAWK3_SUPPORT
  10516     int lb_mode = 0;
  10517 #endif
  10518 
  10519     if (!l3_ecmp_count){
  10520         return BCM_E_PARAM;
  10521     }
  10522 
  10523     if (initial_l3_ecmp_flag
  10524         && (!initial_l3_ecmp_group)) {
  10525         return BCM_E_PARAM;
  10526     }
  10527 
  10528     /*TD+ only for 256 ECMP groups*/
  10529     if (SOC_IS_TRIDENT(unit)) {
  10530         SOC_IF_ERROR_RETURN
  10531             (READ_ING_CONFIG_2r(unit, &ing_config_2));
  10532         ecmp_hash_16bits =
  10533             soc_reg_field_get(unit, ING_CONFIG_2r, ing_config_2,
  10534                               ECMP_HASH_16BITSf);
  10535         if (!ecmp_hash_16bits) {
  10536             if (group_size != -1) {
  10537                 if (!group_size) {
  10538                     soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, COUNT_0f, group_size);
  10539                     soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, COUNT_1f, group_size);
  10540                     soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, COUNT_2f, group_size);
  10541                     soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, COUNT_3f, group_size);
  10542 
  10543                     if (initial_l3_ecmp_flag) {
  10544                         soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm,
  10545                                             initial_l3_ecmp_group, COUNT_0f, group_size);
  10546                         soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm,
  10547                                             initial_l3_ecmp_group, COUNT_1f, group_size);
  10548                         soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm,
  10549                                             initial_l3_ecmp_group, COUNT_2f, group_size);
  10550                         soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm,
  10551                                             initial_l3_ecmp_group, COUNT_3f, group_size);
  10552                     }
  10553                 } else {
  10554                     soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, COUNT_0f, group_size - 1);
  10555                     soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, COUNT_1f, group_size - 1);
  10556                     soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, COUNT_2f, group_size - 1);
  10557                     soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, COUNT_3f, group_size - 1);
  10558 
  10559                     if (initial_l3_ecmp_flag) {
  10560                         soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm,
  10561                                             initial_l3_ecmp_group, COUNT_0f, group_size - 1);
  10562                         soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm,
  10563                                             initial_l3_ecmp_group, COUNT_1f, group_size - 1);
  10564                         soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm,
  10565                                             initial_l3_ecmp_group, COUNT_2f, group_size - 1);
  10566                         soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm,
  10567                                             initial_l3_ecmp_group, COUNT_3f, group_size - 1);
  10568                         }
  10569                 }
  10570             }
  10571 
  10572             if (base_idx != -1) {
  10573                 /* Set group base pointer. */
  10574                 if (SOC_MEM_FIELD_VALID(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) {
  10575                     soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count,
  10576                             BASE_PTR_0f, base_idx);
  10577                 }
  10578                 if (SOC_MEM_FIELD_VALID(unit, L3_ECMP_COUNTm, BASE_PTR_1f)) {
  10579                     soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count,
  10580                             BASE_PTR_1f, base_idx);
  10581                 }
  10582                 if (SOC_MEM_FIELD_VALID(unit, L3_ECMP_COUNTm, BASE_PTR_2f)) {
  10583                     soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count,
  10584                             BASE_PTR_2f, base_idx);
  10585                 }
  10586                 if (SOC_MEM_FIELD_VALID(unit, L3_ECMP_COUNTm, BASE_PTR_3f)) {
  10587                     soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count,
  10588                             BASE_PTR_3f, base_idx);
  10589                 }
  10590 
  10591                 if (initial_l3_ecmp_flag) {
  10592                     if (SOC_MEM_FIELD_VALID(unit, INITIAL_L3_ECMP_GROUPm, BASE_PTR_0f)) {
  10593                         soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm,
  10594                                             initial_l3_ecmp_group, BASE_PTR_0f, base_idx);
  10595                     }
  10596                     if (SOC_MEM_FIELD_VALID(unit, INITIAL_L3_ECMP_GROUPm, BASE_PTR_1f)) {
  10597                         soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm,
  10598                                             initial_l3_ecmp_group, BASE_PTR_1f, base_idx);
  10599                     }
  10600                     if (SOC_MEM_FIELD_VALID(unit, INITIAL_L3_ECMP_GROUPm, BASE_PTR_2f)) {
  10601                         soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm,
  10602                                             initial_l3_ecmp_group, BASE_PTR_2f, base_idx);
  10603                     }
  10604                     if (SOC_MEM_FIELD_VALID(unit, INITIAL_L3_ECMP_GROUPm, BASE_PTR_3f)) {
  10605                         soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm,
  10606                                             initial_l3_ecmp_group, BASE_PTR_3f, base_idx);
  10607                     }
  10608                 }
  10609 
  10610             }
  10611         }
  10612     }
  10613 #if defined(BCM_TOMAHAWK3_SUPPORT)
  10614     if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) &&
  10615         (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == ecmp_mode_hierarchical)
  10616                                       && (ecmp_flags & BCM_L3_ECMP_OVERLAY)) {
  10617         mem = ECMP_GROUP_HIERARCHICALm;
  10618     }
  10619 #endif
  10620     /*For all chips with 1k ECMP groups*/
  10621     if (ecmp_hash_16bits) {
  10622         if (group_size != -1) {
  10623 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  10624             if (soc_feature(unit, soc_feature_dgm) && group_size) {
  10625                 group_size -= alternate_cnt;
  10626                 if (group_size < 0) {
  10627                     return BCM_E_INTERNAL;
  10628                 }
  10629             }
  10630 #endif
  10631             if (!group_size) {
  10632                 soc_mem_field32_set(unit, mem,
  10633                                     l3_ecmp_count, COUNTf, group_size);
  10634                 if (initial_l3_ecmp_flag) {
  10635                     soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm,
  10636                                         initial_l3_ecmp_group, COUNTf, group_size);
  10637                 }
  10638             } else {
  10639 #ifdef BCM_TOMAHAWK_SUPPORT
  10640                 if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) {
  10641                     if (ecmp_flags & BCM_L3_ECMP_RH_OPT) {
  10642                         switch (group_size) {
  10643                         case 64:    group_size = 6;
  10644                             break;
  10645                         case 128:   group_size = 7;
  10646                             break;
  10647                         case 256:   group_size = 8;
  10648                             break;
  10649                         case 512:   group_size = 9;
  10650                             break;
  10651                         case 1024:  group_size = 10;
  10652                             break;
  10653                         case 2048:  group_size = 11;
  10654                             break;
  10655                         case 4096:  group_size = 12;
  10656                             break;
  10657                         case 8192:  group_size = 13;
  10658                             break;
  10659                         case 16384: group_size = 14;
  10660                             break;
  10661                         case 32768: group_size = 15;
  10662                             if (SOC_IS_TOMAHAWK2(unit) || SOC_IS_TOMAHAWK3(unit)) {
  10663                                 break;
  10664                             }
  10665                             /* else fall through */
  10666                         default:
  10667                             return BCM_E_INTERNAL;
  10668                         }
  10669                         group_size++;
  10670                     }
  10671                 }
  10672 #endif
  10673 
  10674 #ifdef BCM_TOMAHAWK3_SUPPORT
  10675                 if ((soc_feature(unit, soc_feature_l3_ecmp_weighted)) &&
  10676                     (ecmp_flags & BCM_L3_ECMP_WEIGHTED)) {
  10677                     /* For Weighted ECMP with group size larger than 128
  10678                        COUNT field is ignored */
  10679                     switch (group_size) {
  10680                         case 256:
  10681                             lb_mode = BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_256;
  10682                             break;
  10683                         case 512:
  10684                             lb_mode = BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_512;
  10685                             break;
  10686                         case 1024:
  10687                             lb_mode = BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_1024;
  10688                             break;
  10689                         case 2048:
  10690                             lb_mode = BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_2048;
  10691                             break;
  10692                         case 4096:
  10693                             lb_mode = BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_4096;
  10694                             break;
  10695                         default:
  10696                             return BCM_E_PARAM;
  10697                    }
  10698                    soc_mem_field32_set(unit, mem, l3_ecmp_count,
  10699                                                   LB_MODEf, lb_mode);
  10700                    BCM_IF_ERROR_RETURN(bcm_opt_ecmp_lb_mode_set(unit, grp_idx, lb_mode));
  10701                 } else
  10702 #endif
  10703                 {
  10704                     soc_mem_field32_set(unit, mem,
  10705                                         l3_ecmp_count, COUNTf, group_size-1);
  10706                 }
  10707 
  10708                 if (initial_l3_ecmp_flag) {
  10709                     soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm,
  10710                                         initial_l3_ecmp_group, COUNTf, group_size - 1);
  10711                 }
  10712             }
  10713         }
  10714 
  10715         if (base_idx != -1) {
  10716             if (SOC_MEM_FIELD_VALID(unit, mem, BASE_PTRf)) {
  10717                 soc_mem_field32_set(unit, mem,
  10718                                     l3_ecmp_count, BASE_PTRf, base_idx);
  10719             }
  10720             if (initial_l3_ecmp_flag) {
  10721                 if (SOC_MEM_FIELD_VALID(unit, INITIAL_L3_ECMP_GROUPm, BASE_PTRf)) {
  10722                     soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm,
  10723                                         initial_l3_ecmp_group, BASE_PTRf, base_idx);
  10724                 }
  10725             }
  10726         }
  10727 
  10728 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  10729         if (soc_feature(unit, soc_feature_dgm)) {
  10730             BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit)[grp_idx] = alternate_cnt;
  10731         }
  10732 #endif
  10733     }
  10734 
  10735     return BCM_E_NONE;
  10736 }
  10737 
  10738 /*
  10739  * Function:
  10740  *      _bcm_xgs3_l3_ecmp_grp_info_get
  10741  * Purpose:
  10742  *      Get ecmp group size and base idx.
  10743  * Parameters:
  10744  *      unit       - (IN) SOC unit number.
  10745  *      grp_idx    - (IN) Index of ECMP group count table.
  10746  *      group_size - (OUT) Ecmp group size.
  10747  *      base_idx   - (OUT) Ecmp base entry
  10748  * Returns:
  10749  *      BCM_E_XXX.
  10750  */
  10751 int
  10752 _bcm_xgs3_l3_ecmp_grp_info_get(int unit, int grp_idx,
  10753                                int *group_size, int *base_idx)
  10754 {
  10755     uint32 hw_buf[SOC_MAX_MEM_WORDS];
  10756     uint32 base_0, base_1;
  10757     uint32 count_0, count_1, count_2, count_3, total_count;
  10758     soc_mem_t mem = L3_ECMP_COUNTm;
  10759 
  10760 #if defined(BCM_TOMAHAWK3_SUPPORT)
  10761     if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) &&
  10762         (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  10763              ecmp_mode_hierarchical) && (grp_idx <
  10764                  (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) {
  10765         mem = ECMP_GROUP_HIERARCHICALm;
  10766     }
  10767 #endif
  10768     if (!SOC_MEM_IS_VALID(unit, mem)) {
  10769         return BCM_E_NONE;
  10770     }
  10771     
  10772     sal_memset(hw_buf, 0, SOC_MAX_MEM_WORDS * sizeof(uint32));
  10773     SOC_IF_ERROR_RETURN(
  10774         soc_mem_read(unit, mem, MEM_BLOCK_ANY,
  10775                      grp_idx, hw_buf));
  10776 
  10777     if (soc_feature(unit, soc_feature_l3_ecmp_1k_groups)) {
  10778         BCM_IF_ERROR_RETURN(
  10779             _bcm_xgs3_l3_ecmp_1k_groups_info_get(unit, grp_idx, hw_buf,
  10780                                                  group_size, base_idx));
  10781         if (group_size) {
  10782             *group_size += 1;
  10783         }
  10784     } else if (SOC_MEM_FIELD_VALID(unit, L3_ECMP_COUNTm, COUNT_0f)) {
  10785 
  10786         base_0 = base_1 = count_0 = count_1 = count_2 = count_3 = 0;
  10787         count_0 = (soc_mem_field32_get(unit, L3_ECMP_COUNTm,
  10788                 hw_buf, COUNT_0f) + 1);
  10789         if (soc_feature(unit, soc_feature_ecmp_1k_paths_4_subgroups)) {
  10790             count_1 = (soc_mem_field32_get(unit, L3_ECMP_COUNTm,
  10791                         hw_buf, COUNT_1f) + 1);
  10792             count_2 = (soc_mem_field32_get(unit, L3_ECMP_COUNTm,
  10793                         hw_buf, COUNT_2f) + 1);
  10794             count_3 = (soc_mem_field32_get(unit, L3_ECMP_COUNTm,
  10795                         hw_buf, COUNT_3f) + 1);
  10796 
  10797             base_0 = soc_mem_field32_get(unit, L3_ECMP_COUNTm,
  10798                     hw_buf, BASE_PTR_0f);
  10799             base_1 = soc_mem_field32_get(unit, L3_ECMP_COUNTm,
  10800                     hw_buf, BASE_PTR_1f);
  10801             total_count = count_0;
  10802             if (base_1 != base_0) {
  10803                 total_count += (count_1 + count_2 + count_3);
  10804             }
  10805         } else {
  10806             total_count = count_0;
  10807         }
  10808         if (group_size) {
  10809             *group_size = total_count;
  10810         }
  10811 
  10812         if (base_idx) {
  10813             *base_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm,
  10814                                             hw_buf, BASE_PTR_0f);
  10815         }
  10816     } else {
  10817         if (SOC_MEM_FIELD_VALID(unit, L3_ECMP_COUNTm, COUNTf)) {
  10818             if (group_size) {
  10819                 *group_size = (soc_mem_field32_get(unit, L3_ECMP_COUNTm,
  10820                                                   hw_buf, COUNTf) + 1);
  10821             }
  10822         }
  10823 
  10824         if (SOC_MEM_FIELD_VALID(unit, L3_ECMP_COUNTm, BASE_PTRf)) {
  10825             if (base_idx) {
  10826                 *base_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm,
  10827                                                 hw_buf, BASE_PTRf);
  10828             }
  10829         }
  10830     }
  10831 
  10832     return BCM_E_NONE;
  10833 }
  10834 
  10835 /*
  10836  * Function:
  10837  *      _bcm_xgs3_ecmp_max_grp_size_get
  10838  * Purpose:
  10839  *      Get maximum number of next hop entries in ecmp group
  10840  * Parameters:
  10841  *      unit           - (IN)SOC unit number.
  10842  *      ecmp_group_id  - (IN)Ecmp group id.
  10843  *      *grp_sz        - (OUT)Ecmp group size.
  10844  * Returns:
  10845  *      void
  10846  */
  10847 int
  10848 _bcm_xgs3_ecmp_max_grp_size_get(int unit, int ecmp_group_id, int *grp_sz)
  10849 {
  10850     int max_group_size;           /* Maximum ecmp group size. */
  10851     int rv = BCM_E_NONE;
  10852 
  10853 #if defined(BCM_TRX_SUPPORT)
  10854 
  10855 #ifdef BCM_TRIUMPH2_SUPPORT
  10856     if (SOC_IS_TRIUMPH3(unit) || BCM_XGS3_L3_MAX_ECMP_MODE(unit)) {
  10857         if (BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)) {
  10858             /* 1k ecmp grp */
  10859             *grp_sz = BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[ecmp_group_id];
  10860             return BCM_E_NONE;
  10861         }
  10862     }
  10863 #endif
  10864 
  10865     if ((SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) && (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))){
  10866         rv = _bcm_xgs3_l3_ecmp_grp_info_get(unit,
  10867                                     ecmp_group_id + 1, grp_sz, NULL);
  10868         if (BCM_FAILURE(rv)) {
  10869             return rv;
  10870         }
  10871     } else
  10872 #endif /* BCM_TRX_SUPPORT */
  10873     {
  10874 
  10875     /* Set number of next hop entries in ecmp group. */
  10876     max_group_size = BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  10877 
  10878     /* Return max group size to the caller. */
  10879     *grp_sz = max_group_size;
  10880     }
  10881     return rv;
  10882 }
  10883 
  10884 /*
  10885  * Function:
  10886  *      _bcm_xgs3_ecmp_max_grp_size_set
  10887  * Purpose:
  10888  *      Set maximum number of next hop entries in ecmp group.
  10889  * Parameters:
  10890  *      unit           - (IN)SOC unit number.
  10891  *      ecmp_group_id  - (IN)Ecmp group id.
  10892  *      max_grp_sz     - (IN)Ecmp max group size.
  10893  *      ecmp_flags     - (IN)Ecmp group flags
  10894  * Returns:
  10895  *      void
  10896  */
  10897 #if defined(BCM_TRX_SUPPORT) 
  10898 STATIC INLINE int
  10899 _bcm_xgs3_ecmp_max_grp_size_set(int unit, int ecmp_group_id,
  10900                                 int max_grp_sz, uint32 ecmp_flags)
  10901 {
  10902 #if defined(BCM_TRX_SUPPORT)
  10903     uint32 hw_buf[SOC_MAX_MEM_WORDS]; /* Buffer to write hw entry. */
  10904     int rv = BCM_E_NONE;
  10905     int subgrp_cnt = 0;
  10906 
  10907 #ifdef BCM_TRIUMPH2_SUPPORT
  10908     if (SOC_IS_TRIUMPH3(unit) || BCM_XGS3_L3_MAX_ECMP_MODE(unit)) {
  10909         if (BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)) {
  10910             /* 1k ecmp grp */
  10911             BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[ecmp_group_id] = max_grp_sz;
  10912             return BCM_E_NONE;
  10913         }
  10914     }
  10915 #endif
  10916     if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) {
  10917         if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  10918             sal_memset(hw_buf, 0, SOC_MAX_MEM_WORDS * sizeof(uint32));
  10919             if (soc_feature(unit, soc_feature_l3_ecmp_1k_groups)) {
  10920                 rv = _bcm_xgs3_l3_ecmp_grp_info_set(unit, (ecmp_group_id + 1),
  10921                          hw_buf, NULL, 0, max_grp_sz, -1, 0, ecmp_flags);
  10922                 if (BCM_FAILURE(rv)) {
  10923                     return rv;
  10924                 }
  10925             } else if (SOC_MEM_FIELD_VALID(unit, L3_ECMP_COUNTm, COUNTf)) {
  10926                  soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf,
  10927                      COUNTf, max_grp_sz -1);
  10928             } else if (soc_feature(unit, soc_feature_ecmp_1k_paths_4_subgroups)
  10929                     && (max_grp_sz >= 256)) {
  10930                 subgrp_cnt = ((max_grp_sz + 3) / 4);
  10931                 rv = soc_mem_read(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL,
  10932                         (ecmp_group_id + 1), hw_buf);
  10933                 if (BCM_FAILURE(rv)) {
  10934                     return rv;
  10935                 }
  10936                 soc_mem_field32_set(unit, L3_ECMP_COUNTm,
  10937                         hw_buf, COUNT_0f, (subgrp_cnt - 1));
  10938                 soc_mem_field32_set(unit, L3_ECMP_COUNTm,
  10939                         hw_buf, COUNT_1f, (subgrp_cnt - 1));
  10940                 soc_mem_field32_set(unit, L3_ECMP_COUNTm,
  10941                         hw_buf, COUNT_2f, (subgrp_cnt - 1));
  10942                 soc_mem_field32_set(unit, L3_ECMP_COUNTm,
  10943                         hw_buf, COUNT_3f,
  10944                         ((max_grp_sz - (3 * subgrp_cnt) - 1)));
  10945             } else {
  10946                  soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf,
  10947                      COUNT_0f, max_grp_sz - 1);
  10948                  soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf,
  10949                      COUNT_1f, max_grp_sz - 1);
  10950                  soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf,
  10951                      COUNT_2f, max_grp_sz - 1);
  10952                  soc_mem_field32_set(unit, L3_ECMP_COUNTm, hw_buf,
  10953                      COUNT_3f, max_grp_sz - 1);
  10954             }
  10955             rv = soc_mem_write(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL,
  10956                      (ecmp_group_id + 1), hw_buf);
  10957             if (BCM_FAILURE(rv)) {
  10958                 return rv;
  10959             }
  10960             return BCM_E_NONE;
  10961         } else {
  10962             return BCM_E_PARAM;
  10963         }
  10964     }
  10965 #endif /* BCM_TRX_SUPPORT */
  10966 
  10967     return BCM_E_UNAVAIL;
  10968 }
  10969 #endif /* BCM_TRX_SUPPORT */
  10970 
  10971 /*
  10972  * Function:
  10973  *      _bcm_xgs3_ecmp_grp_size_get
  10974  * Purpose:
  10975  *      Get number of next hop entries in ecmp group
  10976  * Parameters:
  10977  *      unit          - (IN)SOC unit number.
  10978  *      ecmp_group_id - (IN)Ecmp group id.
  10979  *      nh_arr        - (IN)Ecmp group memeber next hop entries.
  10980  *      *grp_sz       - (OUT)Ecmp group size.
  10981  * Returns:
  10982  *      void
  10983  */
  10984 STATIC INLINE void
  10985 _bcm_xgs3_ecmp_grp_size_get(int unit, int ecmp_group_id,
  10986                             int *nh_arr, int *grp_sz)
  10987 {
  10988     int ecmp_max_paths=0;                 /* Maximum number of paths for group. */
  10989     int ecmp_count;                     /* Ecmp group next hop count.         */
  10990     int idx;                            /* Iteration index.                   */
  10991 
  10992     /* Calculate maximum group size. */
  10993     /* for rh, it's dynamic_size*/
  10994     (void) _bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_id, &ecmp_max_paths);
  10995 
  10996     /* Check real group size. */
  10997     ecmp_count = 0;
  10998     for (idx = 0; idx < ecmp_max_paths; idx++) {
  10999         if (nh_arr[idx] != 0) {
  11000             ecmp_count++;
  11001         } else {
  11002             break;
  11003         }
  11004     }
  11005     *grp_sz = ecmp_count;
  11006     return;
  11007 }
  11008 
  11009 /*
  11010  * Function:
  11011  *      _bcm_xgs3_ecmp_tbl_read
  11012  * Purpose:
  11013  *      Read up to max_cnt values from ecmp table.
  11014  * Parameters:
  11015  *      unit           - (IN)SOC unit number.
  11016  *      ecmp_group_idx - (IN)First ecmp entry index to read.
  11017  *      ecmp_grp       - (OUT)Buffer to fill group info.
  11018  *      ecmp_count     - (OUT)Actual ecmp group size.
  11019  * Returns:
  11020  *      BCM_E_XXX
  11021  */
  11022 STATIC INLINE int
  11023 _bcm_xgs3_ecmp_tbl_read(int unit, int ecmp_group_idx,
  11024                         int *ecmp_grp, int *ecmp_count)
  11025 {
  11026     int rv = BCM_E_UNAVAIL;     /* Operation return value. */
  11027     int max_group_size = 0;
  11028     _bcm_l3_tbl_t *tbl_ptr;      /* ECMP table pointer. */
  11029 
  11030     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  11031 #ifdef BCM_TOMAHAWK3_SUPPORT
  11032     if ((ecmp_group_idx < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2)) &&
  11033         (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == ecmp_mode_hierarchical)
  11034          && (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl))) {
  11035         tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp);
  11036     }
  11037 #endif
  11038 
  11039     /* Make sure entry is inuse. */
  11040     if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr,
  11041                                  ecmp_group_idx)) {
  11042         return (BCM_E_NOT_FOUND);
  11043     }
  11044 
  11045     /* for rh, it's dynamic_size*/
  11046     rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_idx, &max_group_size);
  11047     if (rv < 0) {
  11048         return rv;
  11049     }
  11050 
  11051     /* Read ecmp group members from hw. */
  11052     if (BCM_XGS3_L3_HWCALL_CHECK(unit, ecmp_grp_get) && max_group_size) {
  11053         BCM_XGS3_L3_MODULE_LOCK(unit);
  11054         rv = BCM_XGS3_L3_HWCALL_EXEC (unit, ecmp_grp_get) (unit, ecmp_group_idx,
  11055                                                            max_group_size,
  11056                                                            ecmp_grp);
  11057         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  11058     }
  11059 
  11060     /* Get group size. */
  11061     if (ecmp_count) {
  11062         _bcm_xgs3_ecmp_grp_size_get(unit, ecmp_group_idx, ecmp_grp, ecmp_count);
  11063     }
  11064     return rv;
  11065 }
  11066 
  11067 /*
  11068  * Function:
  11069  *      _bcm_xgs3_ecmp_grp_hash_calc
  11070  * Purpose:
  11071  *      Calculate ecmp group next hops hash(signature).
  11072  * Parameters:
  11073  *      unit     -  (IN)SOC unit number.
  11074  *      buf      -  (IN)Next hop entry information.
  11075  *      hash     -  (OUT) Hash(signature) calculated value.
  11076  * Returns:
  11077  *      BCM_X_XXX
  11078  */
  11079 STATIC int
  11080 _bcm_xgs3_ecmp_grp_hash_calc(int unit, void *buf_ecmp, uint16 *hash)
  11081 {
  11082     int *buf = NULL;
  11083     _bcm_l3_ecmp_group_buffer_t *ecmp_buf = buf_ecmp;
  11084 
  11085     if ((NULL == ecmp_buf) || (NULL == hash) ||
  11086         (NULL == ecmp_buf->group_buffer)) {
  11087         return (BCM_E_PARAM);
  11088     }
  11089 
  11090     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &buf));
  11091 
  11092     if (ecmp_buf->dlb_group_buffer) {
  11093         /* DLB ECMP group excluding filler */
  11094         sal_memcpy (buf, ecmp_buf->dlb_group_buffer,
  11095                     BCM_XGS3_L3_ECMP_MAX_PATHS(unit) * sizeof(int));
  11096     } else {
  11097         sal_memcpy (buf, ecmp_buf->group_buffer,
  11098                     BCM_XGS3_L3_ECMP_MAX_PATHS(unit) * sizeof(int));
  11099     }
  11100 
  11101     _shr_sort(buf, BCM_XGS3_L3_ECMP_MAX_PATHS(unit), sizeof(int),
  11102               _bcm_xgs3_cmp_int);
  11103     /* Calculate hash of next hop indexes, which are members in the group. */
  11104     *hash = _shr_crc16(0, (uint8 *) buf,
  11105                        BCM_XGS3_L3_ECMP_MAX_PATHS(unit) * sizeof(int));
  11106     sal_free(buf);
  11107     return (BCM_E_NONE);
  11108 }
  11109 
  11110 /*
  11111  * Function:
  11112  *      _bcm_xgs3_ecmp_grp_cmp
  11113  * Purpose:
  11114  *      Compare ecmp group next hop members with group in hw.
  11115  * Parameters:
  11116  *      unit       - (IN)SOC unit number.
  11117  *      buf        - (IN)Next hop indexes.
  11118  *      grp_idx    - (IN)ECMP group index in hw.
  11119  *      cmp_result - (OUT)Comparison result.
  11120  * Returns:
  11121  *      BCM_E_XXX
  11122  */
  11123 STATIC int
  11124 _bcm_xgs3_ecmp_grp_cmp(int unit, void *buf, int grp_idx, int *cmp_result)
  11125 {
  11126     int ecmp_max_paths = 0;     /* Maximum number of ecmp paths. */
  11127     int ecmp_count = 0;         /* Count indexes in the group.   */
  11128     int *ecmp_grp;              /* Ecmp group from hw.           */
  11129     int *nh_idx;                /* Ecmp group buffer pointer.    */
  11130     int idx;                    /* Iteration index.              */
  11131     int rv;                     /* Operation return status.      */
  11132     int count = 0;              /* Count indexes in the group.   */
  11133     int *dlb_ecmp_grp = NULL;   /* DLB ecmp group excluding filler.   */
  11134     int *cmp_grp = NULL;
  11135     _bcm_l3_ecmp_group_buffer_t *ecmp_buf = buf;
  11136 
  11137     /* Input parameters sanity check. */
  11138     if ((NULL == cmp_result) || (NULL == ecmp_buf) ||
  11139         (NULL == ecmp_buf->group_buffer)) {
  11140         return (BCM_E_PARAM);
  11141     }
  11142 
  11143     /* Get maximum ecmp group size for group index. */
  11144     /*for rh, it's dynamic_size*/
  11145     rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, grp_idx, &ecmp_max_paths);
  11146     if (rv < 0) {
  11147         return rv;
  11148     }
  11149 
  11150     /* Get next hops array. */
  11151     if (ecmp_buf->dlb_group_buffer) {
  11152         nh_idx = ecmp_buf->dlb_group_buffer;
  11153     } else {
  11154         nh_idx = ecmp_buf->group_buffer;
  11155     }
  11156 
  11157     /* Get ecmp group size. */
  11158     _bcm_xgs3_ecmp_grp_size_get(unit, grp_idx, nh_idx, &ecmp_count);
  11159 
  11160     /* Allocate ecmp group buffer. */
  11161     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp));
  11162 
  11163     /* Read ecmp group from hw. */
  11164     rv = _bcm_xgs3_ecmp_tbl_read(unit, grp_idx, ecmp_grp, &count);
  11165     if (BCM_FAILURE(rv)) {
  11166         sal_free(ecmp_grp);
  11167         return (rv);
  11168     }
  11169 
  11170 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  11171     if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
  11172         bcm_l3_egress_ecmp_t ecmp;
  11173         int location_offset = 0;
  11174         int primary_count = 0;
  11175         int i = 0, j = 0;
  11176         SHR_BITDCL *group_bitmap_ptr = NULL;
  11177 
  11178         bcm_l3_egress_ecmp_t_init(&ecmp);
  11179 
  11180         ecmp.ecmp_intf = grp_idx + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  11181 
  11182         rv = bcm_th2_l3_egress_ecmp_dlb_get(unit, &ecmp);
  11183         if (BCM_FAILURE(rv)) {
  11184             sal_free(ecmp_grp);
  11185             return (rv);
  11186         }
  11187 
  11188         if (BCM_TH2_ECMP_IS_DLB_OR_DGM(unit, ecmp.dynamic_mode)) {
  11189             group_bitmap_ptr =
  11190                 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, grp_idx);
  11191 
  11192             if (ecmp.dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) {
  11193                 SHR_BITCOUNT_RANGE(group_bitmap_ptr, primary_count,
  11194                                    0, ecmp_max_paths / 2);
  11195                 /* Only alternate members exist */
  11196                 if (0 == primary_count) {
  11197                     location_offset = ecmp_max_paths / 2;
  11198                 }
  11199             }
  11200 
  11201             /* Allocate DLB ecmp group buffer. */
  11202             rv = _bcm_xgs3_l3_ecmp_group_alloc(unit, &dlb_ecmp_grp);
  11203             if (BCM_FAILURE(rv)) {
  11204                 sal_free(ecmp_grp);
  11205                 return (rv);
  11206             }
  11207 
  11208             /* Exclude filler members from expanded DLB group */
  11209             for (i = 0; i < count; i++) {
  11210                 if (SHR_BITGET(group_bitmap_ptr, i + location_offset)) {
  11211                     dlb_ecmp_grp[j++] = ecmp_grp[i];
  11212                 }
  11213             }
  11214         }
  11215     }
  11216 #endif /* BCM_TOMAHAWK2_SUPPORT  || BCM_TRIDENT3_SUPPORT*/
  11217 
  11218     cmp_grp = dlb_ecmp_grp ? dlb_ecmp_grp : ecmp_grp;
  11219 
  11220     /* Sort the NH members if they have not been sorted */
  11221 
  11222     if ((BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, grp_idx, \
  11223                       BCM_L3_ECMP_PATH_NO_SORTING))
  11224             || (SOC_IS_TOMAHAWK3(unit) && BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, grp_idx, \
  11225                       BCM_L3_ECMP_WEIGHTED))
  11226        ) {
  11227         _shr_sort(cmp_grp, ecmp_count, sizeof(int), _bcm_xgs3_cmp_int);
  11228     }
  11229 
  11230     /* Compare ecmp groups. */
  11231     if (sal_memcmp(nh_idx, cmp_grp, (ecmp_count * sizeof(int)))) {
  11232         *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  11233         sal_free(ecmp_grp);
  11234         if (dlb_ecmp_grp) {
  11235             sal_free(dlb_ecmp_grp);
  11236         }
  11237         return (BCM_E_NONE);
  11238     }
  11239 
  11240     /* Make sure group doesn't contain any additional indexes. */
  11241     for (idx = ecmp_count; idx < ecmp_max_paths; idx++) {
  11242         if (cmp_grp[idx]) {
  11243             *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  11244             sal_free(ecmp_grp);
  11245             if (dlb_ecmp_grp) {
  11246                 sal_free(dlb_ecmp_grp);
  11247             }
  11248             return (BCM_E_NONE);
  11249         }
  11250     }
  11251     sal_free(ecmp_grp);
  11252     if (dlb_ecmp_grp) {
  11253         sal_free(dlb_ecmp_grp);
  11254     }
  11255     *cmp_result = BCM_L3_CMP_EQUAL;
  11256     return (BCM_E_NONE);
  11257 }
  11258 
  11259 /*
  11260  * Function:
  11261  *      _bcm_xgs3_ecmp_group_del
  11262  * Purpose:
  11263  *      Delete ecmp group
  11264  * Parameters:
  11265  *      unit           - (IN)SOC unit number.
  11266  *      ecmp_group_id  - (IN)Ecmp group id.
  11267  *      flags          - (IN)_BCM_L3_SHR_CLEAN
  11268  * Returns:
  11269  *      BCM_E_XXX
  11270  */
  11271 STATIC int
  11272 _bcm_xgs3_ecmp_group_del(int unit, int ecmp_group_id, uint32 flags)
  11273 {
  11274     _bcm_l3_tbl_op_t data;
  11275     _bcm_l3_ecmp_group_info_t ecmp_info;
  11276 #ifdef BCM_TRX_SUPPORT
  11277     int max_paths = 0;
  11278     uint32 ing_config_2;
  11279     uint8 ecmp_hash_16bits;
  11280 #endif
  11281 
  11282     /* Initialization */
  11283     sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t));
  11284     data.tbl_ptr =  BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  11285 #ifdef BCM_TOMAHAWK3_SUPPORT
  11286     if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) &&
  11287         (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  11288              ecmp_mode_hierarchical) && (ecmp_group_id <
  11289                        (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) {
  11290         data.tbl_ptr =  BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp);
  11291     }
  11292 #endif
  11293     data.oper_flags = flags;
  11294 
  11295     /* Check hw call is defined. */
  11296     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, ecmp_grp_del)) {
  11297         return (BCM_E_UNAVAIL);
  11298     }
  11299 
  11300     /* Calculate ECMP group id. */
  11301     if ((ecmp_group_id > data.tbl_ptr->idx_max) ||
  11302         (ecmp_group_id < data.tbl_ptr->idx_min)) {
  11303         return (BCM_E_PARAM);
  11304     }
  11305 
  11306     data.entry_index = ecmp_group_id;
  11307     sal_memset(&ecmp_info, 0, sizeof(ecmp_info));
  11308 
  11309 #ifdef BCM_TRX_SUPPORT
  11310     if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  11311         if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  11312             /* for rh, it's dynamic_size */
  11313             BCM_IF_ERROR_RETURN
  11314               (_bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_id,
  11315                                               &max_paths));
  11316             if (soc_feature(unit, soc_feature_l3_ecmp_1k_groups)) {
  11317                 if (!soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) &&
  11318                     max_paths > 1024) {
  11319                     max_paths = 1024;
  11320                 }
  11321                 /*For TD+*/
  11322                 if (SOC_IS_TRIDENT(unit)){
  11323                     SOC_IF_ERROR_RETURN
  11324                         (READ_ING_CONFIG_2r(unit, &ing_config_2));
  11325                     ecmp_hash_16bits =
  11326                         soc_reg_field_get(unit, ING_CONFIG_2r, ing_config_2,
  11327                                           ECMP_HASH_16BITSf);
  11328                     if ((!ecmp_hash_16bits) && (max_paths > 256)) {
  11329                         max_paths = 256;
  11330                     }
  11331                 }
  11332                 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  11333                 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  11334             } else if (SOC_IS_TRIDENT(unit)) {
  11335                 if (max_paths > 256) {
  11336                     max_paths = 256;
  11337                 }
  11338                 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  11339                 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  11340             } else if (SOC_IS_SCORPION(unit)) {
  11341                 if (max_paths > 256) {
  11342                     max_paths = 256;
  11343                 }
  11344                 data.width = max_paths;
  11345             } else if (SOC_IS_GREYHOUND(unit) || SOC_IS_HURRICANE3(unit) ||
  11346                        SOC_IS_SABER2(unit) || SOC_IS_GREYHOUND2(unit)) {
  11347                 if (max_paths > 64) {
  11348                     max_paths = 64;
  11349                 }
  11350                 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  11351                 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  11352             } else if (SOC_IS_MONTEREY(unit)) {
  11353                 if (max_paths > 256) {
  11354                     max_paths = 256;
  11355                 }
  11356                 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  11357                 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  11358             } else if SOC_IS_KATANAX(unit) {
  11359                 if (max_paths > 1024) {
  11360                     max_paths = 1024;
  11361                 }
  11362                 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  11363                 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  11364             } else {
  11365                 if (max_paths > 32) {
  11366                     max_paths = 32;
  11367                 }
  11368                 data.width = max_paths;
  11369                 if (SOC_IS_TRIUMPH2(unit) ||
  11370                     SOC_IS_APOLLO(unit) ||
  11371                     SOC_IS_VALKYRIE2(unit) ||
  11372                     SOC_IS_KATANAX(unit)) {
  11373                     data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  11374                     _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  11375                 }
  11376             }
  11377             ecmp_info.max_paths = max_paths;
  11378         } else {
  11379             return (BCM_E_PARAM);
  11380         }
  11381     } else
  11382 #endif
  11383     {
  11384         ecmp_info.max_paths = _BCM_SINGLE_WIDE;
  11385         data.width = _BCM_SINGLE_WIDE;
  11386     }
  11387     data.info = &ecmp_info;
  11388     data.delete_func = BCM_XGS3_L3_HWCALL(unit, ecmp_grp_del);
  11389 
  11390     /* Delete ECMP group table entry. */
  11391     BCM_IF_ERROR_RETURN(_bcm_xgs3_tbl_del(unit, &data));
  11392 
  11393     return (BCM_E_NONE);
  11394 }
  11395 
  11396 
  11397 /*
  11398  * Function:
  11399  *      bcm_xgs3_ecmp_group_del
  11400  * Purpose:
  11401  *      1. delete ecmp group members
  11402  *      2. if _BCM_L3_SHR_CLEAN is not been setup :
  11403  *         update a reference count of existing group
  11404  *         if it is used by other prefixes
  11405  * Parameters:
  11406  *      unit           - (IN)SOC unit number.
  11407  *      ecmp_group_id  - (IN)Ecmp group id.
  11408  *      flags          - (IN)_BCM_L3_SHR_CLEAN
  11409  * Returns:
  11410  *      BCM_E_XXX
  11411  */
  11412 int
  11413 bcm_xgs3_ecmp_group_del(int unit, int ecmp_group_id, uint32 flags)
  11414 {
  11415     _bcm_l3_tbl_t *tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  11416 #ifdef BCM_TRIDENT2_SUPPORT
  11417     int max_vp_lags = 0;
  11418     int ol_ecmp_in_use = 0;
  11419     int split_idx = 0;
  11420 #endif
  11421     int min_ul_grp = 0;
  11422 
  11423     /* Delete ECMP group table entry. */
  11424     BCM_IF_ERROR_RETURN(_bcm_xgs3_ecmp_group_del(unit, ecmp_group_id, flags));
  11425 
  11426 
  11427     /* if just need to clean group members, return here */
  11428     if (flags & _BCM_L3_SHR_CLEAN) {
  11429         return BCM_E_NONE;
  11430     }
  11431 
  11432 #ifdef BCM_TOMAHAWK3_SUPPORT
  11433     if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) &&
  11434         (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  11435              ecmp_mode_hierarchical) && (ecmp_group_id <
  11436                        (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) {
  11437         tbl_ptr =  BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp);
  11438     }
  11439 #endif
  11440 
  11441     /* update ecmp group ref count */
  11442     if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, ecmp_group_id)) {
  11443         BCM_XGS3_L3_ECMP_GRP_CNT(unit)--;
  11444         if (BCM_XGS3_L3_ECMP_GRP_CNT(unit) == 0) {
  11445             BCM_XGS3_L3_ECMP_IN_USE(unit) = 0;
  11446         }
  11447     }
  11448 
  11449     /* update ecmp_inuse flag if last ECMP group is gone */
  11450 #ifdef BCM_TRIDENT2_SUPPORT
  11451     if (soc_feature(unit, soc_feature_vp_lag)) {
  11452         max_vp_lags = soc_property_get(unit, spn_MAX_VP_LAGS,
  11453                           soc_mem_index_count(unit, EGR_VPLAG_GROUPm));
  11454     }
  11455 
  11456 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
  11457     if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) {
  11458         ol_ecmp_in_use = 1;
  11459         split_idx = tbl_ptr->split_idx;
  11460 
  11461         if ((tbl_ptr->split_maxused == (tbl_ptr->idx_min)) &&
  11462             (!BCM_XGS3_L3_ENT_REF_CNT(
  11463             tbl_ptr, tbl_ptr->split_maxused))) {
  11464 
  11465             ol_ecmp_in_use = 0; 
  11466         }
  11467     } 
  11468 #endif
  11469     /* if max_vp_lags has valid value or if this is RIOT/hierarchical ECMP flow then 
  11470        idx_maxused is not 0 and has to be checked with offset value and not 0. */
  11471     if ((max_vp_lags > 0) || (split_idx)) {
  11472         if (max_vp_lags > 0) {
  11473             if (((max_vp_lags + split_idx - 1) == tbl_ptr->idx_maxused) &&
  11474                 (ol_ecmp_in_use == 0)) {
  11475 
  11476                 if (!BCM_XGS3_L3_ENT_REF_CNT
  11477                     (tbl_ptr, (max_vp_lags + split_idx))) {
  11478 
  11479                     BCM_XGS3_L3_ECMP_IN_USE(unit) = 0;
  11480                 }
  11481             }
  11482         } else {
  11483 
  11484             if ((split_idx == tbl_ptr->idx_maxused) &&
  11485                 (ol_ecmp_in_use == 0)) {
  11486 
  11487                 if (!BCM_XGS3_L3_ENT_REF_CNT
  11488                     (tbl_ptr, split_idx)) {
  11489 
  11490                     BCM_XGS3_L3_ECMP_IN_USE(unit) = 0;
  11491                 }
  11492             }
  11493         }
  11494     } else 
  11495 #endif
  11496 #ifdef BCM_TOMAHAWK3_SUPPORT
  11497     if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) &&
  11498        (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  11499              ecmp_mode_hierarchical)) {
  11500         min_ul_grp = (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit)) / 2;
  11501         tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  11502     }
  11503 #endif
  11504     if (((min_ul_grp == tbl_ptr->idx_maxused) ||
  11505          (0 == tbl_ptr->idx_maxused)) && /* No group allocated */
  11506         (BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, 0) == 0)) {
  11507         BCM_XGS3_L3_ECMP_IN_USE(unit) = 0;
  11508     }
  11509     return (BCM_E_NONE);
  11510 }
  11511 
  11512 /*
  11513  * Function:
  11514  *      _bcm_xgs3_ecmp_group_add
  11515  * Purpose:
  11516  *      Write ecmp group to the hw.
  11517  * Parameters:
  11518  *      unit         - (IN)SOC unit number.
  11519  *      flags        - (IN)BCM_L3_REPLACE && BCM_L3_WITH_ID
  11520  *      ecmp_count   - (IN)Ecmp group next hops count.
  11521  *      max_paths    - (IN)Ecmp group max next hops count.
  11522  *      ecmp_group   - (IN)Ecmp group.
  11523  *      group_index  - (IN|OUT)Ecmp group index
  11524  *      primary_count- (IN)Ecmp primary_count
  11525  *      dlb_member_bitmap - (IN) ECMP DLB members.
  11526  * Returns:
  11527  *    BCM_E_XXX
  11528  */
  11529 STATIC int
  11530 _bcm_xgs3_ecmp_group_add(int unit, uint32 flags, uint32 ecmp_flags,
  11531                         int ecmp_count, int max_paths, int *ecmp_group,
  11532                         int *group_index, int primary_count,
  11533                         SHR_BITDCL *dlb_member_bitmap)
  11534 {
  11535     _bcm_l3_tbl_op_t data;        /* Operation data. */
  11536     _bcm_l3_ecmp_group_info_t ecmp_info;
  11537     _bcm_l3_ecmp_group_buffer_t ecmp_buffer;
  11538     int *dlb_ecmp_group = NULL;
  11539     int rv = BCM_E_NONE;
  11540 #ifdef BCM_TRX_SUPPORT
  11541     uint32 ing_config_2;
  11542     uint8 ecmp_hash_16bits;
  11543 #endif
  11544 
  11545 #ifdef BCM_TOMAHAWK_SUPPORT
  11546     int old_grp_tbl_idx_max = 0;
  11547     int old_grp_tbl_idx_min = 0;
  11548     _bcm_l3_tbl_t *grp_tbl_ptr = NULL;
  11549     int old_ecmp_tbl_idx_max = 0;
  11550     int old_ecmp_tbl_idx_min = 0;
  11551     _bcm_l3_tbl_t *ecmp_tbl_ptr = NULL;
  11552 #endif /* BCM_TOMAHAWK_SUPPORT */
  11553 
  11554     /* Make sure ecmp group write call is defined for the device. */
  11555     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, ecmp_grp_add)) {
  11556         return (BCM_E_UNAVAIL);
  11557     }
  11558 
  11559     /*
  11560      * Next hop indexes must be sorted in the group
  11561      * in order to produce identical hash every time.
  11562      */
  11563     if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) ||
  11564         !((SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT(unit) ||
  11565 #if defined(BCM_TRIDENT3_SUPPORT)
  11566            SOC_IS_TRIDENT3X(unit) ||
  11567 #endif
  11568            SOC_IS_TOMAHAWKX(unit)) &&
  11569            ((ecmp_flags & BCM_L3_ECMP_PATH_NO_SORTING) ||
  11570             (SOC_IS_TOMAHAWK3(unit) && (ecmp_flags & BCM_L3_ECMP_WEIGHTED))
  11571         )))  {
  11572 
  11573 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  11574         if (soc_feature(unit, soc_feature_dgm) &&
  11575             (ecmp_flags & BCM_L3_ECMP_DGM_OPT)) {
  11576 
  11577             /* first sort primary, then sort alternate if exist.
  11578              * assume primary and alternate can be seperated via primary_count.
  11579              */
  11580             _shr_sort(ecmp_group, primary_count, sizeof(int), _bcm_xgs3_cmp_int);
  11581             if (ecmp_count - primary_count) {
  11582                 _shr_sort(&ecmp_group[primary_count], ecmp_count - primary_count,
  11583                           sizeof(int), _bcm_xgs3_cmp_int);
  11584             }
  11585         } else
  11586 #endif
  11587         {
  11588             _shr_sort(ecmp_group, ecmp_count, sizeof(int), _bcm_xgs3_cmp_int);
  11589         }
  11590     }
  11591 
  11592     /* Initialization */
  11593     sal_memset(&ecmp_info, 0, sizeof(ecmp_info));
  11594     sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t));
  11595     data.tbl_ptr =  BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  11596     data.oper_flags = flags;
  11597 
  11598 #if defined(BCM_TOMAHAWK3_SUPPORT)
  11599     if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) &&
  11600          (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  11601                                      ecmp_mode_hierarchical)) {
  11602         if (ecmp_flags & BCM_L3_ECMP_OVERLAY) {
  11603             data.tbl_ptr =  BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp);
  11604         }
  11605     }
  11606 #endif
  11607 
  11608     ecmp_info.alternate_cnt = 0;
  11609 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  11610     if (soc_feature(unit, soc_feature_dgm) &&
  11611         (ecmp_flags & BCM_L3_ECMP_DGM_OPT)) {
  11612         ecmp_info.alternate_cnt = ecmp_count - primary_count;
  11613     }
  11614 #endif
  11615 
  11616 #ifdef BCM_TRX_SUPPORT
  11617     if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  11618         if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  11619               /* Limit Max_paths */
  11620             if (soc_feature(unit, soc_feature_l3_ecmp_1k_groups)) {
  11621 
  11622 #ifdef BCM_TOMAHAWK_SUPPORT
  11623                 if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) &&
  11624                     !(ecmp_flags & BCM_L3_ECMP_RH_OPT)) {
  11625                     if ((BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  11626                                      ecmp_mode_hierarchical)) {
  11627 #ifdef BCM_TOMAHAWK3_SUPPORT
  11628                         if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) &&
  11629                             (ecmp_flags & BCM_L3_ECMP_OVERLAY)) {
  11630 
  11631                              /* Overlay ECMP member count must be a power of 2 */
  11632                              if ((ecmp_count & (ecmp_count - 1)) != 0) {
  11633                                 return (BCM_E_PARAM);
  11634                              }
  11635                         } else if (soc_feature(unit, soc_feature_l3_ecmp_weighted) &&
  11636                                    (ecmp_flags &  BCM_L3_ECMP_WEIGHTED)) {
  11637                              if (max_paths >
  11638                                    BCM_TH3_L3_ECMP_WEIGHTED_MAX_PATHS) {
  11639                                  max_paths =
  11640                                    BCM_TH3_L3_ECMP_WEIGHTED_MAX_PATHS;
  11641                              }
  11642                         } else
  11643 #endif
  11644                         if (max_paths > 128) {
  11645                             max_paths = 128;
  11646                         }
  11647                     }
  11648 
  11649                     if (soc_feature(unit, soc_feature_fast_ecmp)) {
  11650                         if (max_paths > 128) {
  11651                             max_paths = 128;
  11652                         }
  11653                     }
  11654 
  11655                     if (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 
  11656                                                        ecmp_mode_single) {
  11657 #ifdef BCM_TOMAHAWK3_SUPPORT
  11658                         if (soc_feature(unit, soc_feature_l3_ecmp_weighted)) {
  11659                             if (ecmp_flags &  BCM_L3_ECMP_WEIGHTED) {
  11660                                 if (max_paths >
  11661                                       BCM_TH3_L3_ECMP_WEIGHTED_MAX_PATHS) {
  11662                                     max_paths =
  11663                                       BCM_TH3_L3_ECMP_WEIGHTED_MAX_PATHS;
  11664                                 }
  11665                             } else {
  11666                                 if (max_paths >
  11667                                       BCM_TH3_L3_ECMP_NON_WEIGHTED_MAX_PATHS) {
  11668                                     max_paths =
  11669                                       BCM_TH3_L3_ECMP_NON_WEIGHTED_MAX_PATHS;
  11670                                 }
  11671                             }
  11672                         } else
  11673 #endif
  11674                         if (max_paths > 1024) {
  11675                             max_paths = 1024;
  11676                         }
  11677                     }
  11678                 }
  11679 #endif /* BCM_TOMAHAWK_SUPPORT */
  11680 
  11681                 if (SOC_IS_TRIDENT(unit)){
  11682                     SOC_IF_ERROR_RETURN
  11683                         (READ_ING_CONFIG_2r(unit, &ing_config_2));
  11684                     ecmp_hash_16bits =
  11685                         soc_reg_field_get(unit, ING_CONFIG_2r, ing_config_2,
  11686                                           ECMP_HASH_16BITSf);
  11687                     if ((!ecmp_hash_16bits) && (max_paths > 256)) {
  11688                         max_paths = 256;
  11689                     }
  11690                 }
  11691                 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  11692                 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  11693             } else if (SOC_IS_TRIDENT(unit)) {
  11694                 if (max_paths > 256) {
  11695                     max_paths = 256;
  11696                 }
  11697                 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  11698                 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  11699             } else if (SOC_IS_SCORPION(unit)) {
  11700                 if (max_paths > 256) {
  11701                     max_paths = 256;
  11702                 }
  11703                 data.width = max_paths;
  11704                 data.oper_flags |= _BCM_L3_SHR_TABLE_TRAVERSE_CONTROL;
  11705             } else if (SOC_IS_GREYHOUND(unit) || SOC_IS_HURRICANE3(unit) ||
  11706                        SOC_IS_SABER2(unit) || SOC_IS_GREYHOUND2(unit)) {
  11707                 if (max_paths > 64) {
  11708                     max_paths = 64;
  11709                 }
  11710                 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  11711                 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  11712             } else if (SOC_IS_MONTEREY(unit)) {
  11713                 if (max_paths > 256) {
  11714                     max_paths = 256;
  11715                 }
  11716                 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  11717                 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  11718             } else if SOC_IS_KATANAX(unit) {
  11719                 if (max_paths > 1024) {
  11720                     max_paths = 1024;
  11721                 }
  11722                 data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  11723                 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  11724             } else {
  11725                 if (max_paths > 32) {
  11726                      max_paths = 32;
  11727                 }
  11728                 data.width = max_paths;
  11729                 if (SOC_IS_TRIUMPH2(unit) ||
  11730                     SOC_IS_APOLLO(unit) ||
  11731                     SOC_IS_VALKYRIE2(unit) ||
  11732                     SOC_IS_KATANAX(unit)) {
  11733                     data.width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  11734                     _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  11735                 }
  11736 
  11737             }
  11738             ecmp_info.max_paths = max_paths;
  11739         } else {
  11740             return (BCM_E_PARAM);
  11741         }
  11742     } else
  11743 #endif  /* BCM_TRX_SUPPORT */
  11744     {
  11745         data.width = _BCM_SINGLE_WIDE;
  11746         ecmp_info.max_paths = _BCM_SINGLE_WIDE;
  11747     }
  11748     ecmp_info.ecmp_flags = ecmp_flags;
  11749     data.info = &ecmp_info;
  11750     if (flags & _BCM_L3_SHR_WITH_ID) {
  11751         data.entry_index = *group_index;
  11752     }
  11753     ecmp_buffer.group_buffer = ecmp_group;
  11754 
  11755 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  11756     if (soc_feature(unit, soc_feature_ecmp_dlb_optimized) &&
  11757         dlb_member_bitmap) {
  11758         int i =0, j = 0, offset = 0;
  11759 
  11760         if (soc_feature(unit, soc_feature_dgm) &&
  11761             (ecmp_flags & BCM_L3_ECMP_DGM_OPT)) {
  11762             if (0 == primary_count) {
  11763                 offset = ecmp_info.max_paths/2;
  11764             }
  11765         }
  11766 
  11767         /* Allocate ecmp dlb group buffer. */
  11768         BCM_IF_ERROR_RETURN(
  11769             _bcm_xgs3_l3_ecmp_group_alloc(unit, &dlb_ecmp_group));
  11770 
  11771         for (i = 0; i < ecmp_count; i++) {
  11772             if (SHR_BITGET(dlb_member_bitmap, i + offset)) {
  11773                 dlb_ecmp_group[j++] = ecmp_group[i];
  11774             }
  11775         }
  11776 
  11777         ecmp_buffer.dlb_group_buffer = dlb_ecmp_group;
  11778     } else
  11779 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/
  11780     {
  11781         ecmp_buffer.dlb_group_buffer = NULL;
  11782     }
  11783 
  11784     data.entry_buffer = (void *)&ecmp_buffer;
  11785 
  11786     data.hash_func = _bcm_xgs3_ecmp_grp_hash_calc;
  11787     data.cmp_func  = _bcm_xgs3_ecmp_grp_cmp;
  11788     data.add_func  = BCM_XGS3_L3_HWCALL(unit, ecmp_grp_add);
  11789 #ifdef BCM_TOMAHAWK_SUPPORT
  11790     if (soc_feature(unit, soc_feature_hierarchical_ecmp) &&
  11791         (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 
  11792                                         ecmp_mode_hierarchical)) {
  11793         grp_tbl_ptr = data.tbl_ptr;
  11794         ecmp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp);
  11795         old_grp_tbl_idx_max = grp_tbl_ptr->idx_max;
  11796         old_grp_tbl_idx_min = grp_tbl_ptr->idx_min;
  11797         old_ecmp_tbl_idx_max = ecmp_tbl_ptr->idx_max;
  11798         old_ecmp_tbl_idx_min = ecmp_tbl_ptr->idx_min;
  11799         if (ecmp_flags & BCM_L3_ECMP_OVERLAY) {
  11800             /*
  11801              * For ECMP group at Level 1, ecmp group can only be added
  11802              * in first half of ECMP table
  11803              */
  11804             if (!soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) {
  11805                 grp_tbl_ptr->idx_max = grp_tbl_ptr->idx_max/2;
  11806             }
  11807             ecmp_tbl_ptr->idx_max = ecmp_tbl_ptr->idx_max/2;
  11808         } else if (ecmp_flags & BCM_L3_ECMP_UNDERLAY) {
  11809             /*
  11810              * For ECMP group at Level 2, ecmp group can only be added
  11811              * in second half of ECMP table
  11812              */
  11813             grp_tbl_ptr->idx_min = (grp_tbl_ptr->idx_max/2) + 1;
  11814             ecmp_tbl_ptr->idx_min = (ecmp_tbl_ptr->idx_max/2) + 1;
  11815         }
  11816     }
  11817 #ifdef BCM_TOMAHAWK3_SUPPORT
  11818     /* If DLB group setup min and max so that the grp is allocated from
  11819         the DLB range. Otherwise make sure the group allocated doesnt
  11820         fall in the DLB range. */
  11821     if ((soc_feature(unit, soc_feature_th3_style_dlb) &&
  11822          !(ecmp_flags & BCM_L3_ECMP_OVERLAY))) {
  11823         grp_tbl_ptr = data.tbl_ptr;
  11824         old_grp_tbl_idx_max = grp_tbl_ptr->idx_max;
  11825         old_grp_tbl_idx_min = grp_tbl_ptr->idx_min;
  11826         if (!dlb_ecmp_group) {
  11827             grp_tbl_ptr->idx_max = BCM_TH3_L3_ECMP_DLB_START(unit) - 1;
  11828         } else {
  11829             grp_tbl_ptr->idx_min = BCM_TH3_L3_ECMP_DLB_START(unit) +
  11830                                    (soc_property_get(unit,
  11831                                         spn_DLB_FLOW_MONITOR_EN, 0) ?
  11832                                         ((BCM_XGS3_L3_MAX_ECMP_MODE(unit)) ?
  11833                                           1 : 2) : 0);
  11834         }
  11835     }
  11836 #endif
  11837 #endif /* BCM_TOMAHAWK_SUPPORT */
  11838 
  11839     /* Add ecmp group. */
  11840     rv = _bcm_xgs3_tbl_add(unit, &data);
  11841 #ifdef BCM_TOMAHAWK_SUPPORT
  11842     if (soc_feature(unit, soc_feature_hierarchical_ecmp) &&
  11843         (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  11844                                        ecmp_mode_hierarchical)) {
  11845         grp_tbl_ptr->idx_max = old_grp_tbl_idx_max;
  11846         grp_tbl_ptr->idx_min = old_grp_tbl_idx_min;
  11847         ecmp_tbl_ptr->idx_max = old_ecmp_tbl_idx_max;
  11848         ecmp_tbl_ptr->idx_min = old_ecmp_tbl_idx_min;
  11849     }
  11850 #ifdef BCM_TOMAHAWK3_SUPPORT
  11851     else if (soc_feature(unit, soc_feature_th3_style_dlb)) {
  11852         grp_tbl_ptr->idx_max = old_grp_tbl_idx_max;
  11853         grp_tbl_ptr->idx_min = old_grp_tbl_idx_min;
  11854     }
  11855 #endif
  11856 #endif /* BCM_TOMAHAWK_SUPPORT */
  11857     if (BCM_FAILURE(rv)) {
  11858         if (dlb_ecmp_group) {
  11859             sal_free(dlb_ecmp_group);
  11860         }
  11861         return rv;
  11862     }
  11863 
  11864     *group_index = data.entry_index;
  11865     /* Indicate that at least one ecmp path is present. */
  11866     if (!BCM_XGS3_L3_ECMP_IN_USE(unit)) {
  11867         BCM_XGS3_L3_ECMP_IN_USE(unit) = 1;
  11868     }
  11869 
  11870     /* If ID and UPDATE flag is set, then the entry is already present
  11871      * in the hardware, so no need to increment
  11872      */
  11873 
  11874     if (!((flags & _BCM_L3_SHR_UPDATE) &&
  11875           (flags & _BCM_L3_SHR_WITH_ID))) {
  11876         BCM_XGS3_L3_ECMP_GRP_CNT(unit)++;
  11877     }
  11878 
  11879     if (ecmp_flags & BCM_L3_ECMP_PATH_NO_SORTING) {
  11880         BCM_XGS3_L3_ECMP_GROUP_FLAGS_SET(unit, *group_index,
  11881                                      BCM_L3_ECMP_PATH_NO_SORTING);
  11882     } else {
  11883         BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit, *group_index,
  11884                                     BCM_L3_ECMP_PATH_NO_SORTING);
  11885     }
  11886     if (ecmp_flags & BCM_L3_ECMP_OVERLAY) {
  11887         BCM_XGS3_L3_ECMP_GROUP_FLAGS_SET(unit, *group_index,
  11888                                      BCM_L3_ECMP_OVERLAY);
  11889     } else {
  11890         BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit, *group_index,
  11891                                     BCM_L3_ECMP_OVERLAY);
  11892     }
  11893     if (ecmp_flags & BCM_L3_ECMP_UNDERLAY) {
  11894         BCM_XGS3_L3_ECMP_GROUP_FLAGS_SET(unit, *group_index,
  11895                                      BCM_L3_ECMP_UNDERLAY);
  11896     } else {
  11897         BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit, *group_index,
  11898                                     BCM_L3_ECMP_UNDERLAY);
  11899     }
  11900 
  11901     if (SOC_IS_TOMAHAWK3(unit)) {
  11902         if (ecmp_flags & BCM_L3_ECMP_WEIGHTED) {
  11903             BCM_XGS3_L3_ECMP_GROUP_FLAGS_SET(unit, *group_index,
  11904                                         BCM_L3_ECMP_WEIGHTED);
  11905         } else {
  11906             BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit, *group_index,
  11907                                     BCM_L3_ECMP_WEIGHTED);
  11908         }
  11909     }
  11910     if (dlb_ecmp_group) {
  11911         sal_free(dlb_ecmp_group);
  11912     }
  11913 
  11914     return (BCM_E_NONE);
  11915 }
  11916 
  11917 /*
  11918  * Function:
  11919  *      _bcm_xgs3_ecmp_group_enlarge
  11920  * Purpose:
  11921  *      Recalculate max paths of ecmp group.
  11922  * Parameters:
  11923  *      unit          - (IN)SOC unit number.
  11924  *      ecmp_flags    - (IN)BCM_L3_ECMP_OVERLAY,etc.
  11925  *      max_paths     - (IN/OUT)ecmp group max group size.
  11926  *      width         - (OUT)Number of entries required for one record.
  11927  *      value         - (OUT)max paths parameter.
  11928  * Returns:
  11929  *    BCM_E_XXX
  11930  */
  11931 #if defined(BCM_TRX_SUPPORT) 
  11932 STATIC int
  11933 _bcm_xgs3_ecmp_max_grp_size_calc(int unit, uint32 ecmp_flags,
  11934     int *max_paths, int *width, int *value)
  11935 {
  11936 #ifdef BCM_TRX_SUPPORT
  11937     uint32 ing_config_2;
  11938     uint8 ecmp_hash_16bits;
  11939 
  11940     if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  11941         if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  11942               /* Limit Max_paths */
  11943             if (soc_feature(unit, soc_feature_l3_ecmp_1k_groups)) {
  11944 #ifdef BCM_TOMAHAWK_SUPPORT
  11945                 if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) &&
  11946                     !(ecmp_flags & BCM_L3_ECMP_RH_OPT)) {
  11947 #ifdef BCM_TOMAHAWK3_SUPPORT
  11948                     if (soc_feature(unit, soc_feature_l3_ecmp_weighted)) {
  11949                         if (*max_paths > 4096) {
  11950                             *max_paths = 4096;
  11951                         }
  11952                     } else
  11953 #endif
  11954                     {
  11955                     if ((BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  11956                                      ecmp_mode_hierarchical)) {
  11957                         if (*max_paths > 128) {
  11958                             *max_paths = 128;
  11959                         }
  11960                     }
  11961 
  11962                     if (soc_feature(unit, soc_feature_fast_ecmp)) {
  11963                         if (*max_paths > 128) {
  11964                             *max_paths = 128;
  11965                         }
  11966                     }
  11967 
  11968                     if (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  11969                                                        ecmp_mode_single) {
  11970                         if (*max_paths > 1024) {
  11971                             *max_paths = 1024;
  11972                         }
  11973                     }
  11974                 }
  11975                 }
  11976 #endif /* BCM_TOMAHAWK_SUPPORT */
  11977 
  11978                 if (SOC_IS_TRIDENT(unit)){
  11979                     SOC_IF_ERROR_RETURN
  11980                         (READ_ING_CONFIG_2r(unit, &ing_config_2));
  11981                     ecmp_hash_16bits =
  11982                         soc_reg_field_get(unit, ING_CONFIG_2r, ing_config_2,
  11983                                           ECMP_HASH_16BITSf);
  11984                     if ((!ecmp_hash_16bits) && (*max_paths > 256)) {
  11985                         *max_paths = 256;
  11986                     }
  11987                 }
  11988                 *width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  11989                              _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  11990             } else if (SOC_IS_TRIDENT(unit)) {
  11991                 if (*max_paths > 256) {
  11992                     *max_paths = 256;
  11993                 }
  11994                 *width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  11995                              _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  11996             } else if (SOC_IS_SCORPION(unit)) {
  11997                 if (*max_paths > 256) {
  11998                     *max_paths = 256;
  11999                 }
  12000                 *width = *max_paths;
  12001             } else if (SOC_IS_GREYHOUND(unit) || SOC_IS_HURRICANE3(unit) ||
  12002                        SOC_IS_SABER2(unit) || SOC_IS_GREYHOUND2(unit)) {
  12003                 if (*max_paths > 64) {
  12004                     *max_paths = 64;
  12005                 }
  12006                 *width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  12007                              _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  12008             } else if (SOC_IS_MONTEREY(unit)) {
  12009                 if (*max_paths > 256) {
  12010                     *max_paths = 256;
  12011                 }
  12012                 *width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  12013                 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  12014             } else if (SOC_IS_KATANAX(unit)) {
  12015                 if (*max_paths > 1024) {
  12016                     *max_paths = 1024;
  12017                 }
  12018                 *width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  12019                 _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  12020             } else {
  12021                 if (*max_paths > 32) {
  12022                      *max_paths = 32;
  12023                 }
  12024                 *width = *max_paths;
  12025                 if (SOC_IS_TRIUMPH2(unit) ||
  12026                     SOC_IS_APOLLO(unit) ||
  12027                     SOC_IS_VALKYRIE2(unit) ||
  12028                     SOC_IS_KATANAX(unit)) {
  12029                     *width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  12030                                  _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  12031                 }
  12032 
  12033             }
  12034             *value = *max_paths;
  12035         } else {
  12036             return (BCM_E_PARAM);
  12037         }
  12038     } else
  12039 #endif  /* BCM_TRX_SUPPORT */
  12040     {
  12041         COMPILER_REFERENCE(max_paths);
  12042         *width = _BCM_SINGLE_WIDE;
  12043         *value = _BCM_SINGLE_WIDE;
  12044     }
  12045     return BCM_E_NONE;
  12046 }
  12047 #endif /* BCM_TRX_SUPPORT */
  12048 
  12049 /*
  12050  * Function:
  12051  *      _bcm_xgs3_ecmp_group_enlarge
  12052  * Purpose:
  12053  *      Enlarge the max group size of ecmp group.
  12054  * Parameters:
  12055  *      unit              - (IN)SOC unit number.
  12056  *      ecmp_group_id     - (IN)Ecmp group index.
  12057  *      old_ecmp_base_idx - (IN) Old base index of L3_ECMP
  12058  *      old_max_paths     - (IN)Old max group size.
  12059  *      new_max_paths     - (IN)New max group size.
  12060  *      ecmp_flags        - (IN)Ecmp flags
  12061  * Returns:
  12062  *    BCM_E_XXX
  12063  */
  12064 #ifdef BCM_TRIUMPH2_SUPPORT
  12065 STATIC int
  12066 _bcm_xgs3_ecmp_group_enlarge(int unit,
  12067     int ecmp_group_id, int old_ecmp_base_idx, int old_max_paths,
  12068     int new_max_paths, uint32 ecmp_flags)
  12069 {
  12070 #ifdef BCM_TRIUMPH2_SUPPORT
  12071     int idx = 0, idx_min = 0, idx_max = 0, *maxused_idx;
  12072     int rv = BCM_E_NONE;
  12073     soc_defragment_member_op_t member_op;
  12074     soc_defragment_group_op_t group_op;
  12075     int new_ecmp_base_idx = 0;
  12076     _bcm_l3_tbl_op_t data;
  12077     int old_base_after_defrag = 0;
  12078 
  12079     if (old_max_paths > new_max_paths) {
  12080         return BCM_E_PARAM;
  12081     }
  12082     sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t));
  12083     if (SOC_IS_ENDURO(unit)) {
  12084         data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  12085     } else {
  12086         data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp);
  12087     }
  12088     data.oper_flags = _BCM_L3_SHR_TABLE_TRAVERSE_CONTROL;
  12089 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
  12090     /*
  12091      * we can look into the ecmp_grp index to know if this
  12092      * is overlay entry or underlay entry.
  12093      */
  12094     if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) {
  12095         if (ecmp_group_id < BCMI_L3_ECMP_OVERLAY_ENTRIES(unit)) {
  12096 
  12097            data.oper_flags |= _BCM_L3_SHR_OVERLAY_OBJECT;
  12098         }
  12099     }
  12100 #endif
  12101 
  12102     bcmi_xgs3_tbl_idx_range_get(unit, &idx_min, &idx_max, &maxused_idx, &data);
  12103     /* Check if it is possible to increase max grp size in-place. */
  12104     for (idx = old_ecmp_base_idx + old_max_paths;
  12105          (idx < (old_ecmp_base_idx + new_max_paths)) && (idx <= idx_max);
  12106          idx++) {
  12107 
  12108         if(BCM_XGS3_L3_ENT_REF_CNT(data.tbl_ptr, idx)) {
  12109              break;
  12110         }
  12111     }
  12112 
  12113     if (SOC_IS_ENDURO(unit)) {
  12114         if (idx == old_ecmp_base_idx + new_max_paths) {
  12115             BCM_IF_ERROR_RETURN(_bcm_xgs3_ecmp_max_grp_size_set(unit,
  12116                 ecmp_group_id, new_max_paths, ecmp_flags));
  12117             return BCM_E_NONE;
  12118         } else {
  12119             /* cannot enlarge group for enduro now */
  12120             return BCM_E_PARAM;
  12121         }
  12122     } else {
  12123         if (idx == old_ecmp_base_idx + new_max_paths) {
  12124             BCM_IF_ERROR_RETURN(_bcm_xgs3_ecmp_max_grp_size_set(unit,
  12125                 ecmp_group_id, new_max_paths, ecmp_flags));
  12126             BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ecmp),
  12127                 old_ecmp_base_idx, old_max_paths);
  12128             BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ecmp),
  12129                 old_ecmp_base_idx, new_max_paths);
  12130             return BCM_E_NONE;
  12131         }
  12132     }
  12133 
  12134     data.width = new_max_paths;
  12135     data.entry_index = -1;
  12136     rv = _bcm_xgs3_tbl_free_idx_get(unit, &data);
  12137     if (rv == BCM_E_FULL) {
  12138         /* Defragment ECMP table */
  12139 #ifdef BCM_TOMAHAWK_SUPPORT
  12140         /* Pass ECMP level so the defragmentation can happen in the
  12141            right part of the ECMP table */
  12142         if (soc_feature(unit, soc_feature_hierarchical_ecmp) &&
  12143             (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  12144                                  ecmp_mode_hierarchical)) {
  12145             if (data.tbl_ptr->idx_min > 0) {
  12146                 /* De-fragment Level 2 or Underlay ECMP table 
  12147                  * ecmp_flags & BCM_L3_ECMP_UNDERLAY */
  12148                 BCM_IF_ERROR_RETURN(bcm_tr2_l3_ecmp_defragment_no_lock(unit, 2));
  12149             } else if ((data.tbl_ptr->idx_min == 0) &&
  12150                      (data.tbl_ptr->idx_max < soc_mem_index_max(unit, L3_ECMPm))) {
  12151                 /* De-fragment Level 1 or Overlay ECMP table 
  12152                  * ecmp_flags & BCM_L3_ECMP_OVERLAY */
  12153                 BCM_IF_ERROR_RETURN(bcm_tr2_l3_ecmp_defragment_no_lock(unit, 1));
  12154             } else {
  12155                 /*
  12156                  * The current entry can go in anywhere in the ECMP table.
  12157                  * Means ecmp_group was created with flags 0,
  12158                  * De-fragment the entire ECMP table
  12159                  */
  12160                 BCM_IF_ERROR_RETURN(bcm_tr2_l3_ecmp_defragment_no_lock(unit, 2));
  12161                 BCM_IF_ERROR_RETURN(bcm_tr2_l3_ecmp_defragment_no_lock(unit, 1));
  12162             }
  12163         } else
  12164 #elif defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
  12165         if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) {
  12166             if (data.oper_flags & _BCM_L3_SHR_OVERLAY_OBJECT) {
  12167                 BCM_IF_ERROR_RETURN(
  12168                     bcm_tr2_l3_ecmp_defragment_no_lock(unit, 2));
  12169             } else {
  12170                 BCM_IF_ERROR_RETURN(
  12171                     bcm_tr2_l3_ecmp_defragment_no_lock(unit, 1));
  12172             }
  12173         } else
  12174 #endif
  12175         {
  12176             BCM_IF_ERROR_RETURN(bcm_tr2_l3_ecmp_defragment_no_lock(unit, 0));
  12177         }
  12178 
  12179         BCM_IF_ERROR_RETURN(
  12180             _bcm_xgs3_l3_ecmp_grp_info_get(unit, ecmp_group_id,
  12181                                            NULL, &old_base_after_defrag));
  12182 
  12183         if (old_base_after_defrag != old_ecmp_base_idx) {
  12184             old_ecmp_base_idx = old_base_after_defrag;
  12185         }
  12186 
  12187         /* Check if it is possible to increase max grp size in-place. */
  12188         for (idx = old_ecmp_base_idx + old_max_paths;
  12189             (idx < (old_ecmp_base_idx + new_max_paths)) && (idx <= idx_max);
  12190              idx++) {
  12191 
  12192             if(BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, ecmp), idx)) {
  12193                  break;
  12194             }
  12195         }
  12196         if (idx == old_ecmp_base_idx + new_max_paths) {
  12197             BCM_IF_ERROR_RETURN(_bcm_xgs3_ecmp_max_grp_size_set(unit,
  12198                 ecmp_group_id, new_max_paths, ecmp_flags));
  12199             BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ecmp),
  12200                 old_ecmp_base_idx, old_max_paths);
  12201             BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ecmp),
  12202                 old_ecmp_base_idx, new_max_paths);
  12203             return BCM_E_NONE;
  12204         }
  12205         /* Attempt to get free index again */
  12206         BCM_IF_ERROR_RETURN(_bcm_xgs3_tbl_free_idx_get(unit, &data));
  12207 
  12208     }
  12209 
  12210     new_ecmp_base_idx = data.entry_index;
  12211     member_op.member_copy = _bcm_tr2_l3_ecmp_member_copy;
  12212     member_op.member_clear = _bcm_tr2_l3_ecmp_member_clear;
  12213     group_op.group_base_ptr_update = _bcm_tr2_l3_ecmp_group_base_ptr_update;
  12214     BCM_IF_ERROR_RETURN(soc_defragment_block_move(unit, old_ecmp_base_idx,
  12215         new_ecmp_base_idx, old_max_paths, &member_op,
  12216         ecmp_group_id, &group_op));
  12217     BCM_IF_ERROR_RETURN(_bcm_xgs3_ecmp_max_grp_size_set(unit,
  12218         ecmp_group_id, new_max_paths, ecmp_flags));
  12219     BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ecmp),
  12220         (new_ecmp_base_idx + old_max_paths),
  12221         (new_max_paths - old_max_paths));
  12222     return BCM_E_NONE;
  12223  #endif/* BCM_TRIUMPH2_SUPPORT */
  12224     return BCM_E_PARAM;
  12225 }
  12226 #endif/* BCM_TRIUMPH2_SUPPORT */
  12227 
  12228 /*
  12229  * Function:
  12230  *      _bcm_xgs3_ecmp_group_max_size_update
  12231  * Purpose:
  12232  *      Update the max group size of ecmp group.
  12233  *      Just used by chips which support BCM_TRIUMPH2_SUPPORT.
  12234  * Parameters:
  12235  *      unit          - (IN)SOC unit number.
  12236  *      ecmp_flags    - (IN)BCM_L3_ECMP_OVERLAY,etc.
  12237  *      ecmp_group_id - (IN)Ecmp group index.
  12238  *      new_max_paths - (IN)New max group size.
  12239  * Returns:
  12240  *    BCM_E_XXX
  12241  */
  12242 STATIC int
  12243 _bcm_xgs3_ecmp_group_max_size_update(int unit,
  12244     uint32 ecmp_flags, int ecmp_group_id,
  12245     int old_max_paths, int new_max_paths)
  12246 {
  12247 #ifdef BCM_TRIUMPH2_SUPPORT
  12248     int old_ecmp_base_idx = 0;
  12249     int rv = BCM_E_NONE;
  12250     int width, value;
  12251 #ifdef BCM_TOMAHAWK_SUPPORT
  12252     int old_grp_tbl_idx_max = 0;
  12253     int old_grp_tbl_idx_min = 0;
  12254     _bcm_l3_tbl_t *grp_tbl_ptr = NULL;
  12255     int old_ecmp_tbl_idx_max = 0;
  12256     int old_ecmp_tbl_idx_min = 0;
  12257     _bcm_l3_tbl_t *ecmp_tbl_ptr = NULL;
  12258 #endif /* BCM_TOMAHAWK_SUPPORT */
  12259 
  12260     if (ecmp_group_id < 0 ||
  12261         ecmp_group_id > soc_mem_index_max(unit, L3_ECMP_COUNTm)) {
  12262         return BCM_E_PARAM;
  12263     }
  12264 
  12265     if (new_max_paths == old_max_paths) {
  12266         return BCM_E_NONE;
  12267     }
  12268 
  12269     if (!soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  12270         return BCM_E_PARAM;
  12271     }
  12272 
  12273     BCM_IF_ERROR_RETURN(
  12274         _bcm_xgs3_l3_ecmp_grp_info_get(unit, ecmp_group_id,
  12275                                        NULL, &old_ecmp_base_idx));
  12276 
  12277     if (new_max_paths < old_max_paths) {
  12278         if (!SOC_IS_ENDURO(unit)) {
  12279             /* setup new max_path */
  12280             BCM_IF_ERROR_RETURN(
  12281                 _bcm_xgs3_ecmp_max_grp_size_set(unit, ecmp_group_id,
  12282                                                 new_max_paths, ecmp_flags));
  12283             BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ecmp),
  12284                                         old_ecmp_base_idx, old_max_paths);
  12285         } else {
  12286             /* clean old ecmp member */
  12287             BCM_IF_ERROR_RETURN(
  12288                 bcm_xgs3_ecmp_group_del(unit, ecmp_group_id, _BCM_L3_SHR_CLEAN));
  12289         }
  12290 #ifdef BCM_TOMAHAWK3_SUPPORT
  12291         /* For replace case, set the old_ecmp_base_idx in the entry */
  12292         if ((soc_feature(unit, soc_feature_post_ifp_single_stage_ecmp)) &&
  12293              (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) {
  12294             uint32 hw_buf[SOC_MAX_MEM_WORDS]; /* Buffer to write hw entry. */
  12295             soc_mem_t mem = L3_ECMP_COUNTm;
  12296             if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) &&
  12297                (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  12298                      ecmp_mode_hierarchical) && (ecmp_group_id <
  12299                        (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) {
  12300                 mem = ECMP_GROUP_HIERARCHICALm;
  12301             }
  12302             sal_memset(hw_buf, 0, SOC_MAX_MEM_WORDS * sizeof(uint32));
  12303             soc_mem_field32_set(unit, mem,
  12304                                 hw_buf, BASE_PTRf, old_ecmp_base_idx);
  12305             rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL,
  12306                      (ecmp_group_id), hw_buf);
  12307             if (BCM_FAILURE(rv)) {
  12308                 return rv;
  12309             }
  12310         }
  12311 #endif
  12312 
  12313         /* setup new max_path */
  12314         BCM_IF_ERROR_RETURN(
  12315             _bcm_xgs3_ecmp_max_grp_size_set(unit, ecmp_group_id,
  12316                                             new_max_paths, ecmp_flags));
  12317         /* update ref_cnt of ecmp member in the group
  12318          *  For enduro:
  12319          *    it use ecmp_grp (not ecmp) to record ecmp members,
  12320          *    so update ref_cnt here.
  12321          *    bcm_xgs3_ecmp_group_del(_BCM_L3_SHR_CLEAN)
  12322          *    would not change the ref_cnt of ecmp_grp
  12323          *  For the others:
  12324          *    it use ecmp_grp to record ecmp group information (ex. base_ptr)
  12325          *           ecmp     to record ecmp members
  12326          *    bcm_xgs3_ecmp_group_del(_BCM_L3_SHR_CLEAN) clean the ecmp members
  12327          *    and decrese the ref_cnt, so only need to increase ref_cnt here
  12328          */
  12329         if (SOC_IS_ENDURO(unit)) {
  12330             BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp),
  12331                                         ecmp_group_id, old_max_paths);
  12332             BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp),
  12333                                         ecmp_group_id, new_max_paths);
  12334         } else {
  12335             BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ecmp),
  12336                                         old_ecmp_base_idx, new_max_paths);
  12337         }
  12338         return BCM_E_NONE;
  12339     }
  12340 
  12341 
  12342     if (new_max_paths > old_max_paths) {
  12343         BCM_IF_ERROR_RETURN(
  12344             _bcm_xgs3_ecmp_max_grp_size_calc(unit, ecmp_flags,
  12345                 &new_max_paths, &width, &value));
  12346 
  12347 #ifdef BCM_TOMAHAWK_SUPPORT
  12348         if (soc_feature(unit, soc_feature_hierarchical_ecmp) &&
  12349             (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  12350              ecmp_mode_hierarchical)) {
  12351             grp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  12352             ecmp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp);
  12353             old_grp_tbl_idx_max = grp_tbl_ptr->idx_max;
  12354             old_grp_tbl_idx_min = grp_tbl_ptr->idx_min;
  12355             old_ecmp_tbl_idx_max = ecmp_tbl_ptr->idx_max;
  12356             old_ecmp_tbl_idx_min = ecmp_tbl_ptr->idx_min;
  12357             if (ecmp_flags & BCM_L3_ECMP_OVERLAY) {
  12358                 /*
  12359                  * For ECMP group at Level 1, ecmp group can only be added
  12360                  * in first half of ECMP table
  12361                  */
  12362                 grp_tbl_ptr->idx_max = grp_tbl_ptr->idx_max/2;
  12363                 ecmp_tbl_ptr->idx_max = ecmp_tbl_ptr->idx_max/2;
  12364             } else if (ecmp_flags & BCM_L3_ECMP_UNDERLAY) {
  12365                 /*
  12366                  * For ECMP group at Level 2, ecmp group can only be added
  12367                  * in second half of ECMP table
  12368                  */
  12369                 grp_tbl_ptr->idx_min = (grp_tbl_ptr->idx_max/2) + 1;
  12370                 ecmp_tbl_ptr->idx_min = (ecmp_tbl_ptr->idx_max/2) + 1;
  12371             }
  12372 #ifdef BCM_TOMAHAWK3_SUPPORT
  12373              else {
  12374                 /*
  12375                  * For ECMP group at Level 2, ecmp group can only be added
  12376                  * in second half of ECMP table
  12377                  */
  12378                 grp_tbl_ptr->idx_min = (grp_tbl_ptr->idx_max/2) + 1;
  12379                 ecmp_tbl_ptr->idx_min = (ecmp_tbl_ptr->idx_max/2) + 1;
  12380             }
  12381 #endif
  12382        }
  12383 #endif /* BCM_TOMAHAWK_SUPPORT */
  12384 
  12385        rv = _bcm_xgs3_ecmp_group_enlarge(unit, ecmp_group_id,
  12386                 old_ecmp_base_idx, old_max_paths, new_max_paths, ecmp_flags);
  12387 
  12388 #ifdef BCM_TOMAHAWK_SUPPORT
  12389         if (soc_feature(unit, soc_feature_hierarchical_ecmp) &&
  12390             (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  12391             ecmp_mode_hierarchical)) {
  12392             grp_tbl_ptr->idx_max = old_grp_tbl_idx_max;
  12393             grp_tbl_ptr->idx_min = old_grp_tbl_idx_min;
  12394             ecmp_tbl_ptr->idx_max = old_ecmp_tbl_idx_max;
  12395             ecmp_tbl_ptr->idx_min = old_ecmp_tbl_idx_min;
  12396         }
  12397 #endif /* BCM_TOMAHAWK_SUPPORT */
  12398         if (BCM_FAILURE(rv)) {
  12399             return rv;
  12400         }
  12401         return BCM_E_NONE;
  12402     }
  12403 #endif/* BCM_TRIUMPH2_SUPPORT */
  12404     return BCM_E_PARAM;
  12405 }
  12406 
  12407 
  12408 /*
  12409  * Functions:
  12410  *      _bcm_xgs3_l3_multipathCountUpdate
  12411  * Description:
  12412  *      Helper function to update L3-DEFIP.ECMP_Count via DMA
  12413  * Parameters:
  12414  *     unit         device number
  12415  * Return:
  12416  *     BCM_E_XXX
  12417  */
  12418 
  12419 int
  12420 _bcm_xgs3_l3_multipathCountUpdate (int unit, int set)
  12421 {
  12422     int idx;                      /* Iteration index. */
  12423     char *lpm_tbl_ptr;    /* Dma table pointer.*/
  12424     uint32 *lpm_entry;    /* Hw entry buffer. */
  12425     int defip_table_size;  /* Defip table size. */
  12426     int ecmp_count=0;             /* Next hop count in the group.        */
  12427     int *ecmp_grp;              /* Ecmp group from hw.                 */
  12428     int ecmp_group_idx;
  12429     int rv=BCM_E_NONE, update_flag=0;
  12430     soc_mem_t mem;         /* IPv4 in IPv6 table memory.    */
  12431 
  12432     mem = BCM_XGS3_L3_MEM(unit, defip);
  12433 
  12434     if (!set) {
  12435        return BCM_E_NONE;
  12436     }
  12437 
  12438     /* Allocate ecmp group buffer. */
  12439     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp));
  12440 
  12441     /* Table DMA the LPM table to software copy */
  12442     rv = bcm_xgs3_l3_tbl_dma(unit, mem,
  12443               BCM_XGS3_L3_ENT_SZ(unit, defip), "lpm_tbl",
  12444                    &lpm_tbl_ptr, &defip_table_size);
  12445     if (BCM_FAILURE(rv)) {
  12446          sal_free(ecmp_grp);
  12447          return (rv);
  12448     }
  12449 
  12450     L3_LOCK(unit);
  12451 
  12452     for (idx = 0; idx < defip_table_size; idx++) {
  12453          /* Calculate entry ofset. */
  12454         if (SOC_MEM_IS_VALID(unit, L3_DEFIPm)) {
  12455             lpm_entry =
  12456                   (uint32 *)soc_mem_table_idx_to_pointer(unit, mem,
  12457                                  defip_entry_t *, lpm_tbl_ptr, idx);
  12458         } else {
  12459             lpm_entry =
  12460                 (uint32 *)soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip),
  12461                                          defip_level1_entry_t *, lpm_tbl_ptr, idx);
  12462         }
  12463          if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, VALID0f)) {
  12464               if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP0f)) {
  12465                    ecmp_group_idx = soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP_PTR0f);
  12466                    rv = _bcm_xgs3_ecmp_tbl_read(unit, ecmp_group_idx, ecmp_grp, &ecmp_count);
  12467                    if (rv != BCM_E_NOT_FOUND) {
  12468                         if (BCM_FAILURE(rv)) {
  12469                             sal_free(ecmp_grp);
  12470                             L3_UNLOCK(unit);
  12471                             return (rv);
  12472                         }
  12473                         soc_L3_DEFIPm_field32_set(unit, lpm_entry, ECMP_COUNT0f, ecmp_count);
  12474                         update_flag = 1;
  12475                    }
  12476               }
  12477          }
  12478 
  12479          if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, VALID1f)) {
  12480               if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP1f)) {
  12481                    ecmp_group_idx = soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP_PTR1f);
  12482                    rv = _bcm_xgs3_ecmp_tbl_read(unit, ecmp_group_idx, ecmp_grp, &ecmp_count);
  12483                    if (rv != BCM_E_NOT_FOUND) {
  12484                         if (BCM_FAILURE(rv)) {
  12485                              sal_free(ecmp_grp);
  12486                              L3_UNLOCK(unit);
  12487                              return (rv);
  12488                         }
  12489                         soc_L3_DEFIPm_field32_set(unit, lpm_entry, ECMP_COUNT1f, ecmp_count);
  12490                         update_flag = 1;
  12491                    }
  12492               }
  12493          }
  12494 #ifdef BCM_TRIDENT_SUPPORT
  12495         if ((SOC_IS_TD_TT(unit) || SOC_IS_TD2_TT2(unit)) &&
  12496              update_flag) {
  12497             uint32 i, hit;
  12498             defip_hit_only_entry_t hit_entry[2];
  12499             soc_mem_t hit_mem[] = {L3_DEFIP_HIT_ONLY_Xm, L3_DEFIP_HIT_ONLY_Ym};
  12500             int hit_mem_cnt = 2;
  12501 
  12502             if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWKX(unit) || SOC_IS_APACHE(unit)) {
  12503                 hit_mem[0] = L3_DEFIP_HIT_ONLYm;
  12504                 hit_mem_cnt = 1;
  12505             }
  12506 
  12507             for (i = 0, hit = 0; i < hit_mem_cnt; i++) {
  12508                 BCM_IF_ERROR_RETURN
  12509                     (BCM_XGS3_MEM_READ(unit, hit_mem[i],
  12510                                        idx, &hit_entry[i]));
  12511                 hit |= soc_mem_field32_get(unit, hit_mem[i],
  12512                                            &hit_entry[i], HIT0f);
  12513             }
  12514             soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, HIT0f, hit);
  12515             for (i = 0, hit = 0; i < hit_mem_cnt; i++) {
  12516                 hit |= soc_mem_field32_get(unit, hit_mem[i],
  12517                                            &hit_entry[i], HIT1f);
  12518             }
  12519             soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, HIT1f, hit);
  12520         }
  12521 #endif /* BCM_TRIDENT_SUPPORT */
  12522     }
  12523     /* Write the modified  buffer back. */
  12524     if (update_flag) {
  12525         rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ALL,
  12526                                  soc_mem_index_min(unit, mem),
  12527                                  soc_mem_index_max(unit, mem), lpm_tbl_ptr);
  12528     }
  12529     sal_free(ecmp_grp);
  12530     soc_cm_sfree(unit, lpm_tbl_ptr);
  12531     L3_UNLOCK(unit);
  12532     return (rv);
  12533 }
  12534 
  12535 
  12536 
  12537 /*
  12538  * Function:
  12539  *      bcm_xgs3_proxy_nh_add
  12540  * Purpose:
  12541  *       Allocate NextHop table index & Write NextHop entry.
  12542  *       Routine trying to match new entry to an existing one,
  12543  *       if match found reference cound is incremented, otherwise
  12544  *       new index allocated & entry added to hw.
  12545  * Parameters:
  12546  *      unit      - (IN)SOC unit number.
  12547  *      flags     - (IN)Egress object flags.
  12548  *      nh_info   - (IN)Next hop  entry info.
  12549  *      index     - (OUT)Next hop index.
  12550  * Returns:
  12551  *    BCM_E_XXX
  12552  */
  12553 
  12554 int
  12555 bcm_xgs3_proxy_nh_add(int unit, uint32 flags, bcm_proxy_egress_t *proxy_nh_info, int *index)
  12556 {
  12557     int rv = BCM_E_UNAVAIL;
  12558     _bcm_l3_tbl_op_t data;        /* Operation data. */
  12559     bcm_port_t port, port_out;
  12560     bcm_module_t modid, modid_out;
  12561     bcm_trunk_t trunk;
  12562     int id;
  12563 
  12564     /*  Make sure module was initialized. */
  12565     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  12566         return (BCM_E_INIT);
  12567     }
  12568 
  12569     /* Input parameters check. */
  12570     if (NULL == proxy_nh_info) {
  12571         return (BCM_E_PARAM);
  12572     }
  12573 
  12574     if (!(flags & _BCM_L3_SHR_WRITE_DISABLE)) {
  12575         /* Make sure hw call is defined. */
  12576         if (!BCM_XGS3_L3_HWCALL_CHECK(unit, proxy_nh_add)) {
  12577             return (BCM_E_UNAVAIL);
  12578         }
  12579 
  12580         /* Convert API next hop entry to HW space format. */
  12581         rv = _bcm_esw_gport_resolve(unit, proxy_nh_info->gport,
  12582                                            &modid, &port,  &trunk, &id);
  12583         BCM_IF_ERROR_RETURN(rv);
  12584 
  12585         if ((proxy_nh_info->flags & BCM_L3_TGID) == 0) {
  12586             BCM_IF_ERROR_RETURN
  12587                 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET,
  12588                                     modid, port,
  12589                                     &modid_out, &port_out));
  12590             if (!SOC_MODID_ADDRESSABLE(unit, modid_out)) {
  12591                 return (BCM_E_BADID);
  12592             }
  12593             if (!SOC_PORT_ADDRESSABLE(unit, port_out)) {
  12594                 return (BCM_E_PORT);
  12595             }
  12596             SOC_GPORT_MODPORT_SET(proxy_nh_info->gport, modid_out, port_out);
  12597         }
  12598     }
  12599 
  12600     /* Initialization */
  12601     sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t));
  12602     data.tbl_ptr =  BCM_XGS3_L3_TBL_PTR(unit, next_hop);
  12603     data.width = _BCM_SINGLE_WIDE;
  12604     data.oper_flags = flags;
  12605     data.entry_buffer = (void *)proxy_nh_info;
  12606     data.hash_func = _bcm_xgs3_nh_hash_calc;
  12607     data.cmp_func  = _bcm_xgs3_nh_ent_cmp;
  12608     data.add_func  = BCM_XGS3_L3_HWCALL(unit, proxy_nh_add);
  12609     if (flags & _BCM_L3_SHR_WITH_ID) {
  12610         data.entry_index = *index;
  12611     }
  12612 
  12613     /* Add next hop table entry. */
  12614     BCM_IF_ERROR_RETURN(_bcm_xgs3_tbl_add(unit, &data));
  12615     *index = data.entry_index;
  12616 
  12617     return (BCM_E_NONE);
  12618 }
  12619 
  12620 
  12621 /*
  12622  * Function:
  12623  *      bcm_xgs3_proxy_nh_get
  12624  * Purpose:
  12625  * Parameters:
  12626  *      unit      - (IN)SOC unit number.
  12627  *      nh_idx    - (IN)Next hop index.
  12628  *      proxy_nh_info   - (OUT)Buffer to fill next hop info.
  12629  * Returns:
  12630  *    BCM_E_XXX
  12631  */
  12632 int
  12633 bcm_xgs3_proxy_nh_get(int unit, int nh_idx, bcm_proxy_egress_t *proxy_nh_info)
  12634 {
  12635     int rv = BCM_E_UNAVAIL;     /* Operation return status.    */
  12636 
  12637     /*  Make sure module was initialized. */
  12638     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  12639         return (BCM_E_INIT);
  12640     }
  12641 
  12642     /* Input parameters check. */
  12643     if (NULL == proxy_nh_info) {
  12644         return (BCM_E_PARAM);
  12645     }
  12646 
  12647     /* Make sure entry is inuse. */
  12648     if (!BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, next_hop), nh_idx)) {
  12649         return (BCM_E_NOT_FOUND);
  12650     }
  12651 
  12652     /* Get next hop entry from hw. */
  12653     if (BCM_XGS3_L3_HWCALL_CHECK(unit, proxy_nh_get)) {
  12654         BCM_XGS3_L3_MODULE_LOCK(unit);
  12655         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, proxy_nh_get) (unit, nh_idx, proxy_nh_info);
  12656         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  12657         BCM_IF_ERROR_RETURN(rv);
  12658     }
  12659     return rv;
  12660 }
  12661 
  12662 #if defined (BCM_TRIUMPH_SUPPORT)
  12663 /*
  12664  * Function:
  12665  *      bcm_esw_l3_ingress_create
  12666  * Purpose:
  12667  *      Create an Ingress Interface object.
  12668  * Parameters:
  12669  *      unit    - (IN)  bcm device.
  12670  *      flags   - (IN)  BCM_L3_INGRESS_REPLACE: replace existing.
  12671  *                          BCM_L3_INGRESS_WITH_ID: intf argument is given.
  12672  *                          BCM_L3_INGRESS_GLOBAL_ROUTE :
  12673  *                          BCM_L3_INGRESS_DSCP_TRUST :
  12674  *      ing_intf     - (IN) Ingress Interface information.
  12675  *      intf_id    - (OUT) L3 Ingress interface id pointing to Ingress object.
  12676  *                      This is an IN argument if either BCM_L3_INGRESS_REPLACE
  12677  *                      or BCM_L3_INGRESS_WITH_ID are given in flags.
  12678  * Returns:
  12679  *      BCM_E_XXX
  12680 */
  12681 
  12682 int
  12683 bcm_xgs3_l3_ingress_create(int unit, bcm_l3_ingress_t *ing_intf, bcm_if_t *intf_id)
  12684 {
  12685     int rv = BCM_E_UNAVAIL;
  12686     _bcm_l3_ingress_intf_t  iif;         /* Ingress interface. */
  12687     int intf_min;
  12688 #ifdef BCM_TOMAHAWK_SUPPORT
  12689     int ecn_map_index;
  12690     int ecn_map_type;
  12691     int ecn_map_num;
  12692 #endif
  12693     /*  Make sure module was initialized. */
  12694     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  12695         return (BCM_E_INIT);
  12696     }
  12697 
  12698     /* Check L3 Ingress Interface mode. */
  12699     if (!(BCM_XGS3_L3_INGRESS_MODE_ISSET(unit))) {
  12700         return (BCM_E_DISABLED);
  12701     }
  12702 
  12703     /* Input parameters check. */
  12704     if ((NULL == ing_intf) || (NULL == intf_id)) {
  12705         return (BCM_E_PARAM);
  12706     }
  12707 
  12708     sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t));
  12709 
  12710     L3_ING_IF_MIN(unit, intf_min);
  12711 
  12712     /* WITH_ID and REPLACE flags check */
  12713     if (ing_intf->flags & BCM_L3_INGRESS_WITH_ID){
  12714         /* Check interface id range */
  12715         if ( (*intf_id < intf_min) ||
  12716              (*intf_id >= BCM_XGS3_L3_ING_IF_TBL_SIZE(unit)) ) {
  12717             return (BCM_E_PARAM);
  12718         }
  12719         iif.intf_id = *intf_id;
  12720         iif.flags |= BCM_L3_INGRESS_WITH_ID;
  12721         if (ing_intf->flags & BCM_L3_INGRESS_REPLACE) {
  12722             iif.flags |= BCM_L3_INGRESS_REPLACE;
  12723         } else if (0 != SHR_BITGET(BCM_XGS3_L3_ING_IF_INUSE(unit), *intf_id)) {
  12724             /* Cannot overwrite if REPLACE Flag is not set */
  12725             return BCM_E_EXISTS;
  12726         }
  12727     } else if (ing_intf->flags & BCM_L3_INGRESS_REPLACE){
  12728         if (0 != SHR_BITGET(BCM_XGS3_L3_ING_IF_INUSE(unit), *intf_id)) {
  12729             iif.intf_id = *intf_id;
  12730             iif.flags |= BCM_L3_INGRESS_REPLACE;
  12731         } else {
  12732             return BCM_E_PARAM;
  12733         }
  12734     }
  12735 
  12736 #ifdef BCM_TOMAHAWK3_SUPPORT
  12737     if (soc_feature(unit, soc_feature_inband_network_telemetry)) {
  12738         if (ing_intf->flags & BCM_L3_INGRESS_INT) {
  12739             iif.flags |= BCM_L3_INGRESS_INT;
  12740         }
  12741     }
  12742 #endif   
  12743 
  12744     /* Enable global route */
  12745     if (ing_intf->flags & BCM_L3_INGRESS_GLOBAL_ROUTE) {
  12746         iif.flags |= BCM_L3_INGRESS_GLOBAL_ROUTE;
  12747     }
  12748 
  12749     /* Enable URPF Default Route Check */
  12750     if (ing_intf->flags & BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK) {
  12751         iif.flags |= BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK;
  12752     }
  12753 
  12754     if (ing_intf->flags & BCM_L3_INGRESS_DSCP_TRUST) {
  12755         iif.qos_map_id = ing_intf->qos_map_id;
  12756         iif.flags |= BCM_L3_INGRESS_DSCP_TRUST;
  12757     }
  12758 
  12759     if (ing_intf->flags & BCM_L3_INGRESS_IPMC_DO_VLAN_DISABLE) {
  12760         iif.flags |= BCM_L3_INGRESS_IPMC_DO_VLAN_DISABLE;
  12761     }
  12762 
  12763     if (ing_intf->flags & BCM_L3_INGRESS_ICMP_REDIRECT_TOCPU) {
  12764         iif.flags |= BCM_L3_INGRESS_ICMP_REDIRECT_TOCPU;
  12765     }
  12766 
  12767     if (ing_intf->flags & BCM_L3_INGRESS_UNKNOWN_IP4_MCAST_TOCPU) {
  12768         iif.flags |= BCM_L3_INGRESS_UNKNOWN_IP4_MCAST_TOCPU;
  12769     }
  12770 
  12771     if (ing_intf->flags & BCM_L3_INGRESS_UNKNOWN_IP6_MCAST_TOCPU) {
  12772         iif.flags |= BCM_L3_INGRESS_UNKNOWN_IP6_MCAST_TOCPU;
  12773     }
  12774 
  12775     if (ing_intf->flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP4_UCAST) {
  12776         iif.flags |= BCM_L3_INGRESS_ROUTE_DISABLE_IP4_UCAST;
  12777     }
  12778 
  12779     if (ing_intf->flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP4_MCAST) {
  12780         iif.flags |= BCM_L3_INGRESS_ROUTE_DISABLE_IP4_MCAST;
  12781     }
  12782 
  12783     if (ing_intf->flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP6_UCAST) {
  12784         iif.flags |= BCM_L3_INGRESS_ROUTE_DISABLE_IP6_UCAST;
  12785     }
  12786 
  12787     if (ing_intf->flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP6_MCAST) {
  12788         iif.flags |= BCM_L3_INGRESS_ROUTE_DISABLE_IP6_MCAST;
  12789     }
  12790 
  12791     if (ing_intf->flags & BCM_L3_INGRESS_UNKNOWN_IPMC_AS_L2MC) {
  12792         iif.flags |= BCM_L3_INGRESS_UNKNOWN_IPMC_AS_L2MC;
  12793     }
  12794 
  12795     if (ing_intf->flags & BCM_L3_INGRESS_SRC_DST_NAT_REALM_ID) {
  12796         iif.flags |= BCM_L3_INGRESS_SRC_DST_NAT_REALM_ID;
  12797     }
  12798 
  12799     if ((ing_intf->urpf_mode < bcmL3IngressUrpfDisable) || 
  12800             (ing_intf->urpf_mode > bcmL3IngressUrpfStrict)) {
  12801         return BCM_E_PARAM;
  12802     }
  12803 #ifdef BCM_TOMAHAWK_SUPPORT    
  12804     if ((SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) &&
  12805         soc_feature(unit, soc_feature_ecn_wred) &&
  12806         (ing_intf->flags & BCM_L3_INGRESS_TUNNEL_TERM_ECN_MAP)) {
  12807         ecn_map_type = ing_intf->tunnel_term_ecn_map_id & 
  12808                         _BCM_XGS5_ECN_MAP_TYPE_MASK;
  12809         ecn_map_index = ing_intf->tunnel_term_ecn_map_id & 
  12810                         _BCM_XGS5_ECN_MAP_NUM_MASK;
  12811         ecn_map_num = 
  12812             soc_mem_index_count(unit, ING_TUNNEL_ECN_DECAPm) / 
  12813             _BCM_ECN_MAX_ENTRIES_PER_TUNNEL_TERM_MAP;
  12814         if (ecn_map_type != _BCM_XGS5_ECN_MAP_TYPE_TUNNEL_TERM) {
  12815             return BCM_E_PARAM;
  12816         }
  12817         if (ecn_map_index >= ecn_map_num) {
  12818             return BCM_E_PARAM;
  12819         }          
  12820         if (!bcmi_xgs5_ecn_map_used_get(unit, ecn_map_index, 
  12821                                         _bcmEcnmapTypeTunnelTerm)) {
  12822             return BCM_E_PARAM;
  12823         }
  12824         iif.tunnel_term_ecn_map_id = ecn_map_index;
  12825         iif.flags |= BCM_L3_INGRESS_TUNNEL_TERM_ECN_MAP;
  12826     }
  12827 #endif /* BCM_TOMAHAWK_SUPPORT */   
  12828     iif.vrf = ing_intf->vrf;
  12829     iif.if_class = ing_intf->intf_class;
  12830     iif.ipmc_intf_id = ing_intf->ipmc_intf_id;
  12831     iif.urpf_mode = ing_intf->urpf_mode;
  12832     iif.nat_realm_id = ing_intf->nat_realm_id;
  12833     iif.ip4_options_profile_id = ing_intf->ip4_options_profile_id;
  12834     rv =_bcm_xgs3_l3_ingress_interface_add (unit, &iif);
  12835     if (BCM_SUCCESS(rv)) {
  12836         *intf_id = iif.intf_id;
  12837 
  12838 #ifdef BCM_WARM_BOOT_SUPPORT
  12839         SOC_CONTROL_LOCK(unit);
  12840         SOC_CONTROL(unit)->scache_dirty = 1;
  12841         SOC_CONTROL_UNLOCK(unit);
  12842 #endif
  12843     }
  12844     return rv;
  12845 }
  12846 
  12847 /*
  12848  * Function:
  12849  *      bcm_xgs3_l3_ingress_destroy
  12850  * Purpose:
  12851  *      Destroy an Ingress Interface object.
  12852  * Parameters:
  12853  *      unit    - (IN) bcm device.
  12854  *      intf_id    - (IN) L3 Ingress interface id pointing to Ingress object.
  12855  * Returns:
  12856  *      BCM_E_XXX
  12857  */
  12858 int
  12859 bcm_xgs3_l3_ingress_destroy(int unit, bcm_if_t intf_id)
  12860 {
  12861     /*  Make sure module was initialized. */
  12862     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  12863         return (BCM_E_INIT);
  12864     }
  12865 
  12866     /* Check L3 Ingress Interface mode. */
  12867     if (!(BCM_XGS3_L3_INGRESS_MODE_ISSET(unit))) {
  12868         return (BCM_E_DISABLED);
  12869     }
  12870 
  12871     /* Input parameters check. */
  12872     if ( (intf_id < 0) ||  (intf_id >= BCM_XGS3_L3_ING_IF_TBL_SIZE(unit))) {
  12873          return (BCM_E_PARAM);
  12874     }
  12875 
  12876     BCM_IF_ERROR_RETURN
  12877           (_bcm_xgs3_l3_ingress_interface_delete(unit, intf_id));
  12878 
  12879 #ifdef BCM_WARM_BOOT_SUPPORT
  12880     SOC_CONTROL_LOCK(unit);
  12881     SOC_CONTROL(unit)->scache_dirty = 1;
  12882     SOC_CONTROL_UNLOCK(unit);
  12883 #endif
  12884     return BCM_E_NONE;
  12885 }
  12886 
  12887 /*
  12888  * Function:
  12889  *      bcm_xgs3_l3_ingress_get
  12890  * Purpose:
  12891  *      Get an Ingress Interface object.
  12892  * Parameters:
  12893  *      unit    - (IN) bcm device.
  12894  *      intf_id    - (IN) L3 Ingress interface id pointing to Ingress object.
  12895  *      ing_intf  - (OUT) Ingress Interface information.
  12896  * Returns:
  12897  *      BCM_E_XXX
  12898  */
  12899 int
  12900 bcm_xgs3_l3_ingress_get(int unit, bcm_if_t intf_id, bcm_l3_ingress_t *ing_intf)
  12901 {
  12902     int rv = BCM_E_UNAVAIL;
  12903     _bcm_l3_ingress_intf_t  iif;         /* Ingress interface. */
  12904 
  12905     /*	Make sure module was initialized. */
  12906     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  12907        return (BCM_E_INIT);
  12908     }
  12909 
  12910     /* Check L3 Ingress Interface mode. */
  12911     if (!(BCM_XGS3_L3_INGRESS_MODE_ISSET(unit))) {
  12912        return (BCM_E_DISABLED);
  12913     }
  12914 
  12915     /* Input parameters check. */
  12916     if ( (intf_id < 0) ||  (intf_id > BCM_XGS3_L3_ING_IF_TBL_SIZE(unit))) {
  12917        return (BCM_E_PARAM);
  12918     }
  12919 
  12920     if (!SHR_BITGET(BCM_XGS3_L3_ING_IF_INUSE(unit), intf_id)) {
  12921         return (BCM_E_NOT_FOUND);
  12922     }
  12923     /* Initialize ingress buffer */
  12924     (void) bcm_l3_ingress_t_init(ing_intf);
  12925     iif.intf_id = intf_id;
  12926 
  12927     rv = _bcm_xgs3_l3_ingress_interface_get(unit, &iif);
  12928     if (BCM_SUCCESS(rv)) {
  12929         ing_intf->vrf = iif.vrf;
  12930         ing_intf->intf_class = iif.if_class;
  12931         ing_intf->ipmc_intf_id = iif.ipmc_intf_id;
  12932         ing_intf->urpf_mode = iif.urpf_mode;
  12933         ing_intf->ip4_options_profile_id = iif.ip4_options_profile_id;
  12934         ing_intf->nat_realm_id = iif.nat_realm_id;
  12935 
  12936         if (iif.flags & BCM_L3_INGRESS_GLOBAL_ROUTE) {
  12937             if (SOC_MEM_FIELD_VALID(unit, L3_IIF_PROFILEm, ALLOW_GLOBAL_ROUTEf)) {
  12938                 ing_intf->flags |= BCM_L3_INGRESS_GLOBAL_ROUTE;
  12939             }
  12940         }
  12941 
  12942         if (iif.flags & BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK) {
  12943             ing_intf->flags |= BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK;
  12944         }
  12945 
  12946         if (iif.flags & BCM_L3_INGRESS_DSCP_TRUST) {
  12947             ing_intf->qos_map_id =  iif.qos_map_id;
  12948             ing_intf->flags |= BCM_L3_INGRESS_DSCP_TRUST;
  12949         }
  12950 
  12951         if (iif.flags & BCM_L3_INGRESS_IPMC_DO_VLAN_DISABLE) {
  12952             ing_intf->flags |= BCM_L3_INGRESS_IPMC_DO_VLAN_DISABLE;
  12953         }
  12954 
  12955         if (iif.flags & BCM_L3_INGRESS_ICMP_REDIRECT_TOCPU) {
  12956             ing_intf->flags |= BCM_L3_INGRESS_ICMP_REDIRECT_TOCPU;
  12957         }
  12958 
  12959         if (iif.flags & BCM_L3_INGRESS_UNKNOWN_IP4_MCAST_TOCPU) {
  12960             ing_intf->flags |= BCM_L3_INGRESS_UNKNOWN_IP4_MCAST_TOCPU;
  12961         }
  12962 
  12963         if (iif.flags & BCM_L3_INGRESS_UNKNOWN_IP6_MCAST_TOCPU) {
  12964             ing_intf->flags |= BCM_L3_INGRESS_UNKNOWN_IP6_MCAST_TOCPU;
  12965         }
  12966 
  12967         if (iif.flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP4_UCAST) {
  12968             ing_intf->flags |= BCM_L3_INGRESS_ROUTE_DISABLE_IP4_UCAST;
  12969         }
  12970 
  12971         if (iif.flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP4_MCAST) {
  12972             ing_intf->flags |= BCM_L3_INGRESS_ROUTE_DISABLE_IP4_MCAST;
  12973         }
  12974 
  12975         if (iif.flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP6_UCAST) {
  12976             ing_intf->flags |= BCM_L3_INGRESS_ROUTE_DISABLE_IP6_UCAST;
  12977         }
  12978 
  12979         if (iif.flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP6_MCAST) {
  12980             ing_intf->flags |= BCM_L3_INGRESS_ROUTE_DISABLE_IP6_MCAST;
  12981         }
  12982 
  12983         if (iif.flags & BCM_L3_INGRESS_UNKNOWN_IPMC_AS_L2MC) {
  12984             ing_intf->flags |= BCM_L3_INGRESS_UNKNOWN_IPMC_AS_L2MC;
  12985         }
  12986 #ifdef BCM_TOMAHAWK_SUPPORT        
  12987         if ((SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) &&
  12988             soc_feature(unit, soc_feature_ecn_wred) &&
  12989             (bcmi_xgs5_ecn_map_used_get(unit, ing_intf->tunnel_term_ecn_map_id,
  12990                                        _bcmEcnmapTypeTunnelTerm) > 0)) {
  12991             ing_intf->flags |= BCM_L3_INGRESS_TUNNEL_TERM_ECN_MAP;
  12992             ing_intf->tunnel_term_ecn_map_id = iif.tunnel_term_ecn_map_id | 
  12993                 _BCM_XGS5_ECN_MAP_TYPE_TUNNEL_TERM;
  12994         }
  12995 #endif        
  12996     }
  12997 
  12998     return rv;
  12999 }
  13000 
  13001 /*
  13002  * Function:
  13003  *      bcm_xgs3_l3_ingress_find
  13004  * Purpose:
  13005  *      Find an Ingress Interface object.
  13006  * Parameters:
  13007  *      unit       - (IN) bcm device.
  13008  *      ing_intf        - (IN) Ingress Interface information.
  13009  *      intf_id       - (OUT) L3 Ingress interface id pointing to Ingress object.
  13010  * Returns:
  13011  *      BCM_E_XXX
  13012  */
  13013 int
  13014 bcm_xgs3_l3_ingress_find(int unit, bcm_l3_ingress_t *ing_intf,
  13015                         bcm_if_t *intf_id)
  13016 {
  13017     _bcm_l3_ingress_intf_t  iif;         /* Ingress interface. */
  13018     int index_max;                       /* max index for L3_IIF */
  13019     int idx;          /* Start index */
  13020 
  13021     /*  Make sure module was initialized. */
  13022     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  13023         return (BCM_E_INIT);
  13024     }
  13025 
  13026     /* Check l3 switching mode. */
  13027     if (!(BCM_XGS3_L3_INGRESS_MODE_ISSET(unit))) {
  13028         return (BCM_E_DISABLED);
  13029     }
  13030 
  13031     /* Input parameters check. */
  13032     if ((NULL == ing_intf) || (NULL == intf_id)) {
  13033         return (BCM_E_PARAM);
  13034     }
  13035 
  13036     sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t));
  13037 
  13038 
  13039     /* cannot match vrf or urpf_mode if these fields do not exist */
  13040     if (!soc_mem_field_valid(unit, L3_IIFm, VRFf) &&
  13041         ing_intf->vrf != 0) {
  13042         return BCM_E_UNAVAIL;
  13043     }
  13044     if (!(soc_mem_field_valid(unit, L3_IIFm, URPF_MODEf) ||
  13045           (soc_feature(unit, soc_feature_l3_iif_profile) &&
  13046            soc_mem_field_valid(unit, L3_IIF_PROFILEm, URPF_MODEf))) &&
  13047         ing_intf->urpf_mode != 0) {
  13048         return BCM_E_UNAVAIL;
  13049     }
  13050 
  13051     L3_ING_IF_MIN(unit, idx);
  13052 
  13053     /* get max table index */
  13054     index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, ing_intf));
  13055     for (;idx <= index_max; idx++) {
  13056         if (!SHR_BITGET(BCM_XGS3_L3_ING_IF_INUSE(unit), idx)) {
  13057             continue;
  13058         }
  13059 
  13060         iif.intf_id = idx;
  13061         BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ingress_interface_get(unit, &iif));
  13062 
  13063         /* Match VRF */
  13064         if (iif.vrf != ing_intf->vrf) {
  13065             continue;
  13066         }
  13067 
  13068         /* Match urpf_mode */
  13069         if (iif.urpf_mode != ing_intf->urpf_mode) {
  13070             continue;
  13071         }
  13072         break;
  13073     }
  13074 
  13075     if (idx > index_max) {
  13076         return BCM_E_NOT_FOUND;
  13077     }
  13078 
  13079     *intf_id = idx;
  13080 
  13081     return (BCM_E_NONE);
  13082 }
  13083 
  13084 /*
  13085  * Function:
  13086  *      _bcm_xgs3_ing_intf_traverse_cb
  13087  * Purpose:
  13088  *      Call user callback for valid L3_IIF entries.
  13089  * Parameters:
  13090  *      unit      - (IN)SOC unit number.
  13091  *      pattern   - (IN)Match pattern (interface id & negate).
  13092  *      data1     - (IN)Route info.
  13093  *      data2     - (IN)Next hop info.
  13094  *      cmp_result- (OUT)Comparison result.
  13095  * Returns:
  13096  *      BCM_E_XXX
  13097  */
  13098 STATIC int
  13099 _bcm_xgs3_ing_intf_traverse_cb(int unit, void *pattern, void *data1,
  13100                          void *data2, int *cmp_result)
  13101 {
  13102     _bcm_l3_trvrs_data_t *trv_data;     /* Travers data.    */
  13103     bcm_l3_ingress_t  *ing_intf;              /* Ingress object.   */
  13104     int intf_id;                         /* L3 IIF index.  */
  13105 
  13106 
  13107     /* Cast input parameters. */
  13108     trv_data = (_bcm_l3_trvrs_data_t *) pattern;
  13109     ing_intf      = (bcm_l3_ingress_t *) data1;
  13110     intf_id   = *(int *)data2;
  13111 
  13112     /* Call user callback. */
  13113     if (NULL != trv_data->ingress_cb) {
  13114         (*trv_data->ingress_cb) (unit, intf_id, ing_intf, trv_data->cookie);
  13115     }
  13116 
  13117     return (BCM_E_NONE);
  13118 }
  13119 
  13120 
  13121 /*
  13122  * Function:
  13123  *      bcm_xgs3_l3_ingress_traverse
  13124  * Purpose:
  13125  *      Goes through ingress interface objects table and runs the user callback
  13126  *      function at each valid ingress objects entry passing back the
  13127  *      information for that object.
  13128  * Parameters:
  13129  *      unit       - (IN) bcm device.
  13130  *      trav_fn    - (IN) Callback function.
  13131  *      user_data  - (IN) User data to be passed to callback function.
  13132  * Returns:
  13133  *      BCM_E_XXX
  13134  */
  13135 
  13136 int
  13137 bcm_xgs3_l3_ingress_traverse(int unit, bcm_l3_ingress_traverse_cb trav_fn,
  13138                             void *user_data)
  13139 {
  13140     _bcm_l3_trvrs_data_t trv_data;     /* Travers initiator function input. */
  13141 
  13142     /*  Make sure module was initialized. */
  13143     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  13144         return (BCM_E_INIT);
  13145     }
  13146 
  13147     /* Check l3 switching mode. */
  13148     if (!(BCM_XGS3_L3_INGRESS_MODE_ISSET(unit))) {
  13149         return (BCM_E_DISABLED);
  13150     }
  13151 
  13152     /* Input parameters check. */
  13153     if (NULL == trav_fn) {
  13154         return (BCM_E_PARAM);
  13155     }
  13156 
  13157     /* Zero traverse info. */
  13158     sal_memset(&trv_data, 0, sizeof(_bcm_l3_trvrs_data_t));
  13159 
  13160     /* Fill traverse data struct. */
  13161     trv_data.op_cb = _bcm_xgs3_ing_intf_traverse_cb;
  13162     trv_data.ingress_cb = trav_fn;
  13163     trv_data.cookie = user_data;
  13164 
  13165     /*  Update_match */
  13166     if (BCM_XGS3_L3_HWCALL_CHECK(unit, ing_intf_update_match)) {
  13167         int rv;
  13168         BCM_XGS3_L3_MODULE_LOCK(unit);
  13169         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ing_intf_update_match) (unit, &trv_data);
  13170         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  13171         return rv;
  13172     }
  13173 
  13174     return (BCM_E_UNAVAIL);
  13175 }
  13176 
  13177 
  13178 /*
  13179  * Function:
  13180  *      _bcm_xgs3_ing_intf_entry_parse
  13181  * Purpose:
  13182  *      Parse the L3 Ingress Interface  table entry info.
  13183  * Parameters:
  13184  *      unit          - (IN) SOC unit number.
  13185  *      ing_entry_ptr - (IN) Ingress Interface table entry.
  13186  *      bcm_l3_ingress_t      - (OUT) Ingress Interface table entry info.
  13187  * Returns:
  13188  *      BCM_E_XXX
  13189  */
  13190 
  13191 STATIC int
  13192 _bcm_xgs3_ing_intf_entry_parse(int unit, uint32 *ing_entry_ptr,
  13193                          bcm_l3_ingress_t *ing_intf_entry)
  13194 {
  13195     soc_mem_t mem;                      /* Table location memory.           */
  13196     int hw_map_idx=0;
  13197 #ifdef BCM_TRIDENT2_SUPPORT
  13198     iif_entry_t entry;       /* HW entry buffer.        */
  13199     uint32 index;
  13200     void *entries[1];
  13201     iif_profile_entry_t l3_iif_profile;
  13202 #endif
  13203 
  13204     /* Zero buffers. */
  13205     sal_memset(ing_intf_entry, 0, sizeof(bcm_l3_ingress_t));
  13206 
  13207     /* Get next hop table memory location. */
  13208     mem = BCM_XGS3_L3_MEM(unit, ing_intf);
  13209 
  13210     /* Get class id value. */
  13211     if (SOC_MEM_FIELD_VALID(unit, L3_IIFm, CLASS_IDf)) {
  13212         ing_intf_entry->intf_class = soc_mem_field32_get(unit, 
  13213                 mem, ing_entry_ptr, CLASS_IDf);
  13214     }
  13215 
  13216     /* Get vrf id value. */
  13217     if (SOC_MEM_FIELD_VALID(unit, L3_IIFm, VRFf)) {
  13218         ing_intf_entry->vrf = soc_mem_field32_get(unit, 
  13219                 mem, ing_entry_ptr, VRFf);
  13220     }
  13221 
  13222     /* Get Flags value. */
  13223     if (SOC_MEM_FIELD_VALID(unit, L3_IIFm, ALLOW_GLOBAL_ROUTEf)) {
  13224         if (1 == soc_mem_field32_get(unit, mem, ing_entry_ptr,
  13225                                      ALLOW_GLOBAL_ROUTEf)) {
  13226             ing_intf_entry->flags |= BCM_L3_INGRESS_GLOBAL_ROUTE;
  13227         }
  13228     }
  13229 
  13230 #ifdef BCM_TRIDENT2_SUPPORT
  13231     if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit)
  13232                                || SOC_IS_TRIDENT3X(unit)) {
  13233         /* Get l3 iif profile entry */
  13234         entries[0] = &l3_iif_profile;
  13235         index = soc_mem_field32_get(unit, L3_IIFm, (uint32 *)&entry,
  13236                                     L3_IIF_PROFILE_INDEXf);
  13237         if (_bcm_l3_iif_profile_entry_get(unit, index, 1, entries)
  13238                                                        != BCM_E_NONE) {
  13239             return BCM_E_FAIL;
  13240         }
  13241     }
  13242 #endif
  13243 
  13244     /* Get Trust QoS Map Id Value. */
  13245     if (soc_mem_field_valid(unit, L3_IIFm, TRUST_DSCP_PTRf)) {
  13246         hw_map_idx = soc_mem_field32_get(unit, mem, ing_entry_ptr,
  13247                                         TRUST_DSCP_PTRf);
  13248     }
  13249 #ifdef BCM_TRIDENT2_SUPPORT
  13250     if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit)
  13251                                || SOC_IS_TRIDENT3X(unit)) {
  13252         hw_map_idx = soc_mem_field32_get(unit, L3_IIF_PROFILEm,
  13253                                          &l3_iif_profile, TRUST_DSCP_PTRf);
  13254     }
  13255 #endif
  13256     if (hw_map_idx != 63) {
  13257          if (SOC_IS_TRIUMPH(unit) || SOC_IS_VALKYRIE(unit)) {
  13258               BCM_IF_ERROR_RETURN
  13259                    (_bcm_tr_qos_idx2id(unit, hw_map_idx, 0x3,
  13260                         &ing_intf_entry->qos_map_id));
  13261          } else {
  13262 #ifdef BCM_TRIUMPH2_SUPPORT
  13263               BCM_IF_ERROR_RETURN
  13264                    (_bcm_tr2_qos_idx2id(unit, hw_map_idx, 0x3,
  13265                         &ing_intf_entry->qos_map_id));
  13266 #endif /*BCM_TRIUMPH2_SUPPORT*/
  13267          }
  13268          ing_intf_entry->flags |= BCM_L3_INGRESS_DSCP_TRUST;
  13269     }
  13270 
  13271 #ifdef BCM_TRIUMPH2_SUPPORT
  13272     if (soc_mem_field_valid(unit, mem, IPMC_L3_IIFf)) {
  13273          ing_intf_entry->ipmc_intf_id = soc_mem_field32_get(unit, mem,
  13274                                                                      ing_entry_ptr, IPMC_L3_IIFf);
  13275     }
  13276 #endif
  13277 
  13278 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_HURRICANE3_SUPPORT)
  13279     if (soc_mem_field_valid(unit, L3_IIFm, URPF_MODEf)) {
  13280          ing_intf_entry->urpf_mode = soc_mem_field32_get(unit, mem,
  13281                                                                 ing_entry_ptr, URPF_MODEf);
  13282     }
  13283 
  13284     if (soc_mem_field_valid(unit, L3_IIFm, URPF_DEFAULTROUTECHECKf)) {
  13285          if (1 == soc_mem_field32_get(unit, mem, ing_entry_ptr,
  13286                                        URPF_DEFAULTROUTECHECKf)) {
  13287               ing_intf_entry->flags |= BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK;
  13288          }
  13289     }
  13290 #endif  /* BCM_TRIDENT_SUPPORT || BCM_HURRICANE3_SUPPORT */
  13291 #ifdef BCM_TRIDENT2_SUPPORT
  13292     if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit)
  13293                                || SOC_IS_TRIDENT3X(unit)) {
  13294         if (SOC_MEM_FIELD_VALID(
  13295                 unit, L3_IIF_PROFILEm, URPF_DEFAULTROUTECHECKf)) {
  13296             if (1 == soc_mem_field32_get(unit, L3_IIF_PROFILEm,
  13297                         &l3_iif_profile, URPF_DEFAULTROUTECHECKf)) {
  13298                 ing_intf_entry->flags |=
  13299                     BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK;
  13300             }
  13301         }
  13302     }
  13303 #endif
  13304 #ifdef BCM_TOMAHAWK_SUPPORT
  13305     if (SOC_IS_TOMAHAWKX(unit)) {
  13306         if (soc_mem_field_valid(unit, L3_IIF_PROFILEm, IPMC_MISS_AS_L2MCf)) {
  13307             if (0 != soc_mem_field32_get(unit, L3_IIF_PROFILEm,
  13308                                          &l3_iif_profile,
  13309                                          IPMC_MISS_AS_L2MCf)) {
  13310                 ing_intf_entry->flags |= BCM_L3_INGRESS_UNKNOWN_IPMC_AS_L2MC;
  13311             }
  13312         }
  13313     }
  13314 #endif
  13315 
  13316     return BCM_E_NONE;
  13317 }
  13318 
  13319 /*
  13320  * Function:
  13321  *      _bcm_xgs3_ing_intf_update_match
  13322  * Purpose:
  13323  *      Update/Show/Delete all entries in L3_IIF table matching a certain rule.
  13324  * Parameters:
  13325  *      unit     - (IN)SOC unit number.
  13326  *      trv_data - (IN)Delete pattern + compare,act,notify routines.
  13327  * Returns:
  13328  *      BCM_E_XXX
  13329  */
  13330 STATIC int
  13331 _bcm_xgs3_ing_intf_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data)
  13332 {
  13333     bcm_l3_ingress_t  ing_intf_entry;     /* Next hop entry info.           */
  13334     uint32 *ing_entry_ptr;        /* Ingress L3-IIF Table entry pointer.*/
  13335     char *ing_tbl_ptr;            /* Dma table pointer.             */
  13336     int cmp_result;               /* Test routine result.           */
  13337     soc_mem_t mem;                /* Next hop memory.               */
  13338     int idx,start_iif;                      /* Iteration index.               */
  13339     int rv = BCM_E_NONE;          /* Operation return status.       */
  13340 
  13341     /* Get L3-IIF Table memory. */
  13342     mem = BCM_XGS3_L3_MEM(unit, ing_intf);
  13343 
  13344     L3_ING_IF_MIN(unit, start_iif);
  13345 
  13346     /* Table DMA the L3-IIF table to software copy */
  13347     BCM_IF_ERROR_RETURN
  13348         (bcm_xgs3_l3_tbl_dma(unit, mem, BCM_XGS3_L3_ENT_SZ(unit, ing_intf), "ing_intf_tbl",
  13349                              &ing_tbl_ptr, NULL));
  13350 
  13351     for (idx = start_iif; idx < BCM_XGS3_L3_ING_IF_TBL_SIZE(unit); idx++) {
  13352         /* Skip unused entries. */
  13353         if (0 == SHR_BITGET(BCM_XGS3_L3_ING_IF_INUSE(unit), idx)) {
  13354             continue;
  13355         }
  13356 
  13357         /* Calculate entry ofset. */
  13358         ing_entry_ptr =
  13359             soc_mem_table_idx_to_pointer(unit, mem, uint32 *, ing_tbl_ptr, idx);
  13360 
  13361         (void) _bcm_xgs3_ing_intf_entry_parse(unit, ing_entry_ptr, &ing_intf_entry);
  13362 
  13363         /* Execute operation routine if any. */
  13364         if (trv_data->op_cb) {
  13365             rv = (*trv_data->op_cb)(unit, (void *)trv_data,
  13366                                     (void *)&ing_intf_entry,(void *)&idx, &cmp_result);
  13367             if (rv < 0) {
  13368 #ifdef BCM_CB_ABORT_ON_ERR
  13369                 if (SOC_CB_ABORT_ON_ERR(unit)) {
  13370                     break;
  13371                 }
  13372 #endif
  13373             }
  13374         }
  13375     }
  13376     soc_cm_sfree(unit, ing_tbl_ptr);
  13377     return (rv);
  13378 }
  13379 
  13380 #endif /*BCM_TRIUMPH_SUPPORT*/
  13381 
  13382 /*
  13383  * Function:
  13384  *      bcm_xgs3_l3_egress_id_parse
  13385  * Purpose:
  13386  *      Parse Egress object, to return flag and next hop / ecmp group id.
  13387  * Parameters:
  13388  *      unit       - (IN)  bcm device.
  13389  *      intf       - (IN)  Interface id pointing to egress object or
  13390  *                         multipath egress object.
  13391  *      flags      - (OUT) BCM_L3_MULTIPATH if interface points to multipath
  13392  *                         egress object.
  13393  *      nh_ecmp_id - (OUT) Next hop /ecmp group id.
  13394  * Returns:
  13395  *      BCM_E_DISABLED - if advanced egress switching disabled.
  13396  *      BCM_E_PARAM    - if invalid interface id passed.
  13397  *      BCM_E_NONE     - otherwise.
  13398  */
  13399 int
  13400 bcm_xgs3_l3_egress_id_parse(int unit, bcm_if_t intf,
  13401                             uint32 *flags, int *nh_ecmp_id)
  13402 {
  13403     /* Check if L3 feature is supported on the device */
  13404     if (!soc_feature(unit, soc_feature_l3)) {
  13405         return (BCM_E_UNAVAIL);
  13406     }
  13407 
  13408     /*  Make sure module was initialized. */
  13409     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  13410         return (BCM_E_INIT);
  13411     }
  13412 
  13413     /* Check l3 switching mode. */
  13414     if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) {
  13415         return (BCM_E_DISABLED);
  13416     }
  13417 
  13418     /* Input parameters check. */
  13419     if ((NULL == flags) || (NULL == nh_ecmp_id)) {
  13420         return (BCM_E_PARAM);
  13421     }
  13422 
  13423     if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) {
  13424         *nh_ecmp_id = intf - BCM_XGS3_EGRESS_IDX_MIN(unit);
  13425         /* Make sure next hop is in use. */
  13426         if (!BCM_XGS3_L3_ENT_REF_CNT
  13427               (BCM_XGS3_L3_TBL_PTR(unit, next_hop), *nh_ecmp_id)) {
  13428                    return (BCM_E_PARAM);
  13429         }
  13430         *flags = 0;
  13431     } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) {
  13432         *nh_ecmp_id = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  13433         /* Make sure next hop is in use. */
  13434         if (!BCM_XGS3_L3_ENT_REF_CNT
  13435               (BCM_XGS3_L3_TBL_PTR(unit, next_hop), *nh_ecmp_id)) {
  13436                    return (BCM_E_PARAM);
  13437         }
  13438         *flags = 0;
  13439     } else if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf)) {
  13440         *nh_ecmp_id = intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  13441         /* Make sure ecmp grp is in use. */
  13442 #ifdef BCM_TOMAHAWK3_SUPPORT
  13443         if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) &&
  13444             (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  13445                                   ecmp_mode_hierarchical) &&
  13446             (*nh_ecmp_id < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) {
  13447              if (!BCM_XGS3_L3_ENT_REF_CNT
  13448                   (BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp), *nh_ecmp_id)) {
  13449                        return (BCM_E_PARAM);
  13450              }
  13451 
  13452         } else
  13453 #endif
  13454         if (!BCM_XGS3_L3_ENT_REF_CNT
  13455               (BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), *nh_ecmp_id)) {
  13456                    return (BCM_E_PARAM);
  13457         }
  13458         *flags = BCM_L3_MULTIPATH;
  13459     } else {
  13460         return (BCM_E_PARAM);
  13461     }
  13462 
  13463     return (BCM_E_NONE);
  13464 }
  13465 
  13466 /*
  13467  * Function:
  13468  *      _bcm_xgs3_l3_egress_to_nh_info
  13469  * Purpose:
  13470  *      Map API egress object data to hw used next hop format.
  13471  * Parameters:
  13472  *      unit       - (IN)     bcm device.
  13473  *      egr        - (IN)     Egress object properties to match.
  13474  *      nh_info    - (IN/OUT) L3 interface id pointing to egress object
  13475  * Returns:
  13476  *      BCM_E_XXX.
  13477  */
  13478 STATIC int
  13479 _bcm_xgs3_l3_egress_to_nh_info(int unit, bcm_l3_egress_t *egr,
  13480                                bcm_l3_egress_t *nh_info)
  13481 {
  13482 #ifdef BCM_FIREBOLT_SUPPORT
  13483     _bcm_l3_intf_cfg_t l3_intf;     /* Outgoing interface info. */
  13484     int interface_map_mode=0;
  13485     int rv;
  13486 #endif /* BCM_FIREBOLT_SUPPORT  */
  13487 
  13488 #ifdef BCM_TRIUMPH_SUPPORT
  13489     if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
  13490          /* Check L3 Ingress Interface Map mode. */
  13491         BCM_IF_ERROR_RETURN (bcm_xgs3_l3_ingress_intf_map_get(unit, &interface_map_mode));
  13492     }
  13493 #endif /* BCM_TRIUMPH_SUPPORT */
  13494 
  13495 
  13496     /* Copy user info to local structure to preserve user structure. */
  13497     *nh_info = *egr;
  13498 
  13499     /* If trap to cpu required overwrite mac/module/intf/port. */
  13500     if (nh_info->flags & BCM_L3_L2TOCPU) {
  13501         /* Set module id to a local module. */
  13502         BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &nh_info->module));
  13503 
  13504         /* Set port to be a cpu port. */
  13505         nh_info->port = CMIC_PORT(unit);
  13506 
  13507         /* Set interface to be cpu interface. */
  13508         nh_info->intf = BCM_XGS3_L3_L2CPU_INTF_IDX(unit);
  13509     }
  13510 #ifdef BCM_FIREBOLT_SUPPORT
  13511     /* Firebolt devices need interface info to fill vid & tunnel next hop. */
  13512     else if (SOC_IS_FBX(unit)) {
  13513         /* Read interface information. */
  13514         /* Verify interface index range. */
  13515         if ((nh_info->intf != BCM_XGS3_L3_L2CPU_INTF_IDX(unit)) &&
  13516              (nh_info->intf != BCM_IF_INVALID)) {
  13517             if (nh_info->intf >= BCM_XGS3_L3_IF_TBL_SIZE(unit)) {
  13518                 return (BCM_E_PARAM);
  13519             }
  13520             sal_memset(&l3_intf, 0, sizeof(_bcm_l3_intf_cfg_t));
  13521             BCM_XGS3_L3_INTF_IDX_SET(l3_intf, nh_info->intf);
  13522             BCM_XGS3_L3_MODULE_LOCK(unit);
  13523             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, &l3_intf);
  13524             BCM_XGS3_L3_MODULE_UNLOCK(unit);
  13525             if (rv >= 0) {
  13526                 if (interface_map_mode) {
  13527                     nh_info->vlan = egr->vlan;
  13528                 } else {
  13529                     /* Set vid to next hop entry. */
  13530                     nh_info->vlan = l3_intf.l3i_vid;
  13531                     if (!BCM_VLAN_VALID(nh_info->vlan)) {
  13532                          return (BCM_E_CONFIG);
  13533                     }
  13534                 }
  13535             }
  13536         }else {
  13537            /* Set as Internally configured interface */
  13538            nh_info->intf = BCM_XGS3_L3_L2CPU_INTF_IDX(unit);
  13539            nh_info->vlan = 0;
  13540         }
  13541     }
  13542 #endif /* BCM_FIREBOLT_SUPPORT  */
  13543 
  13544 #if defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_GREYHOUND_SUPPORT)
  13545     if (nh_info->flags & BCM_L3_IPMC) {
  13546         if (!soc_feature(unit, soc_feature_repl_l3_intf_use_next_hop) &&
  13547                 !soc_feature(unit, soc_feature_l3mc_use_egress_next_hop)) {
  13548             return BCM_E_UNAVAIL;
  13549         }
  13550     }
  13551 #endif /* BCM_TRIUMPH3_SUPPORT */
  13552 
  13553     if ((nh_info->flags2 & BCM_L3_FLAGS2_UNDERLAY) && (nh_info->flags & BCM_L3_IPMC)) {
  13554         if (BCM_GPORT_IS_VXLAN_PORT(egr->port)) {
  13555             nh_info->port = 0;
  13556         }
  13557     }
  13558 
  13559     return (BCM_E_NONE);
  13560 }
  13561 
  13562 #ifdef BCM_TRIDENT_SUPPORT
  13563 /*
  13564  * Function:
  13565  *      _bcm_xgs3_trunk_replace_check
  13566  * Purpose:
  13567  *      Store old trunk-id in replace operation to reset the next hop store
  13568  * Parameters:
  13569  *      unit       - (IN)     bcm device.
  13570  *      flag       - (IN) L3 egress flags
  13571  *      egr_nh_old - (IN) Pointer to L3 Egress object.
  13572  *      trunk_id_in_use    - (OUT) used-trunk-id in replace operation
  13573  * Returns:
  13574  *      BCM_E_XXX.
  13575  */
  13576 STATIC int
  13577 _bcm_xgs3_trunk_replace_check(int unit, uint32 flags,
  13578                               bcm_l3_egress_t* egr_nh_old,
  13579                               bcm_trunk_t *trunk_id_in_use)
  13580 {
  13581 
  13582     if (( soc_feature(unit, soc_feature_trill) && (flags & BCM_L3_TRILL_ONLY)) ||
  13583         ( soc_feature(unit, soc_feature_l2gre) && (flags & BCM_L3_L2GRE_ONLY)) ||
  13584         ( soc_feature(unit, soc_feature_vxlan) && (flags & BCM_L3_VXLAN_ONLY)) ) {
  13585 
  13586         if (egr_nh_old == NULL) {
  13587             return BCM_E_INTERNAL;
  13588         }
  13589         /* Check if we are replacing a trunk destination */
  13590         if (BCM_L3_TGID & egr_nh_old->flags) {
  13591             *trunk_id_in_use = egr_nh_old->trunk;
  13592         }
  13593     }
  13594     return BCM_E_NONE;
  13595 }
  13596 
  13597 /*
  13598  * Function:
  13599  *      _bcm_xgs3_trunk_update_check
  13600  * Purpose:
  13601  *      Update used-trunk-id member-ports in replace operation to update  the next hop store
  13602  * Parameters:
  13603  *      unit       - (IN)     bcm device.
  13604  *      nh_info  - (IN) L3 Egress_object
  13605  *      tid_in_use    - (IN) used-trunk-id in replace operation
  13606  *      index  - (IN) Next hop index.
  13607  * Returns:
  13608  *      BCM_E_XXX.
  13609  */
  13610 STATIC int
  13611 _bcm_xgs3_trunk_update_check(int unit, bcm_l3_egress_t *nh_info, bcm_trunk_t tid_in_use, int index)
  13612 {
  13613 
  13614      /* For a replace operation where Trunk id is replaced,
  13615       * de-link the old trunk id from the next hop store.
  13616       */
  13617      if (tid_in_use != -1) {
  13618          /* if the destination is trunk then replacing tid
  13619           * should be different from replaced tid
  13620           */
  13621          if (BCM_L3_TGID & nh_info->flags) {
  13622              if (tid_in_use != nh_info->port) {
  13623                  BCM_IF_ERROR_RETURN(_bcm_xgs3_trunk_nh_store_unmap(unit, tid_in_use, index));
  13624              }
  13625          } else {
  13626              BCM_IF_ERROR_RETURN(_bcm_xgs3_trunk_nh_store_unmap(unit, tid_in_use, index));
  13627          }
  13628      }
  13629     return BCM_E_NONE;
  13630 }
  13631 
  13632 /*
  13633  * Function:
  13634  *      _bcm_xgs3_l3_egress_nhi_mapping_store
  13635  * Purpose:
  13636  *      Store old trunk/module-id/port-id in replace operation
  13637  *      to reset the nhi mapping store
  13638  * Parameters:
  13639  *      unit   - (IN)  bcm device
  13640  *      intf   - (IN)  L3 interface id pointing to Egress object
  13641  *      tgid   - (OUT) used-trunk-id
  13642  *      modid  - (OUT) used-mod-id
  13643  *      portid - (OUT) used-port-id
  13644  * Returns:
  13645  *      BCM_E_XXX.
  13646  */
  13647 STATIC int
  13648 _bcm_xgs3_l3_egress_nhi_mapping_store(int unit, uint32 flags, 
  13649                                       bcm_if_t intf, bcm_trunk_t *tgid,
  13650                                       bcm_module_t *modid, bcm_port_t *portid)
  13651 {
  13652     bcm_l3_egress_t egr_nh_old;
  13653     int rv = BCM_E_NONE;
  13654 
  13655     rv = bcm_xgs3_l3_egress_get(unit, intf, &egr_nh_old);
  13656     if (BCM_SUCCESS(rv)) {
  13657         /* Only for Unicast Next-hops */
  13658         if (!(egr_nh_old.flags & BCM_L3_IPMC) && 
  13659             ((egr_nh_old.flags & BCM_L3_VXLAN_ONLY)||
  13660             (egr_nh_old.flags & BCM_L3_TRILL_ONLY) ||
  13661             (egr_nh_old.flags & BCM_L3_L2GRE_ONLY))) {
  13662             *modid = egr_nh_old.module;
  13663             *portid = egr_nh_old.port;
  13664  
  13665             if (egr_nh_old.flags & BCM_L3_TGID) {
  13666                 *tgid = egr_nh_old.trunk;
  13667             }
  13668         }
  13669     }
  13670 
  13671     return BCM_E_NONE;
  13672 }
  13673 
  13674 /*
  13675  * Function:
  13676  *     _bcm_xgs3_l3_egress_nhi_mapping_reset
  13677  * Purpose:
  13678  *     Reset NHI mappping store entry
  13679  * Parameters:
  13680  *     unit       - (IN) bcm device.
  13681  *     nh_index   - (IN) nexthop index
  13682  *     old_tgid   - (IN) trunk id
  13683  *     old_modid  - (IN) module id
  13684  *     old_portid - (IN) port id
  13685  *     flags      - (IN) flag information
  13686  * Returns:
  13687  *     BCM_E_XXX
  13688  */
  13689 STATIC int
  13690 _bcm_xgs3_l3_egress_nhi_mapping_reset(int unit, int nh_index, 
  13691                                       bcm_trunk_t old_tgid, 
  13692                                       bcm_module_t old_modid,
  13693                                       bcm_port_t old_portid,
  13694                                       uint32 flags)
  13695 {
  13696     ing_l3_next_hop_entry_t ing_nh;
  13697     int rv = BCM_E_NONE;
  13698     int is_local = 0;
  13699     bcm_port_t portid = 0;
  13700     bcm_trunk_t tgid = 0;
  13701     int num_ports = 0;
  13702     int idx = -1;
  13703     bcm_port_t local_ports[SOC_MAX_NUM_PORTS];
  13704     int modid = 0;
  13705     int gport = 0;
  13706 #if defined(BCM_TRIDENT2PLUS_SUPPORT)  || defined(BCM_TRIDENT3_SUPPORT)
  13707     bcm_trunk_member_t *tmp_member_gports_array = NULL;
  13708 #endif
  13709 
  13710     if (!(flags & BCM_L3_REPLACE)) {
  13711         /* Ingore if not replace action */
  13712        return BCM_E_NONE;
  13713     }
  13714 
  13715     BCM_IF_ERROR_RETURN(soc_mem_read(unit, ING_L3_NEXT_HOPm,
  13716         MEM_BLOCK_ANY, nh_index, &ing_nh));
  13717      if (soc_feature(unit, soc_feature_generic_dest)) {
  13718          uint32 dest_type = SOC_MEM_FIF_DEST_INVALID, dest = 0;
  13719          dest = soc_mem_field32_dest_get(unit, ING_L3_NEXT_HOPm, &ing_nh,
  13720                                          DESTINATIONf, &dest_type);
  13721          portid = (dest & SOC_MEM_FIF_DGPP_TGID_MASK);
  13722          if (dest_type == SOC_MEM_FIF_DEST_LAG) {
  13723              tgid = (dest & SOC_MEM_FIF_DGPP_TGID_MASK);
  13724          } else if (dest_type == SOC_MEM_FIF_DEST_DGPP) {
  13725              modid = (dest & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >>
  13726                       SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS;
  13727          }
  13728      } else {
  13729 #ifdef BCM_TOMAHAWK3_SUPPORT
  13730          if (soc_feature(unit, soc_feature_th3_style_dlb)) {
  13731              modid = 0;
  13732          } else
  13733 #endif
  13734          {
  13735              modid = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, &ing_nh, MODULE_IDf);
  13736          }
  13737      }
  13738      if (old_tgid != -1) {
  13739          if (!soc_feature(unit, soc_feature_generic_dest)) {
  13740              if (soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, &ing_nh, Tf)) {
  13741                  tgid = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm,
  13742                                             &ing_nh, TGIDf);
  13743              }
  13744          }
  13745 
  13746          if (old_tgid != tgid) {
  13747 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  13748             rv = bcm_esw_trunk_get(unit, old_tgid, NULL, 0, NULL, &num_ports);
  13749             if (BCM_FAILURE(rv)) {
  13750                 return BCM_E_PORT;
  13751             }
  13752             if (num_ports == 0) {
  13753                 return BCM_E_NONE;
  13754             }
  13755 
  13756             if(soc_feature(unit, soc_feature_egr_modport_to_nhi)) {
  13757                 tmp_member_gports_array = sal_alloc(
  13758                     sizeof(bcm_trunk_member_t) * num_ports, "tmp_member_gports_arry");
  13759                 if (tmp_member_gports_array == NULL) {
  13760                     return BCM_E_MEMORY;
  13761                 }
  13762                 sal_memset(tmp_member_gports_array, 0,
  13763                     sizeof(bcm_trunk_member_t) * num_ports);
  13764                 rv = bcm_esw_trunk_get(unit, old_tgid, NULL,
  13765                          num_ports, tmp_member_gports_array, &num_ports);
  13766                 if (BCM_FAILURE(rv)) {
  13767                     goto clean_up;
  13768                 }
  13769             } else
  13770 #endif
  13771             {
  13772                 BCM_IF_ERROR_RETURN(_bcm_esw_trunk_local_members_get(unit, old_tgid,
  13773                     SOC_MAX_NUM_PORTS, local_ports, &num_ports));
  13774             }
  13775        }
  13776     } else if (old_portid != -1) {
  13777         BCM_IF_ERROR_RETURN
  13778             (_bcm_esw_modid_is_local(unit, old_modid, &is_local));
  13779         if (!is_local) {
  13780             if (!soc_feature(unit, soc_feature_egr_modport_to_nhi)) {
  13781                 /* Ignore EGR_PORT_TO_NHI_MAPPINGs */
  13782                 return BCM_E_NONE;
  13783             }
  13784         }
  13785 
  13786         if (!soc_feature(unit, soc_feature_generic_dest)) {
  13787             portid = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm,
  13788                                          &ing_nh, PORT_NUMf);
  13789         }
  13790         if ((old_portid != portid) || (old_modid != modid)) {
  13791 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  13792             if(soc_feature(unit, soc_feature_egr_modport_to_nhi)) {
  13793                 /* Alloc one trunk member size memory */
  13794                 tmp_member_gports_array = sal_alloc(
  13795                     sizeof(bcm_trunk_member_t), "tmp_member_gports_arry");
  13796                 if (tmp_member_gports_array == NULL) {
  13797                     return BCM_E_MEMORY;
  13798                 }
  13799                 sal_memset(tmp_member_gports_array, 0,
  13800                            sizeof(bcm_trunk_member_t));
  13801                 BCM_GPORT_MODPORT_SET(gport, old_modid, old_portid);
  13802                 tmp_member_gports_array[num_ports++].gport = gport;
  13803             } else
  13804 #endif
  13805             {
  13806                 local_ports[num_ports++] = old_portid;
  13807             }
  13808         }
  13809     }
  13810 
  13811     for (idx = 0; idx < num_ports; idx++) {
  13812 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
  13813         if(soc_feature(unit, soc_feature_egr_modport_to_nhi)) {
  13814             gport = tmp_member_gports_array[idx].gport;
  13815         } else
  13816 #endif
  13817         {
  13818             BCM_GPORT_MODPORT_SET(gport, old_modid, local_ports[idx]);
  13819         }
  13820 
  13821         rv = _bcm_trx_gport_to_nhi_set(unit, gport, 0);
  13822         if (BCM_FAILURE(rv)) {
  13823             goto clean_up;
  13824         }
  13825     }
  13826 
  13827 clean_up:
  13828 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
  13829     if (NULL != tmp_member_gports_array) {
  13830         sal_free(tmp_member_gports_array);
  13831     }
  13832 #endif
  13833 
  13834     return rv;
  13835 }
  13836 #endif /* BCM_TRIDENT_SUPPORT */
  13837 
  13838 /*
  13839  * Function:
  13840  *      bcm_xgs3_l3_egress_create
  13841  * Purpose:
  13842  *      Create an Egress forwarding object.
  13843  * Parameters:
  13844  *      unit    - (IN)  bcm device.
  13845  *      flags   - (IN)  BCM_L3_REPLACE: replace existing.
  13846  *                      BCM_L3_WITH_ID: intf argument is given.
  13847  *      egr     - (IN) Egress forwarding destination.
  13848  *      intf    - (OUT) L3 interface id pointing to Egress object.
  13849  *                      This is an IN argument if either BCM_L3_REPLACE
  13850  *                      or BCM_L3_WITH_ID are given in flags.
  13851  * Returns:
  13852  *      BCM_E_XXX
  13853  */
  13854 int
  13855 bcm_xgs3_l3_egress_create(int unit, uint32 flags, bcm_l3_egress_t *egr,
  13856                           bcm_if_t *intf)
  13857 {
  13858     int err_code = BCM_E_NONE;      /* Used for cleanup.   */
  13859     int index = -1;                 /* Next hop index.     */
  13860     bcm_l3_egress_t   nh_info;      /* Next hop entry.     */
  13861     uint32  shr_flags;              /* Table shared flags. */
  13862 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT)
  13863     uint32  entry_type=0;              /* Next Hop Entry_type */
  13864 #endif /* BCM_TRIUMPH_SUPPORT  && BCM_MPLS_SUPPORT */
  13865 #if defined(BCM_TRIUMPH2_SUPPORT)
  13866     uint32 protection_flags=0;
  13867     uint32 old_l3_payload = 0xffffffff;
  13868 #endif /* BCM_TRIUMPH2_SUPPORT */
  13869 #if defined(BCM_TRIDENT_SUPPORT)
  13870     int rv;
  13871     bcm_trunk_t tid_in_use = -1;
  13872     bcm_trunk_t tgid = -1;
  13873     bcm_module_t modid = -1; 
  13874     bcm_port_t portid = -1; 
  13875     bcm_l3_egress_t egr_nh_old, *p_egr_nh_old = NULL;
  13876 #endif /* BCM_TRIDENT_SUPPORT */
  13877     int egress_obj_update = 0;
  13878 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_TRIUMPH2_SUPPORT)
  13879     int overlay_nh = FALSE;
  13880 #endif
  13881     int entry_flag = 0;
  13882 
  13883     /*  Make sure module was initialized. */
  13884     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  13885         return (BCM_E_INIT);
  13886     }
  13887 
  13888     /* Check l3 switching mode. */
  13889     if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) {
  13890         return (BCM_E_DISABLED);
  13891     }
  13892 
  13893     /* Input parameters check. */
  13894     if ((NULL == egr) || (NULL == intf)) {
  13895         return (BCM_E_PARAM);
  13896     }
  13897 
  13898     /* Flags check */
  13899     if ((!soc_feature(unit, soc_feature_trill)) &&
  13900         (egr->flags & BCM_L3_TRILL_ONLY)) {
  13901         return (BCM_E_PARAM);
  13902     }
  13903 
  13904     if (!(soc_feature(unit, soc_feature_vxlan) ||
  13905         soc_feature(unit, soc_feature_vxlan_lite)) &&
  13906         (egr->flags & BCM_L3_VXLAN_ONLY)) {
  13907         return (BCM_E_PARAM);
  13908     }
  13909 
  13910     if ((!soc_feature(unit, soc_feature_l2gre)) &&
  13911         (egr->flags & BCM_L3_L2GRE_ONLY)) {
  13912         return (BCM_E_PARAM);
  13913     }
  13914 
  13915 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
  13916     if ((!soc_feature(unit, soc_feature_flex_flow)) &&
  13917         (egr->flags2 & BCM_L3_FLOW_ONLY)) {
  13918         return (BCM_E_PARAM);
  13919     }
  13920 
  13921     if ((!soc_feature(unit, soc_feature_flex_flow)) &&
  13922         (egr->flags2 & BCM_L3_MPLS_GRE_LABEL)) {
  13923         return (BCM_E_PARAM);
  13924     }
  13925 #endif
  13926 
  13927 #if defined(BCM_TRIDENT3_SUPPORT)
  13928     if (soc_feature(unit, soc_feature_flex_flow) &&
  13929         (egr->flow_handle != 0) &&
  13930         ((egr->flags2 & BCM_L3_FLAGS2_FIELD_ONLY) ||
  13931          (egr->flags2 & BCM_L3_FLAGS2_SRC_DST_MAC_SWAP) ||
  13932          (egr->flags & BCM_L3_ROUTE_LABEL))) {
  13933         return (BCM_E_PARAM);
  13934     }
  13935 
  13936     if (soc_feature(unit, soc_feature_large_scale_nat)) {
  13937         if (egr->replication_id < 0 ||
  13938             egr->replication_id > 0xffff) {
  13939             return (BCM_E_PARAM);
  13940         }
  13941     }
  13942 #endif
  13943 
  13944     if ((!soc_feature(unit, soc_feature_nh_for_ifp_actions)) && 
  13945         (egr->flags2 & BCM_L3_FLAGS2_FIELD_ONLY)) {
  13946         return (BCM_E_UNAVAIL);
  13947     }
  13948 
  13949     if ((!soc_feature(unit, soc_feature_fcoe)) &&
  13950         (egr->flags2 & BCM_L3_FLAGS2_FCOE_ONLY)) {
  13951         return (BCM_E_UNAVAIL);
  13952     }
  13953 
  13954     if ((!soc_feature(unit, soc_feature_nh_ifp_action_src_dst_mac_swap)) &&
  13955         (egr->flags2 & BCM_L3_FLAGS2_SRC_DST_MAC_SWAP)) {
  13956         return (BCM_E_UNAVAIL);
  13957     }
  13958 
  13959     if ((!soc_feature(unit, soc_feature_th_nh_no_overlap_ecmp)) &&
  13960         (egr->flags2 & BCM_L3_FLAGS2_NO_ECMP_OVERLAP)) {
  13961         return (BCM_E_UNAVAIL);
  13962     }
  13963 
  13964 #if defined(BCM_TOMAHAWK_SUPPORT)
  13965     if ((egr->flags2 & BCM_L3_FLAGS2_NO_ECMP_OVERLAP) &&
  13966         (flags & BCM_L3_WITH_ID)) {
  13967         return (BCM_E_PARAM);
  13968     }
  13969 #endif /* BCM_TOMAHAWK_SUPPORT */
  13970 
  13971 
  13972 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
  13973     /* For IFP_ACTIONS view only */
  13974     if ((!(egr->flags2 & BCM_L3_FLAGS2_FIELD_ONLY)) &&
  13975         (egr->flags2 & BCM_L3_FLAGS2_SRC_DST_MAC_SWAP)) {
  13976         return (BCM_E_PARAM);
  13977     }
  13978 
  13979     /* BCM_L3_FLAGS2_SRC_DST_MAC_SWAP must not be used together
  13980        with BCM_L3_KEEP_SRCMAC or BCM_L3_KEEP_DSTMAC */
  13981     if ((egr->flags2 & BCM_L3_FLAGS2_SRC_DST_MAC_SWAP) &&
  13982         ((egr->flags & BCM_L3_KEEP_SRCMAC) ||
  13983         (egr->flags & BCM_L3_KEEP_DSTMAC))) {
  13984         return (BCM_E_PARAM);
  13985     }
  13986 #endif /* BCM_TRIDENT2PLUS_SUPPORT */
  13987 
  13988     if ((!soc_feature(unit, soc_feature_redirect_nh_to_ecmp_for_mpls_php)) &&
  13989         (egr->flags2 & BCM_L3_FLAGS2_MPLS_PHP)) {
  13990         return (BCM_E_PARAM);
  13991     }
  13992 
  13993     /* Verify egress object range if BCM_L3_WITH_ID flag is set. */
  13994     if (flags & BCM_L3_WITH_ID) {
  13995         if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, *intf) &&
  13996             !BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, *intf)) {
  13997              return (BCM_E_PARAM);
  13998         }
  13999         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, *intf)) {
  14000             index = *intf - BCM_XGS3_EGRESS_IDX_MIN(unit);
  14001         } else {
  14002             index = *intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  14003         }
  14004 
  14005 #ifdef BCM_TOMAHAWK3_SUPPORT
  14006         /* When Tomahawk3 Failover with fixed egress nh offset is enable,
  14007            egr->failover_id is used internally to distinguish between user
  14008            created primary intf (should be zero) and prot_intf created from
  14009            bcm_th3_failover_egress_set (should be _FAILOVER_FIXED_NH_OFFSET_ON) */
  14010         if (FAILOVER_INFO(unit)->prot_offset > 0) {
  14011             if (!_BCM_FAILOVER_ID_HAS_FIXED_NH_OFFSET(egr->failover_id) &&
  14012                 (index >= FAILOVER_INFO(unit)->prot_offset)) {
  14013                 return BCM_E_PARAM; /* primary nh index invalid */
  14014             }
  14015             /* Clear the bit after above check */
  14016             egr->failover_id &= ~_FAILOVER_FIXED_NH_OFFSET_ON;
  14017         }
  14018 #endif
  14019 
  14020     }
  14021 
  14022     bcm_l3_egress_t_init(&nh_info);
  14023     /* Convert api egress object to hw next hop entry format. */
  14024     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_egress_to_nh_info(unit, egr, &nh_info));
  14025 
  14026     /* Convert api flags to shared table management flags. */
  14027     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_flags_to_shr(flags, &shr_flags));
  14028 
  14029    /* Store api flags within egr object flags */
  14030     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_flags_to_egr_obj(flags, &nh_info));
  14031 
  14032     /* Disable matching entry lookup. */
  14033     shr_flags |= _BCM_L3_SHR_MATCH_DISABLE;
  14034 
  14035     if (!(egr->flags2 & BCM_L3_FLAGS2_UNDERLAY)) {
  14036 #ifdef BCM_RIOT_SUPPORT
  14037         if (BCMI_RIOT_IS_ENABLED(unit)
  14038             && (_bcm_vp_is_vfi_type(unit, nh_info.port) ||
  14039             _bcm_vp_lag_member_is_vfi_type(unit, nh_info.port))) {
  14040 
  14041             overlay_nh = TRUE;
  14042             shr_flags |= _BCM_L3_SHR_OVERLAY_OBJECT;
  14043         }
  14044 #endif
  14045     }
  14046 
  14047 #if defined(BCM_TRIDENT_SUPPORT)
  14048     /* Retrieve used-trunk-id in replace operation to reset the next hop store */
  14049     if (BCM_L3_REPLACE & flags) {
  14050         rv = bcm_xgs3_l3_egress_get(unit, *intf, &egr_nh_old);
  14051         if (BCM_SUCCESS(rv)) {
  14052             p_egr_nh_old = &egr_nh_old;
  14053             _bcm_xgs3_trunk_replace_check(unit, egr->flags,
  14054                                           p_egr_nh_old, &tid_in_use);
  14055             egress_obj_update = 1;
  14056         }
  14057     }
  14058 
  14059     if ((soc_feature(unit, soc_feature_vxlan) ||
  14060         soc_feature(unit, soc_feature_flex_flow) ||
  14061         soc_feature(unit, soc_feature_trill) ||
  14062         soc_feature(unit, soc_feature_l2gre)) && (!overlay_nh)) {
  14063         if (flags & BCM_L3_REPLACE) {
  14064             /* Retrieve old trunk/module-id/port-id in replace operation
  14065              * to reset the nhi mapping store
  14066              */
  14067             BCM_IF_ERROR_RETURN(
  14068                 _bcm_xgs3_l3_egress_nhi_mapping_store(unit, egr->flags,
  14069                      *intf, &tgid, &modid, &portid));
  14070         }
  14071     }
  14072 #endif /* BCM_TRIDENT_SUPPORT */
  14073 
  14074 #if defined(BCM_TOMAHAWK_SUPPORT)
  14075     if (soc_feature(unit, soc_feature_th_nh_no_overlap_ecmp) &&
  14076         (BCM_L3_FLAGS2_NO_ECMP_OVERLAP & egr->flags2)) {
  14077         shr_flags |= _BCM_L3_SHR_NO_ECMP_OVERLAP;
  14078     }
  14079 
  14080 #endif /* BCM_TOMAHAWK_SUPPORT */
  14081 
  14082 #if defined(BCM_TRIDENT3_SUPPORT)
  14083     if (soc_feature(unit, soc_feature_flex_flow) &&
  14084         nh_info.flow_handle != 0) {
  14085 
  14086         uint32 entry_width;
  14087 
  14088         BCM_IF_ERROR_RETURN(
  14089             _bcm_l3_get_flex_entry_width(unit, &nh_info, &entry_width));
  14090 
  14091         if (entry_width == _BCM_DOUBLE_WIDE) {
  14092             entry_flag = _BCM_L3_SHR_WIDE_FLEX_ENTRY;
  14093         }
  14094     }
  14095     if (soc_feature(unit, soc_feature_large_scale_nat) &&
  14096         flags & BCM_L3_REPLACE &&
  14097         flags & BCM_L3_WITH_ID) {
  14098         /* Release MAC_DA_PROFILE if used */
  14099         BCM_IF_ERROR_RETURN(
  14100             bcm_td3_ipmc_egr_nh_mac_da_profile_entry_delete(unit, index));
  14101     }
  14102 #endif /* BCM_TRIDENT3_SUPPORT */
  14103 
  14104     /* Create next hop entry. */
  14105     BCM_IF_ERROR_RETURN(bcm_xgs3_nh_add(unit, shr_flags, &nh_info, &index));
  14106 
  14107     /* Return Egress object id 100K + nh_index for regular L3 egress objects */
  14108     /* Return BCM_XGS3_DVP_EGRESS_IDX_MIN(unit) + nh_index for L3 egress objects on VP */
  14109 #ifdef BCM_TRIUMPH2_SUPPORT
  14110     if (((soc_feature(unit, soc_feature_wlan) ||
  14111          soc_feature(unit, soc_feature_virtual_port_routing)) &&
  14112         (egr->encap_id > 0 && egr->encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit))) ||
  14113         overlay_nh) {
  14114 
  14115         *intf = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit) + index;
  14116     } else
  14117 #endif
  14118     {
  14119         *intf = BCM_XGS3_EGRESS_IDX_MIN(unit) + index;
  14120     }
  14121 
  14122 #if defined(BCM_TRIDENT_SUPPORT)
  14123     if (soc_feature(unit, soc_feature_vxlan) ||
  14124         soc_feature(unit, soc_feature_flex_flow) ||
  14125         soc_feature(unit, soc_feature_trill) ||
  14126         soc_feature(unit, soc_feature_l2gre)) {
  14127         /* Reset nhi mapping store */
  14128         L3_IF_ERROR_CLEANUP(
  14129             _bcm_xgs3_l3_egress_nhi_mapping_reset(
  14130                 unit, index, tgid, modid, portid, flags));
  14131     }
  14132 
  14133     if ( soc_feature(unit, soc_feature_trill) && 
  14134         (egr->flags & BCM_L3_TRILL_ONLY) && (!overlay_nh)){
  14135        /* Update used-trunk-id member-ports in replace operation to update  the next hop store */
  14136        L3_IF_ERROR_CLEANUP
  14137           (_bcm_xgs3_trunk_update_check(unit, &nh_info, tid_in_use, index));
  14138        /* Set Trunk-Id to NextHop-Index Store entry for Unicast Next-hops  */
  14139        if ((egr->flags & BCM_L3_TGID) && (!(flags & BCM_L3_IPMC))) {
  14140              L3_IF_ERROR_CLEANUP(_bcm_xgs3_trunk_nh_store_set(unit, nh_info.port, index));
  14141        }
  14142        /* Configure TRILL NextHop */
  14143        L3_IF_ERROR_CLEANUP_ELSE_RETURN(bcm_td_trill_egress_set(unit, index, flags));
  14144     }
  14145 #endif /* BCM_TRIDENT_SUPPORT */
  14146 
  14147 #if defined(BCM_TRIUMPH3_SUPPORT)
  14148     if (soc_feature(unit, soc_feature_l2gre) && 
  14149         (egr->flags & BCM_L3_L2GRE_ONLY) && (!overlay_nh)){
  14150        /* Update used-trunk-id member-ports in replace operation to update  the next hop store */
  14151        L3_IF_ERROR_CLEANUP
  14152           (_bcm_xgs3_trunk_update_check(unit, &nh_info, tid_in_use, index));
  14153        /* Set Trunk-Id to NextHop-Index Store entry for Unicast Next-hops  */
  14154        if ((egr->flags & BCM_L3_TGID) && (!(flags & BCM_L3_IPMC))) {
  14155            L3_IF_ERROR_CLEANUP(_bcm_xgs3_trunk_nh_store_set(unit, nh_info.port, index));
  14156        }
  14157        /* Configure L2GRE NextHop */
  14158        L3_IF_ERROR_CLEANUP_ELSE_RETURN(bcm_tr3_l2gre_egress_set(unit, index, flags));
  14159     }
  14160 #endif /* BCM_TRIUMPH3_SUPPORT */
  14161 
  14162 #if defined(BCM_TRIDENT2_SUPPORT)
  14163     if ( soc_feature(unit, soc_feature_vxlan) && 
  14164         (egr->flags & BCM_L3_VXLAN_ONLY) && (!overlay_nh)){
  14165         int vp = 0;
  14166         int drop = 0;
  14167         _bcm_vp_info_t vp_info;
  14168 
  14169         if (BCM_GPORT_IS_VXLAN_PORT(egr->port)) {
  14170             vp = BCM_GPORT_VXLAN_PORT_ID_GET(egr->port);
  14171             L3_IF_ERROR_CLEANUP(_bcm_vp_info_get(unit, vp, &vp_info));
  14172             if (vp_info.vp_type != _bcmVpTypeVxlan) {
  14173                 L3_IF_ERROR_CLEANUP(BCM_E_PARAM); 
  14174             }
  14175         }
  14176 
  14177         if (egr->multicast_flags & BCM_L3_MULTICAST_L3_DROP) {
  14178             drop = 1;
  14179         }
  14180 
  14181        /* Update used-trunk-id member-ports in replace operation to update  the next hop store */
  14182        L3_IF_ERROR_CLEANUP
  14183           (_bcm_xgs3_trunk_update_check(unit, &nh_info, tid_in_use, index));
  14184        /* Set Trunk-Id to NextHop-Index Store entry for Unicast Next-hops */
  14185        if ((egr->flags & BCM_L3_TGID) && (!(flags & BCM_L3_IPMC))) {
  14186            L3_IF_ERROR_CLEANUP(_bcm_xgs3_trunk_nh_store_set(unit, nh_info.port, index));
  14187        }
  14188        /* Configure VXLAN NextHop */
  14189        L3_IF_ERROR_CLEANUP_ELSE_RETURN(bcm_td2_vxlan_next_hop_set(unit, index, flags, vp, drop));
  14190     }
  14191 #endif /* BCM_TRIDENT2_SUPPORT */
  14192 
  14193 #if defined(BCM_GREYHOUND2_SUPPORT)
  14194     if (soc_feature(unit, soc_feature_vxlan_lite) &&
  14195         (egr->flags & BCM_L3_VXLAN_ONLY)) {
  14196         if (flags & BCM_L3_REPLACE) {
  14197             BCM_IF_ERROR_RETURN(bcmi_gh2_vxlan_egress_entry_mac_replace(
  14198                                     unit, index, egr));
  14199         }
  14200         if (!overlay_nh) {
  14201             L3_IF_ERROR_CLEANUP_ELSE_RETURN(err_code);
  14202         }
  14203     }
  14204 #endif /* BCM_GREYHOUND2_SUPPORT */
  14205 
  14206 #if defined(BCM_TRIDENT3_SUPPORT)
  14207     if ((soc_feature(unit, soc_feature_flex_flow)) &&
  14208         (egr->flow_handle != 0) &&
  14209         (egr->flags2 & BCM_L3_MPLS_GRE_LABEL)) {
  14210 
  14211             BCM_IF_ERROR_RETURN(_bcm_td3_mpls_gre_label_add(unit, egr, index, flags));
  14212     }
  14213 
  14214     if (soc_feature(unit, soc_feature_flex_flow) &&
  14215         (egr->flags2 & BCM_L3_FLOW_ONLY) && (!overlay_nh)){
  14216         int vp = 0;
  14217         int drop = 0;
  14218         _bcm_vp_info_t vp_info;
  14219 
  14220         if ((egr->encap_id > 0) && (egr->encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit))) {
  14221             vp = egr->encap_id;
  14222         }
  14223 
  14224         if (BCM_GPORT_IS_FLOW_PORT(egr->port)) {
  14225             vp = BCM_GPORT_FLOW_PORT_ID_GET(egr->port);
  14226         }
  14227 
  14228         if (vp) {
  14229             L3_IF_ERROR_CLEANUP(_bcm_vp_info_get(unit, vp, &vp_info));
  14230             if (vp_info.vp_type != _bcmVpTypeFlow) {
  14231                 L3_IF_ERROR_CLEANUP(BCM_E_PARAM);
  14232             }
  14233         }
  14234 
  14235         if (egr->multicast_flags & BCM_L3_MULTICAST_L3_DROP) {
  14236             drop = 1;
  14237         }
  14238 
  14239        /* Update used-trunk-id member-ports in replace operation to update the next hop store */
  14240        L3_IF_ERROR_CLEANUP
  14241           (_bcm_xgs3_trunk_update_check(unit, &nh_info, tid_in_use, index));
  14242        /* Set Trunk-Id to NextHop-Index Store entry for Unicast Next-hops */
  14243        if ((egr->flags & BCM_L3_TGID) && (!(flags & BCM_L3_IPMC))) {
  14244            L3_IF_ERROR_CLEANUP(_bcm_xgs3_trunk_nh_store_set(unit, nh_info.port, index));
  14245        }
  14246        /* Configure FLOW NextHop */
  14247        L3_IF_ERROR_CLEANUP_ELSE_RETURN(_bcm_td3_flow_next_hop_set(unit, index, flags, vp, drop));
  14248     }
  14249 #endif /* BCM_TRIDENT3_SUPPORT */
  14250 
  14251 #ifdef BCM_TRIDENT_SUPPORT
  14252     if (soc_feature(unit, soc_feature_nh_for_ifp_actions) && 
  14253         (nh_info.flags2 & BCM_L3_FLAGS2_FIELD_ONLY)) {
  14254             egr_l3_next_hop_entry_t egr_nh;
  14255             uint32                  tag_buffer = 0;
  14256             uint8                   tag_action = 0;
  14257             BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm, 
  14258                                              MEM_BLOCK_ALL, index, &egr_nh));            
  14259 #ifdef BCM_TOMAHAWK3_SUPPORT
  14260             if (SOC_IS_TOMAHAWK3(unit)) {
  14261                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
  14262                                     nh_entry_type_field[unit], 2);
  14263             } else
  14264 #endif
  14265             {
  14266                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
  14267                                     nh_entry_type_field[unit], 6);
  14268             }
  14269             if (SOC_IS_TD2_TT2(unit)) {
  14270                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
  14271                                 IFP_ACTIONS__L3_UC_SA_DISABLEf,
  14272                                 ((nh_info.flags & BCM_L3_KEEP_SRCMAC)!=0));
  14273                 if (!SOC_IS_TOMAHAWK3(unit)) {
  14274                     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
  14275                                     L3__L3_UC_SA_DISABLEf, 0);
  14276                 }
  14277             }
  14278 
  14279             if (egr->vntag_action == bcmVnTagActionChange) {
  14280                tag_action = 1;
  14281                tag_buffer = (((uint32)egr->vntag.direction & 0x1) << 31) |
  14282                              (((uint32)egr->vntag.pointer & 0x1) << 30) |
  14283                              (((uint32)egr->vntag.dst_vif & 0x3fff) << 16)|
  14284                              (((uint32)egr->vntag.loop & 0x1) << 15) |
  14285                              ((uint32)egr->vntag.src_vif & 0xfff);
  14286             } else if (egr->etag_action == bcmETagActionChange) {
  14287                tag_action = 2;
  14288                tag_buffer = (((uint32)egr->etag.pcp & 0x7) << 29) |
  14289                              (((uint32)egr->etag.de & 0x1) << 28) |
  14290                              (((uint32)egr->etag.src_vid & 0xfff) << 16) |
  14291                              ((uint32)egr->etag.vid & 0x3fff);
  14292             } else if (egr->vntag_action == bcmVnTagActionDelete) {
  14293                 tag_action = 3;
  14294                 tag_buffer = 0;
  14295             } else if (egr->etag_action == bcmETagActionDelete) {
  14296                 tag_action = 3;
  14297                 tag_buffer = ~0;
  14298             }
  14299 
  14300             if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm,
  14301                                     IFP_ACTIONS__VNTAGf)) {
  14302                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
  14303                                     IFP_ACTIONS__VNTAGf, tag_buffer);
  14304             }
  14305 
  14306             if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm,
  14307                                     IFP_ACTIONS__VNTAG_ACTIONf)) {
  14308                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
  14309                                     IFP_ACTIONS__VNTAG_ACTIONf, tag_action);
  14310             }
  14311 
  14312             BCM_IF_ERROR_RETURN
  14313                 (soc_mem_write(unit, EGR_L3_NEXT_HOPm,
  14314                                MEM_BLOCK_ALL, index, &egr_nh));
  14315     }
  14316 #endif 
  14317 
  14318 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
  14319     if (soc_feature(unit, soc_feature_nh_ifp_action_src_dst_mac_swap) &&
  14320         (nh_info.flags2 & BCM_L3_FLAGS2_SRC_DST_MAC_SWAP)) {
  14321         egr_l3_next_hop_entry_t egr_nh;
  14322         BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm,
  14323                                          MEM_BLOCK_ALL, index, &egr_nh));
  14324         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
  14325                             IFP_ACTIONS__SWAP_MAC_DA_SAf, 1);
  14326         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
  14327                             IFP_ACTIONS__L3_UC_SA_DISABLEf, 1);
  14328         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
  14329                             IFP_ACTIONS__L3_UC_DA_DISABLEf, 1);
  14330         BCM_IF_ERROR_RETURN
  14331             (soc_mem_write(unit, EGR_L3_NEXT_HOPm,
  14332                            MEM_BLOCK_ALL, index, &egr_nh));
  14333     }
  14334 #endif /* BCM_TRIDENT2PLUS_SUPPORT */
  14335 
  14336 #if defined(BCM_TRIUMPH2_SUPPORT)
  14337     if (soc_feature(unit, soc_feature_failover)) {
  14338          if (BCM_SUCCESS(_bcm_esw_failover_egr_check (unit, egr))) {
  14339               if (_BCM_MULTICAST_IS_SET(egr->failover_mc_group)) {
  14340                    protection_flags |= _BCM_FAILOVER_1_PLUS_PROTECTION;
  14341               }
  14342               L3_IF_ERROR_CLEANUP(
  14343               _bcm_esw_failover_prot_nhi_create(unit, protection_flags, index,
  14344                   (uint32) (egr->failover_if_id - BCM_XGS3_EGRESS_IDX_MIN(unit)),
  14345                   egr->failover_mc_group, egr->failover_id));
  14346          } else if (flags & BCM_L3_REPLACE) {
  14347              /* Clean up prot_nhi if egress object is replaced by new one which
  14348               * has no failover information.
  14349               */
  14350              if ((0 == egr->failover_id) && (0 == egr->failover_if_id)) {
  14351                  if (SOC_IS_TRIUMPH3(unit) || SOC_IS_KATANA2(unit)) {
  14352                      if (0 == egr->failover_mc_group) {
  14353                          err_code =
  14354                              _bcm_esw_failover_prot_nhi_cleanup(unit, index);
  14355                      }
  14356                  } else {
  14357                      err_code =
  14358                          _bcm_esw_failover_prot_nhi_cleanup(unit, index);
  14359                  }
  14360                  if ((err_code != BCM_E_NOT_FOUND) &&
  14361                      (err_code != BCM_E_NONE)) {
  14362                      goto cleanup;
  14363                  }
  14364              }
  14365          }
  14366     }
  14367 #endif /* BCM_TRIUMPH2_SUPPORT  */
  14368 
  14369 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT)
  14370     if ((SOC_IS_TR_VL(unit)) && (soc_feature(unit, soc_feature_mpls))) {
  14371         /*
  14372          * BCM_L3_ROUTE_LABEL is an egress object flag. There was a
  14373          * bug in the code wherein bcm_l3_egress_create was looking
  14374          * for BCM_L3_ROUTE_LABEL in "flags" and get/destroy functions
  14375          * were looking in "egr->flags". This was causing MPLS actions
  14376          * to be modified during replace.
  14377          * Changing this check to egr->flags might affect customers who
  14378          * are passing BCM_L3_ROUTE_LABEL in "flags".
  14379          * Therefore, modifying code to check for BCM_L3_ROUTE_LABEL
  14380          * in flags as well as egr->flags.
  14381          */
  14382         if ((flags & BCM_L3_ROUTE_LABEL) ||
  14383                 (egr->flags & BCM_L3_ROUTE_LABEL)) {
  14384              if (egr->mpls_label != BCM_MPLS_LABEL_INVALID) {
  14385                   /* Case of PUSH Inner-Label */
  14386                   L3_IF_ERROR_CLEANUP(
  14387                        bcm_tr_mpls_get_entry_type(unit, index, &entry_type));
  14388                   if (entry_type == 0) {
  14389                        L3_IF_ERROR_CLEANUP(
  14390                             bcm_tr_mpls_egress_entry_modify(unit, index, 0, 1));
  14391                   }
  14392 #if defined(BCM_TOMAHAWK3_SUPPORT)
  14393                   if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
  14394                       L3_IF_ERROR_CLEANUP(
  14395                            bcm_th3_mpls_l3_label_add(unit, egr, index, flags));
  14396                   } else
  14397 #endif
  14398                   {
  14399                       L3_IF_ERROR_CLEANUP(
  14400                            bcm_tr_mpls_l3_label_add (unit, egr, index, flags));
  14401                   }
  14402               }
  14403 #if defined(BCM_TRIUMPH2_SUPPORT)
  14404               if (soc_feature(unit, soc_feature_mpls_failover)) {
  14405                   if ((protection_flags & _BCM_FAILOVER_1_PLUS_PROTECTION) && 
  14406                       soc_mem_field_valid(unit, EGR_IPMCm, L3_PAYLOADf)) {
  14407                       egr_ipmc_entry_t   egr_ipmc_entry;
  14408                       int l3mc_index = _BCM_MULTICAST_ID_GET(egr->failover_mc_group);
  14409                       L3_IF_ERROR_CLEANUP(soc_mem_read(unit, EGR_IPMCm, 
  14410                                                        MEM_BLOCK_ANY, l3mc_index, 
  14411                                                        &egr_ipmc_entry));
  14412                       old_l3_payload = soc_mem_field32_get(unit, EGR_IPMCm, &egr_ipmc_entry, 
  14413                                                            L3_PAYLOADf);
  14414                       soc_mem_field32_set(unit, EGR_IPMCm, &egr_ipmc_entry, 
  14415                                           L3_PAYLOADf,1);  
  14416                       L3_IF_ERROR_CLEANUP(soc_mem_write(unit, EGR_IPMCm,
  14417                                                         MEM_BLOCK_ALL, 
  14418                                                         l3mc_index, 
  14419                                                         &egr_ipmc_entry));
  14420                   }
  14421               }
  14422 #endif  
  14423         } else if (!((flags & BCM_L3_ROUTE_LABEL) ||
  14424                 (egr->flags & BCM_L3_ROUTE_LABEL))) {
  14425               if ((egr->mpls_label != BCM_MPLS_LABEL_INVALID) ||
  14426                   _BCM_MPLS_EGRESS_LABEL_PRESERVE(unit, egr->mpls_flags)) {
  14427                   /* Case of SWAP-OUT Label */
  14428                   L3_IF_ERROR_CLEANUP(
  14429                        bcm_tr_mpls_get_entry_type(unit, index, &entry_type));
  14430                   if (entry_type == 0) {
  14431                        L3_IF_ERROR_CLEANUP(
  14432                            bcm_tr_mpls_egress_entry_modify(unit, index, 0, 1));
  14433                   }
  14434 #if defined(BCM_TOMAHAWK3_SUPPORT)
  14435                   if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
  14436                       L3_IF_ERROR_CLEANUP(
  14437                                bcm_th3_mpls_swap_nh_info_add (unit, egr, index, flags));
  14438                   } else
  14439 #endif
  14440                   {
  14441 
  14442                       L3_IF_ERROR_CLEANUP(
  14443                                bcm_tr_mpls_swap_nh_info_add (unit, egr, index, flags));
  14444                   }
  14445               } else if (egr->mpls_label == BCM_MPLS_LABEL_INVALID ) {
  14446                   /* Case of Egress into MPLS Tunnel */
  14447                   L3_IF_ERROR_CLEANUP(
  14448                       bcm_tr_mpls_swap_nh_info_delete(unit, index));
  14449                   if (BCM_SUCCESS(bcm_tr_mpls_tunnel_intf_valid (unit, index))) {
  14450                        L3_IF_ERROR_CLEANUP(
  14451                             bcm_tr_mpls_get_entry_type(unit, index, &entry_type));
  14452                        if (entry_type == 0) {
  14453                             L3_IF_ERROR_CLEANUP(
  14454                                  bcm_tr_mpls_egress_entry_modify(unit, index,
  14455                                      0, 1));
  14456 #if defined(BCM_KATANA_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  14457                            if (soc_feature(unit, soc_feature_mpls_nh_ttl_control)) {
  14458                                if (egr->flags & BCM_L3_KEEP_TTL) {
  14459                                    egr_l3_next_hop_entry_t egr_nh;
  14460                                    BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm,
  14461                                                                     MEM_BLOCK_ALL, index, &egr_nh));
  14462                                    soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
  14463                                                        MPLS__DISABLE_TTL_DECREMENTf, 1);
  14464                                    BCM_IF_ERROR_RETURN
  14465                                        (soc_mem_write(unit, EGR_L3_NEXT_HOPm,
  14466                                                       MEM_BLOCK_ALL, index, &egr_nh));
  14467                                }
  14468                            }
  14469 #endif
  14470 #if defined(INCLUDE_XFLOW_MACSEC)
  14471                             if (soc_feature(unit, soc_feature_xflow_macsec) &&
  14472                                 ((egr->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_ENCRYPT) ||
  14473                                 (egr->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_DECRYPT))) {
  14474                                 egr_l3_next_hop_entry_t egr_nh;
  14475                                 BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm,
  14476                                                                 MEM_BLOCK_ALL, index, &egr_nh));
  14477                                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm,
  14478                                         &egr_nh, MPLS__MACSEC_ENCRYPTf, 0);
  14479                                     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm,
  14480                                             &egr_nh, MPLS__MACSEC_DECRYPTf, 0);
  14481                                 if (egr->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_ENCRYPT) {
  14482                                     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm,
  14483                                             &egr_nh, MPLS__MACSEC_ENCRYPTf, 0x1);
  14484                                 } else {
  14485                                     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm,
  14486                                             &egr_nh, MPLS__MACSEC_DECRYPTf, 0x1);
  14487                                 }
  14488                                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm,
  14489                                         &egr_nh, MPLS__HG_MC_DST_MODIDf, egr->module);
  14490                                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm,
  14491                                         &egr_nh, MPLS__HG_MC_DST_PORT_NUMf, egr->port);
  14492                                 BCM_IF_ERROR_RETURN
  14493                                     (soc_mem_write(unit, EGR_L3_NEXT_HOPm,
  14494                                                     MEM_BLOCK_ALL, index, &egr_nh));
  14495                             }
  14496 #endif
  14497                        }
  14498                   } else {
  14499                       L3_IF_ERROR_CLEANUP(
  14500                           bcm_tr_mpls_get_entry_type(unit, index, &entry_type));
  14501                       if (entry_type == 1) {  
  14502                           L3_IF_ERROR_CLEANUP(
  14503                               bcm_tr_mpls_egress_entry_modify(unit, index, 0, entry_type));
  14504                       }
  14505                   }
  14506 #if defined(BCM_TRIUMPH2_SUPPORT)
  14507                   if (soc_feature(unit, soc_feature_mpls_failover)) {
  14508                       if (soc_mem_field_valid(unit, EGR_IPMCm, L3_PAYLOADf)) {
  14509                           egr_ipmc_entry_t   egr_ipmc_entry;
  14510                           int l3mc_index = _BCM_MULTICAST_ID_GET(egr->failover_mc_group);
  14511                           L3_IF_ERROR_CLEANUP(soc_mem_read(unit, EGR_IPMCm, 
  14512                                                            MEM_BLOCK_ANY, l3mc_index, 
  14513                                                            &egr_ipmc_entry));
  14514                           old_l3_payload = soc_mem_field32_get(unit, EGR_IPMCm, &egr_ipmc_entry, 
  14515                                                                L3_PAYLOADf);
  14516                           soc_mem_field32_set(unit, EGR_IPMCm, &egr_ipmc_entry, 
  14517                                               L3_PAYLOADf,0);  
  14518                           L3_IF_ERROR_CLEANUP(soc_mem_write(unit, EGR_IPMCm,
  14519                                                             MEM_BLOCK_ALL, 
  14520                                                             l3mc_index, 
  14521                                                             &egr_ipmc_entry));
  14522                       }
  14523                   }
  14524 #endif   
  14525               }
  14526         }
  14527         if (flags & BCM_L3_REPLACE) {
  14528              bcm_tr_mpls_egress_entry_mac_replace(unit, index, egr);
  14529              if (!soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
  14530              /* Update the VP NextHops -- For L2 MPLS and L3 SWAP */
  14531              L3_IF_ERROR_CLEANUP(bcm_tr_mpls_update_vp_nh (unit, *intf));
  14532         }
  14533     }
  14534     }
  14535 #endif /* BCM_TRX_SUPPORT  && BCM_MPLS_SUPPORT */
  14536 
  14537 #ifdef BCM_TRIDENT2_SUPPORT
  14538     if (soc_feature(unit, soc_feature_redirect_nh_to_ecmp_for_mpls_php) &&
  14539         (nh_info.flags2 & BCM_L3_FLAGS2_MPLS_PHP)) {
  14540         L3_IF_ERROR_CLEANUP(
  14541            bcm_tr_mpls_get_entry_type(unit, index, &entry_type));
  14542         if (entry_type == 0) {
  14543            L3_IF_ERROR_CLEANUP(
  14544                bcm_tr_mpls_egress_entry_modify(unit, index, 0, 1));
  14545         }
  14546     }
  14547 #endif /* BCM_TRIDENT2_SUPPORT */
  14548 
  14549 #ifdef BCM_TRIDENT2_SUPPORT
  14550     if (soc_feature(unit, soc_feature_fcoe) &&
  14551         (nh_info.flags2 & BCM_L3_FLAGS2_FCOE_ONLY)) {
  14552             egr_l3_next_hop_entry_t egr_nh;
  14553             BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm,
  14554                                              MEM_BLOCK_ALL, index, &egr_nh));
  14555             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
  14556                                 nh_entry_type_field[unit], 8);
  14557             BCM_IF_ERROR_RETURN
  14558                 (soc_mem_write(unit, EGR_L3_NEXT_HOPm,
  14559                                MEM_BLOCK_ALL, index, &egr_nh));
  14560     }
  14561 #endif
  14562 
  14563 #ifdef BCM_TRIUMPH3_SUPPORT
  14564     if (soc_feature(unit, soc_feature_ecmp_dlb)) {
  14565 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  14566         if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
  14567             if (!BCM_GPORT_IS_SET(egr->port)) {
  14568             L3_IF_ERROR_CLEANUP
  14569                     (bcm_th2_l3_egress_dlb_attr_set(unit, index,
  14570                                                     egr, p_egr_nh_old));
  14571             }
  14572         } else
  14573 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/
  14574         {
  14575             L3_IF_ERROR_CLEANUP
  14576                (bcm_tr3_l3_egress_dlb_attr_set(unit, index, egr));
  14577         }
  14578     } else
  14579 #endif /* BCM_TRIUMPH3_SUPPORT */
  14580     {
  14581         if ((egr->dynamic_scaling_factor !=
  14582                 BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID) ||
  14583             (egr->dynamic_load_weight !=
  14584                 BCM_L3_ECMP_DYNAMIC_LOAD_WEIGHT_INVALID) ||
  14585             (egr->dynamic_queue_size_weight !=
  14586                 BCM_L3_ECMP_DYNAMIC_QUEUE_SIZE_WEIGHT_INVALID)) {
  14587             err_code = BCM_E_UNAVAIL;
  14588             goto cleanup;
  14589         }
  14590     }
  14591 
  14592     return (BCM_E_NONE);
  14593 cleanup:
  14594     if (!egress_obj_update) {
  14595         (void) bcm_xgs3_nh_del(unit, entry_flag, index);
  14596     }
  14597 #if defined(BCM_TRIUMPH2_SUPPORT)
  14598     if (soc_feature(unit, soc_feature_mpls_failover)) {
  14599         if ((old_l3_payload != 0xffffffff) && 
  14600             soc_mem_field_valid(unit, EGR_IPMCm, L3_PAYLOADf)) {
  14601             egr_ipmc_entry_t   egr_ipmc_entry;
  14602             int l3mc_index = _BCM_MULTICAST_ID_GET(egr->failover_mc_group);
  14603             (void) soc_mem_read(unit, EGR_IPMCm, MEM_BLOCK_ANY, l3mc_index, 
  14604                                 &egr_ipmc_entry);
  14605             soc_mem_field32_set(unit, EGR_IPMCm, &egr_ipmc_entry, 
  14606                                 L3_PAYLOADf,old_l3_payload);  
  14607             (void) soc_mem_write(unit, EGR_IPMCm, MEM_BLOCK_ALL, l3mc_index, 
  14608                                  &egr_ipmc_entry);
  14609         }
  14610     }
  14611 #endif 
  14612     return err_code;
  14613 }
  14614 
  14615 /*
  14616  * Function:
  14617  *      bcm_xgs3_l3_egress_destroy
  14618  * Purpose:
  14619  *      Destroy an Egress forwarding object.
  14620  * Parameters:
  14621  *      unit    - (IN) bcm device.
  14622  *      intf    - (IN) L3 interface id pointing to Egress object.
  14623  * Returns:
  14624  *      BCM_E_XXX
  14625  */
  14626 int
  14627 bcm_xgs3_l3_egress_destroy(int unit, bcm_if_t intf)
  14628 {
  14629     bcm_l3_egress_t  egr;     /* Next hop info.           */
  14630     int nh_idx;               /* Next hop index.          */
  14631     int rv;                   /* Operation return status. */
  14632 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT)
  14633     uint32  entry_type=0;              /* Next Hop Entry_type */
  14634 #endif /* BCM_TRIUMPH_SUPPORT  && BCM_MPLS_SUPPORT */
  14635     uint32  entry_flag=0;
  14636 
  14637     /*  Make sure module was initialized. */
  14638     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  14639         return (BCM_E_INIT);
  14640     }
  14641 
  14642     /* Check l3 switching mode. */
  14643     if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) {
  14644         return (BCM_E_DISABLED);
  14645     }
  14646 
  14647     /* Input parameters check. */
  14648     if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf) &&
  14649         !BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) {
  14650         return (BCM_E_PARAM);
  14651     }
  14652 
  14653     /* Calculate next hop index. */
  14654     if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) {
  14655         nh_idx = intf - BCM_XGS3_EGRESS_IDX_MIN(unit);
  14656     } else {
  14657         nh_idx = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  14658     }
  14659 
  14660     /* If entry is used by hosts/routes or ecmp objects - reject deletion */
  14661     if(1 < BCM_XGS3_L3_ENT_REF_CNT
  14662        (BCM_XGS3_L3_TBL_PTR(unit, next_hop), nh_idx)) {
  14663         return (BCM_E_BUSY);
  14664     }
  14665 
  14666     rv = bcm_xgs3_l3_egress_get(unit, intf, &egr);
  14667     BCM_IF_ERROR_RETURN(rv);
  14668 
  14669 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT)
  14670     if ((SOC_IS_TR_VL(unit)) && (soc_feature(unit, soc_feature_mpls))) {
  14671         /* coverity[uninit_use] */
  14672         BCM_IF_ERROR_RETURN(bcm_tr_mpls_get_entry_type(unit, nh_idx, &entry_type));
  14673         if (entry_type == 1) {
  14674             if (egr.flags &  BCM_L3_ROUTE_LABEL) {
  14675                 if (egr.mpls_label != BCM_MPLS_LABEL_INVALID) {
  14676                     rv = bcm_tr_mpls_l3_label_delete (unit, nh_idx);
  14677                     BCM_IF_ERROR_RETURN(rv);
  14678                 }
  14679             } else if (!(egr.flags &  BCM_L3_ROUTE_LABEL)) {
  14680                 if (egr.mpls_label != BCM_MPLS_LABEL_INVALID) {
  14681                     rv = bcm_tr_mpls_swap_nh_info_delete (unit, nh_idx);
  14682                     BCM_IF_ERROR_RETURN(rv);
  14683                     rv = bcm_tr_mpls_egress_entry_modify(unit, nh_idx, 0, 0);
  14684                     BCM_IF_ERROR_RETURN(rv);
  14685                  } else if (egr.mpls_label == BCM_MPLS_LABEL_INVALID) {
  14686                     rv = bcm_tr_mpls_egress_entry_modify(unit, nh_idx, 0, 0);
  14687                     BCM_IF_ERROR_RETURN(rv);
  14688                 }
  14689             }
  14690         }
  14691     }
  14692 #endif /* BCM_TRIUMPH_SUPPORT && BCM_MPLS_SUPPORT */
  14693 
  14694 #if defined(BCM_TRIDENT3_SUPPORT)
  14695     if ((soc_feature(unit, soc_feature_flex_flow)) &&
  14696         (egr.flow_handle != 0) &&
  14697         (egr.mpls_label != BCM_MPLS_LABEL_INVALID)) {
  14698 
  14699         soc_mem_t view_id;
  14700 
  14701         BCM_IF_ERROR_RETURN(
  14702             soc_flow_db_ffo_to_mem_view_id_get(unit,
  14703                               egr.flow_handle,
  14704                               egr.flow_option_handle,
  14705                               SOC_FLOW_DB_FUNC_EGRESS_OBJ_ID,
  14706                               (uint32 *)&view_id));
  14707 
  14708         rv = _bcm_td3_mpls_gre_label_delete(unit, nh_idx, view_id);
  14709 
  14710         BCM_IF_ERROR_RETURN(rv);
  14711     }
  14712 #endif
  14713 
  14714 #if defined(BCM_TRIUMPH2_SUPPORT)
  14715     if (soc_feature(unit, soc_feature_failover))  {
  14716         if (BCM_SUCCESS(_bcm_esw_failover_egr_check(unit, &egr))) {
  14717             rv = _bcm_esw_failover_prot_nhi_cleanup(unit, nh_idx);
  14718             if ( (rv != BCM_E_NOT_FOUND) && (rv != BCM_E_NONE) ) {
  14719                 return rv;
  14720             }
  14721         }
  14722     }
  14723 #endif /* BCM_TRIUMPH2_SUPPORT  */
  14724 
  14725 #ifdef BCM_TRIDENT2_SUPPORT
  14726     if (soc_feature(unit, soc_feature_vxlan)) {
  14727         if(egr.flags & BCM_L3_VXLAN_ONLY) {
  14728            /* Reset VXLAN Egress NextHop */
  14729            BCM_IF_ERROR_RETURN(
  14730                bcm_td2_vxlan_egress_reset(unit, nh_idx));
  14731            /* Reset Trunk to NextHop Index Store entry */
  14732            if (!(egr.flags & BCM_L3_IPMC) && (egr.flags & BCM_L3_TGID)) {
  14733                BCM_IF_ERROR_RETURN(
  14734                   _bcm_xgs3_trunk_nh_store_reset (unit, egr.trunk, nh_idx));
  14735            }
  14736         }
  14737     }
  14738 #endif /* BCM_TRIDENT2_SUPPORT */
  14739 
  14740 #ifdef BCM_TRIDENT3_SUPPORT
  14741     if (soc_feature(unit, soc_feature_flex_flow)) {
  14742         uint32 entry_width;
  14743 
  14744         if(egr.flags2 & BCM_L3_FLOW_ONLY) {
  14745            /* Reset FLOW Egress NextHop */
  14746            BCM_IF_ERROR_RETURN(
  14747                _bcm_td3_flow_egress_reset(unit, nh_idx));
  14748            /* Reset Trunk to NextHop Index Store entry */
  14749            if (!(egr.flags & BCM_L3_IPMC) && (egr.flags & BCM_L3_TGID)) {
  14750                BCM_IF_ERROR_RETURN(
  14751                   _bcm_xgs3_trunk_nh_store_reset (unit, egr.trunk, nh_idx));
  14752            }
  14753         }
  14754 
  14755         if (egr.flow_handle != 0) {
  14756             BCM_IF_ERROR_RETURN(
  14757                 _bcm_l3_get_flex_entry_width(unit, &egr, &entry_width));
  14758 
  14759             if (entry_width == _BCM_DOUBLE_WIDE) {
  14760                 entry_flag = _BCM_L3_SHR_WIDE_FLEX_ENTRY;
  14761             }
  14762         }
  14763     }
  14764 #endif /* BCM_TRIDENT3_SUPPORT */
  14765 
  14766 #ifdef BCM_TRIUMPH3_SUPPORT
  14767     if (soc_feature(unit, soc_feature_l2gre)) {
  14768             /* Reset L2GRE Egress NextHop */
  14769             if(egr.flags & BCM_L3_L2GRE_ONLY) {
  14770                BCM_IF_ERROR_RETURN(
  14771                    bcm_tr3_l2gre_egress_reset(unit, nh_idx));
  14772                /* Reset Trunk to NextHop Index Store entry */
  14773                if (!(egr.flags & BCM_L3_IPMC) && (egr.flags & BCM_L3_TGID)) {
  14774                    BCM_IF_ERROR_RETURN(
  14775                       _bcm_xgs3_trunk_nh_store_reset (unit, egr.trunk, nh_idx));
  14776                }
  14777             }
  14778          }
  14779 #endif /* BCM_TRIUMPH3_SUPPORT */
  14780 
  14781 
  14782 #ifdef BCM_TRIDENT_SUPPORT
  14783         if (soc_feature(unit, soc_feature_trill)) {
  14784                 /* Reset TRILL Egress NextHop */
  14785                 if(egr.flags & BCM_L3_TRILL_ONLY) {
  14786                    BCM_IF_ERROR_RETURN(
  14787                        bcm_td_trill_egress_reset(unit, nh_idx));
  14788                    /* Reset Trunk to NextHop Index Store entry */
  14789                    if (!(egr.flags & BCM_L3_IPMC) && (egr.flags & BCM_L3_TGID)) {
  14790                        BCM_IF_ERROR_RETURN(
  14791                           _bcm_xgs3_trunk_nh_store_reset (unit, egr.trunk, nh_idx));
  14792                    }
  14793                 }
  14794          }
  14795 #endif /* BCM_TRIDENT_SUPPORT */
  14796 
  14797 
  14798 #ifdef BCM_TRIUMPH3_SUPPORT
  14799     if (soc_feature(unit, soc_feature_ecmp_dlb)) {
  14800 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  14801         if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
  14802             if (!BCM_GPORT_IS_SET(egr.port)) {
  14803             BCM_IF_ERROR_RETURN
  14804                 (bcm_th2_l3_egress_dlb_attr_destroy(unit, nh_idx, &egr));
  14805             }
  14806         } else
  14807 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/
  14808         {
  14809             BCM_IF_ERROR_RETURN
  14810                 (bcm_tr3_l3_egress_dlb_attr_destroy(unit, nh_idx));
  14811         }
  14812     }
  14813 #endif /* BCM_TRIUMPH3_SUPPORT */
  14814 
  14815 #ifdef BCM_KATANA_SUPPORT
  14816     if (soc_feature(unit, soc_feature_extended_queueing) &&
  14817          (egr.flags & BCM_L3_QUEUE_MAP)) {
  14818 
  14819         BCM_IF_ERROR_RETURN(
  14820              bcmi_kt_extended_queue_config_destroy(unit, nh_idx));
  14821     }
  14822 #endif /*BCM_KATANA_SUPPORT*/
  14823 #if defined(BCM_TRIUMPH2_SUPPORT)
  14824     if (soc_feature(unit, soc_feature_mpls_failover)) {
  14825         if ((egr.flags & BCM_L3_ROUTE_LABEL) && 
  14826             (egr.mpls_label != BCM_MPLS_LABEL_INVALID) && 
  14827             _BCM_MULTICAST_IS_SET(egr.failover_mc_group) && 
  14828             soc_mem_field_valid(unit, EGR_IPMCm, L3_PAYLOADf)) {
  14829             egr_ipmc_entry_t   egr_ipmc_entry;
  14830             int l3mc_index = _BCM_MULTICAST_ID_GET(egr.failover_mc_group);
  14831             rv = soc_mem_read(unit, EGR_IPMCm, MEM_BLOCK_ANY, l3mc_index, 
  14832                               &egr_ipmc_entry);
  14833             BCM_IF_ERROR_RETURN(rv);
  14834             soc_mem_field32_set(unit, EGR_IPMCm, &egr_ipmc_entry, 
  14835                                 L3_PAYLOADf,0);  
  14836             rv = soc_mem_write(unit, EGR_IPMCm, MEM_BLOCK_ALL, l3mc_index, 
  14837                                &egr_ipmc_entry);
  14838             BCM_IF_ERROR_RETURN(rv);
  14839         }
  14840     }
  14841 #endif
  14842     /* Delete next hop entry. */
  14843     rv = bcm_xgs3_nh_del(unit, entry_flag, nh_idx);
  14844     return (rv);
  14845 }
  14846 
  14847 /*
  14848  * Function:
  14849  *      bcm_xgs3_l3_egress_get
  14850  * Purpose:
  14851  *      Get an Egress forwarding object.
  14852  * Parameters:
  14853  *      unit    - (IN) bcm device.
  14854  *      intf    - (IN) L3 interface id pointing to Egress object.
  14855  *      egr     - (OUT) Egress forwarding destination.
  14856  * Returns:
  14857  *      BCM_E_XXX
  14858  */
  14859 int
  14860 bcm_xgs3_l3_egress_get(int unit, bcm_if_t intf, bcm_l3_egress_t *egr)
  14861 {
  14862     int offset;
  14863 
  14864     /*  Make sure module was initialized. */
  14865     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  14866         return (BCM_E_INIT);
  14867     }
  14868 
  14869     /* Check l3 switching mode. */
  14870     if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) {
  14871         return (BCM_E_DISABLED);
  14872     }
  14873 
  14874     /* Input parameters check. */
  14875     if ((NULL == egr) || (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf) &&
  14876          !BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf))) {
  14877         return (BCM_E_PARAM);
  14878     }
  14879     if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) {
  14880         offset = BCM_XGS3_EGRESS_IDX_MIN(unit);
  14881     } else {
  14882         offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  14883     }
  14884     /* Fill next hop entry info. */
  14885     BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, (intf - offset), egr));
  14886 
  14887 #ifdef BCM_TRIUMPH3_SUPPORT
  14888     if (soc_feature(unit, soc_feature_ecmp_dlb)) {
  14889         /* Get dynamic_scaling_factor and dynamic_load_weight */
  14890 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  14891         if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
  14892             if (!BCM_GPORT_IS_SET(egr->port)) {
  14893             BCM_IF_ERROR_RETURN
  14894                 (bcm_th2_l3_egress_dlb_attr_get(unit, (intf - offset), egr));
  14895             }
  14896         } else
  14897 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/
  14898         {
  14899             BCM_IF_ERROR_RETURN
  14900                 (bcm_tr3_l3_egress_dlb_attr_get(unit, (intf - offset), egr));
  14901         }
  14902     } else
  14903 #endif /* BCM_TRIUMPH3_SUPPORT */
  14904     {
  14905         egr->dynamic_scaling_factor = BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID;
  14906         egr->dynamic_load_weight = BCM_L3_ECMP_DYNAMIC_LOAD_WEIGHT_INVALID;
  14907         egr->dynamic_queue_size_weight = BCM_L3_ECMP_DYNAMIC_QUEUE_SIZE_WEIGHT_INVALID;
  14908     }
  14909 
  14910     return BCM_E_NONE;
  14911 }
  14912 
  14913 /*
  14914  * Function:
  14915  *      bcm_xgs3_l3_egress_find
  14916  * Purpose:
  14917  *      Find an egress forwarding object.
  14918  * Parameters:
  14919  *      unit       - (IN) bcm device.
  14920  *      egr        - (IN) Egress object properties to match.
  14921  *      intf       - (OUT) L3 interface id pointing to egress object
  14922  *                         if found.
  14923  * Returns:
  14924  *      BCM_E_XXX
  14925  */
  14926 int
  14927 bcm_xgs3_l3_egress_find(int unit, bcm_l3_egress_t *egr,
  14928                         bcm_if_t *intf)
  14929 {
  14930     _bcm_l3_tbl_op_t data;         /* Operation data.      */
  14931     bcm_l3_egress_t nh_info;       /* Next hop structure.  */
  14932     int nh_idx;
  14933     int riot_vp_egress_obj = 0;
  14934 #ifdef BCM_RIOT_SUPPORT
  14935     _bcm_l3_bookkeeping_t *l3_bk;
  14936 #endif
  14937 
  14938 
  14939 
  14940     /*  Make sure module was initialized. */
  14941     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  14942         return (BCM_E_INIT);
  14943     }
  14944 
  14945     /* Check l3 switching mode. */
  14946     if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) {
  14947         return (BCM_E_DISABLED);
  14948     }
  14949 
  14950     /* Input parameters check. */
  14951     if ((NULL == egr) || (NULL == intf)) {
  14952         return (BCM_E_PARAM);
  14953     }
  14954 
  14955 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
  14956     if (!soc_feature(unit, soc_feature_flex_flow) &&
  14957         (egr->flags2 & BCM_L3_MPLS_GRE_LABEL)) {
  14958         return (BCM_E_PARAM);
  14959     }
  14960 #endif
  14961 
  14962     /* Convert api egress object to hw next hop entry format. */
  14963     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_egress_to_nh_info(unit, egr, &nh_info));
  14964 
  14965     /* Convert API next hop entry to HW space format. */
  14966     BCM_IF_ERROR_RETURN(_bcm_xgs3_nh_map_api_data_to_hw(unit, &nh_info));
  14967 
  14968 
  14969     /* Initialization */
  14970     sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t));
  14971     data.tbl_ptr =  BCM_XGS3_L3_TBL_PTR(unit, next_hop);
  14972     data.width = _BCM_SINGLE_WIDE;
  14973     data.entry_buffer = (void *)&nh_info;
  14974     data.hash_func = _bcm_xgs3_nh_hash_calc;
  14975     data.cmp_func  = _bcm_xgs3_nh_ent_cmp;
  14976 
  14977     /* Find next hop entry. */
  14978     BCM_IF_ERROR_RETURN (_bcm_xgs3_tbl_match(unit, &data));
  14979     nh_idx = data.entry_index;
  14980 
  14981 
  14982 #ifdef BCM_RIOT_SUPPORT
  14983     l3_bk = &_bcm_l3_bk_info[unit];
  14984 
  14985     if (BCMI_RIOT_IS_ENABLED(unit)) {
  14986          if (l3_bk->l3_intf_overlay_alloc_mode > 0) {
  14987              if (nh_idx > l3_bk->l3_nh_overlay_entries) {
  14988                  riot_vp_egress_obj = 1;
  14989              }
  14990          } else {
  14991              if (nh_idx <= l3_bk->l3_nh_overlay_entries) {
  14992                  riot_vp_egress_obj = 1;
  14993              }
  14994          }
  14995     }
  14996 #endif
  14997 
  14998     /* Return Egress object id offset + nh_index */
  14999     /* Offset depends on whether it is a regular next hop residing on
  15000      * a physical port, or a next hop residing on a VP.
  15001      */
  15002     if ((nh_info.encap_id > 0 &&
  15003          nh_info.encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit)) ||
  15004         riot_vp_egress_obj) {
  15005         /* encap_id contains a vp value */
  15006         *intf = nh_idx + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  15007     } else {
  15008         *intf = nh_idx + BCM_XGS3_EGRESS_IDX_MIN(unit);
  15009     }
  15010 
  15011     return (BCM_E_NONE);
  15012 }
  15013 
  15014 /*
  15015  * Function:
  15016  *      _bcm_xgs3_nh_traverse_cb
  15017  * Purpose:
  15018  *      Call user callback for valid next hop entries.
  15019  * Parameters:
  15020  *      unit      - (IN)SOC unit number.
  15021  *      pattern   - (IN)Match pattern (interface id & negate).
  15022  *      data1     - (IN)Route info.
  15023  *      data2     - (IN)Next hop info.
  15024  *      cmp_result- (OUT)Comparison result.
  15025  * Returns:
  15026  *      BCM_E_XXX
  15027  */
  15028 STATIC int
  15029 _bcm_xgs3_nh_traverse_cb(int unit, void *pattern, void *data1,
  15030                          void *data2, int *cmp_result)
  15031 {
  15032     _bcm_l3_trvrs_data_t *trv_data;     /* Travers data.    */
  15033     bcm_l3_egress_t  *egr;              /* Egress object.   */
  15034     int nh_idx;                         /* Next hop index.  */
  15035     int rv = BCM_E_NONE;
  15036 
  15037     /* Cast input parameters. */
  15038     trv_data = (_bcm_l3_trvrs_data_t *) pattern;
  15039     egr      = (bcm_l3_egress_t *) data1;
  15040     nh_idx   = *(int *)data2;
  15041 
  15042 #ifdef BCM_TRX_SUPPORT
  15043     if (egr->encap_id > 0 && egr->encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit)) {
  15044         /* encap_id contains a virtual port value */
  15045         int vp;
  15046 
  15047         vp = egr->encap_id;
  15048         if (_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
  15049             BCM_GPORT_NIV_PORT_ID_SET(egr->port, vp);
  15050             nh_idx += BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  15051         } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeExtender)) {
  15052             BCM_GPORT_EXTENDER_PORT_ID_SET(egr->port, vp);
  15053             nh_idx += BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  15054         } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) {
  15055             BCM_GPORT_VLAN_PORT_ID_SET(egr->port, vp);
  15056             nh_idx += BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  15057         } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) {
  15058             BCM_GPORT_WLAN_PORT_ID_SET(egr->port, vp);
  15059             nh_idx += BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  15060         } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeMpls)) {
  15061             BCM_GPORT_MPLS_PORT_ID_SET(egr->port, vp);
  15062             nh_idx += BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  15063         } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeVxlan)) {
  15064             BCM_GPORT_VXLAN_PORT_ID_SET(egr->encap_id, vp);
  15065             nh_idx += BCM_XGS3_EGRESS_IDX_MIN(unit);
  15066         } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeFlow)) {
  15067             BCM_GPORT_FLOW_PORT_ID_SET(egr->encap_id, vp);
  15068             nh_idx += BCM_XGS3_EGRESS_IDX_MIN(unit);
  15069         } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeL2Gre)) {
  15070             BCM_GPORT_L2GRE_PORT_ID_SET(egr->encap_id, vp);
  15071             nh_idx += BCM_XGS3_EGRESS_IDX_MIN(unit);
  15072         } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeTrill)) {
  15073             BCM_GPORT_TRILL_PORT_ID_SET(egr->encap_id, vp);
  15074             nh_idx += BCM_XGS3_EGRESS_IDX_MIN(unit);
  15075         } else {
  15076             nh_idx += BCM_XGS3_EGRESS_IDX_MIN(unit);
  15077         }
  15078         if (egr->encap_id == vp) {
  15079             egr->module = 0;
  15080             egr->trunk = 0;
  15081             egr->flags &= ~BCM_L3_TGID;
  15082             egr->encap_id = 0;
  15083         }
  15084     } else if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, egr->encap_id)) {
  15085         /* encap_id contains a L2 egress object ID */
  15086         egr->port = 0;
  15087         egr->module = 0;
  15088         egr->trunk = 0;
  15089         egr->flags &= ~BCM_L3_TGID;
  15090         nh_idx += BCM_XGS3_EGRESS_IDX_MIN(unit);
  15091     } else
  15092 #endif /* BCM_TRX_SUPPORT */
  15093     {
  15094 #ifdef BCM_RIOT_SUPPORT
  15095         if (BCMI_RIOT_IS_ENABLED(unit) &&
  15096             (_bcm_vp_is_vfi_type(unit, egr->port))) {
  15097             nh_idx += BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  15098         } else
  15099 #endif
  15100         {
  15101             nh_idx += BCM_XGS3_EGRESS_IDX_MIN(unit);
  15102         }
  15103     }
  15104 
  15105     /* Call user callback. */
  15106     if (NULL != trv_data->egress_cb) {
  15107         rv = (*trv_data->egress_cb) (unit, nh_idx, egr, trv_data->cookie);
  15108 #ifdef BCM_CB_ABORT_ON_ERR
  15109         if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
  15110             return (rv);
  15111         }
  15112 #endif
  15113     }
  15114 
  15115     return (rv);
  15116 }
  15117 
  15118 /*
  15119  * Function:
  15120  *      _bcm_xgs3_ecmp_group_nh_delete
  15121  * Purpose:
  15122  *      Service routine used to decrement ecmp group member next hop
  15123  *      reference counter.
  15124  * Parameters:
  15125  *      unit         - (IN)SOC unit number.
  15126  *      ecmp_group   - (IN)Ecmp group member array.
  15127  *      ecmp_count   - (IN)Number of entries in ecmp group erray.
  15128  * Returns:
  15129  *      BCM_E_XXX
  15130  */
  15131 STATIC INLINE int
  15132 _bcm_xgs3_ecmp_group_nh_delete(int unit, int *ecmp_group, int ecmp_count)
  15133 {
  15134     int idx;         /* Iteration index. */
  15135 
  15136     /* Decrease reference count for all group member nexthops. */
  15137     for (idx = 0; idx < ecmp_count; idx++) {
  15138          /* If ECMP member is another ECMP group, skip NH delete */
  15139          if (soc_feature(unit, soc_feature_hierarchical_ecmp) ||
  15140              soc_feature(unit, soc_feature_multi_level_ecmp)) {
  15141              if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit,
  15142                                                     ecmp_group[idx])) {
  15143                  continue;
  15144              }
  15145          }
  15146 
  15147         bcm_xgs3_nh_del(unit, 0, ecmp_group[idx]);
  15148     }
  15149     return (BCM_E_NONE);
  15150 }
  15151 
  15152 
  15153 /*
  15154  * Function:
  15155  *      _bcm_xgs3_ecmp_group_remove
  15156  * Purpose:
  15157  *      Service routine used to decrement ecmp group member next hop
  15158  *      reference counter & destroy ecmp group.
  15159  * Parameters:
  15160  *      unit         - (IN)SOC unit number.
  15161  *      ecmp_idx     - (IN)Ecmp group start index.
  15162  *      remove_nh    - (IN)Remove group's member next hops.
  15163  * Returns:
  15164  *      BCM_E_XXX
  15165  */
  15166 STATIC int
  15167 _bcm_xgs3_ecmp_group_remove(int unit, int ecmp_idx, int remove_nh)
  15168 {
  15169     int ecmp_count = 0;             /* Next hop count in the group.  */
  15170     int *ecmp_grp;              /* Ecmp group from hw.           */
  15171     int rv=BCM_E_NONE;                     /* Operation return status.      */
  15172 
  15173     if (remove_nh) {
  15174         /* Allocate ecmp group buffer. */
  15175         BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp));
  15176 
  15177         /* Read ecmp group members from the hw. */
  15178         rv = _bcm_xgs3_ecmp_tbl_read(unit, ecmp_idx,
  15179                                      ecmp_grp, &ecmp_count);
  15180         if (BCM_FAILURE(rv)) {
  15181             sal_free(ecmp_grp);
  15182             return (rv);
  15183         }
  15184 
  15185         /* Decrease reference count for all group member nexthops. */
  15186         rv = _bcm_xgs3_ecmp_group_nh_delete(unit, ecmp_grp, ecmp_count);
  15187         if (BCM_FAILURE(rv)) {
  15188             sal_free(ecmp_grp);
  15189             return (rv);
  15190         }
  15191         sal_free (ecmp_grp);
  15192     }
  15193 
  15194     /* Decrement reference count of existing group */
  15195 	return bcm_xgs3_ecmp_group_del(unit, ecmp_idx, 0);
  15196 }
  15197 
  15198 /*
  15199  * Function:
  15200  *      bcm_xgs3_l3_egress_traverse
  15201  * Purpose:
  15202  *      Goes through egress objects table and runs the user callback
  15203  *      function at each valid egress objects entry passing back the
  15204  *      information for that object.
  15205  * Parameters:
  15206  *      unit       - (IN) bcm device.
  15207  *      trav_fn    - (IN) Callback function.
  15208  *      user_data  - (IN) User data to be passed to callback function.
  15209  * Returns:
  15210  *      BCM_E_XXX
  15211  */
  15212 int
  15213 bcm_xgs3_l3_egress_traverse(int unit, bcm_l3_egress_traverse_cb trav_fn,
  15214                             void *user_data)
  15215 {
  15216     _bcm_l3_trvrs_data_t trv_data;     /* Travers initiator function input. */
  15217 
  15218     /*  Make sure module was initialized. */
  15219     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  15220         return (BCM_E_INIT);
  15221     }
  15222 
  15223     /* Check l3 switching mode. */
  15224     if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) {
  15225         return (BCM_E_DISABLED);
  15226     }
  15227 
  15228     /* Input parameters check. */
  15229     if (NULL == trav_fn) {
  15230         return (BCM_E_PARAM);
  15231     }
  15232 
  15233     /* Zero traverse info. */
  15234     sal_memset(&trv_data, 0, sizeof(_bcm_l3_trvrs_data_t));
  15235 
  15236     /* Fill traverse data struct. */
  15237     trv_data.op_cb = _bcm_xgs3_nh_traverse_cb;
  15238     trv_data.egress_cb = trav_fn;
  15239     trv_data.cookie = user_data;
  15240 
  15241     /*  Delete routes matching the pattern from hw. */
  15242     if (BCM_XGS3_L3_HWCALL_CHECK(unit, nh_update_match)) {
  15243         int rv;
  15244         BCM_XGS3_L3_MODULE_LOCK(unit);
  15245         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, nh_update_match) (unit, &trv_data);
  15246         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  15247         return rv;
  15248     }
  15249     return (BCM_E_UNAVAIL);
  15250 }
  15251 
  15252 /*
  15253  * Function:
  15254  *      _bcm_xgs3_l3_egress_intf_validate
  15255  * Purpose:
  15256  *       Validate L3 egress objects array for multipath egress object
  15257  *       create / destroy / lookup
  15258  * Parameters:
  15259  *      unit        - (IN) bcm device.
  15260  *      intf_count  - (IN) Number of elements in intf_array.
  15261  *      intf_array  - (IN) Array of Egress forwarding objects.
  15262  *      ecmp_group_flags - (IN) ECMP group flags.
  15263  * Returns:
  15264  *      BCM_E_XXX
  15265  */
  15266 STATIC int
  15267 _bcm_xgs3_l3_egress_intf_validate(int unit, int intf_count,
  15268                                   bcm_if_t *intf_array,
  15269                                   uint32 ecmp_group_flags)
  15270 {
  15271     _bcm_l3_tbl_t *tbl_ptr;      /* Unit next hop table pointer. */
  15272     int idx;                     /* Iteration index.             */
  15273     int nh_id;                   /* Next hop id.                 */
  15274 #ifdef BCM_MULTI_LEVEL_ECMP_SUPPORT
  15275     int ecmp_group_idx;          /* ECMP group index             */
  15276 #endif
  15277 
  15278     /* Input parameters check */
  15279     if (intf_count > 0 && NULL == intf_array) {
  15280         return (BCM_E_PARAM);
  15281     }
  15282 
  15283     /* Get next hop table pointer. */
  15284     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop);
  15285 
  15286     /* Initialize ecmp group next hop indexes. */
  15287     for (idx = 0; idx < intf_count; idx ++) {
  15288 
  15289 #ifdef BCM_TOMAHAWK_SUPPORT
  15290         if (soc_feature(unit, soc_feature_hierarchical_ecmp)) {
  15291             if (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 
  15292                                  ecmp_mode_hierarchical) {
  15293                 /*
  15294                  * If ECMP group is at level 1, group index is a valid member
  15295                  * when the load balancing mode is not Resilient Hashing
  15296                  */
  15297                 if ((ecmp_group_flags & BCM_L3_ECMP_OVERLAY) &&
  15298                     !(ecmp_group_flags & BCM_L3_ECMP_RH_OPT) &&
  15299                     (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf_array[idx]))) {
  15300                     if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit,
  15301                         (intf_array[idx] - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)),
  15302                         BCM_L3_ECMP_UNDERLAY)) {
  15303                         continue;
  15304                     } else {
  15305                         return (BCM_E_PARAM);
  15306                     } 
  15307                 }
  15308             }
  15309         }
  15310 #endif /* BCM_TOMAHAWK_SUPPORT */
  15311 
  15312 #ifdef BCM_MULTI_LEVEL_ECMP_SUPPORT
  15313         if (soc_feature(unit, soc_feature_multi_level_ecmp)) {
  15314             if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) {
  15315                 /*
  15316                  * Overlay ECMP groups may have ecmp groups as valid members
  15317                  */
  15318                 if ((ecmp_group_flags & BCM_L3_ECMP_OVERLAY) &&
  15319                     (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit,
  15320                                                         intf_array[idx]))) {
  15321                     /* Make sure ecmp group member is inuse. */
  15322                     ecmp_group_idx = intf_array[idx] -
  15323                                      BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  15324 
  15325                     if (!BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit,
  15326                                                  ecmp_grp), ecmp_group_idx)) {
  15327                         return (BCM_E_PARAM);
  15328                     }
  15329                     /* Make sure ecmp group member is underlay. */
  15330                     if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit,
  15331                         (intf_array[idx] - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)),
  15332                         BCM_L3_ECMP_OVERLAY)) {
  15333                         return (BCM_E_PARAM);
  15334                     }
  15335                     continue;
  15336                 }
  15337             }
  15338         }
  15339 #endif /* BCM_MULTI_LEVEL_ECMP_SUPPORT */
  15340 
  15341         /* Egress object range sanity. */
  15342         if ((!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf_array[idx]) &&
  15343             !BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf_array[idx]))) {
  15344 #ifdef BCM_TOMAHAWK3_SUPPORT
  15345             if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf_array[idx])) {
  15346                 if (!((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) &&
  15347                       (ecmp_group_flags & BCM_L3_ECMP_OVERLAY)) ||
  15348                     !(BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  15349                                           ecmp_mode_hierarchical)) {
  15350                     return (BCM_E_PARAM);
  15351                 }
  15352             } else
  15353 #endif
  15354             {
  15355                 return (BCM_E_PARAM);
  15356             }
  15357         }
  15358 
  15359         /* Calculate next hop index. */
  15360         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf_array[idx])) {
  15361             nh_id = intf_array[idx] - BCM_XGS3_EGRESS_IDX_MIN(unit);
  15362         }
  15363 #ifdef BCM_TOMAHAWK3_SUPPORT
  15364         else if ((BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf_array[idx])) &&
  15365                  (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) &&
  15366                     (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  15367                                           ecmp_mode_hierarchical)) {
  15368             nh_id = intf_array[idx] - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  15369             tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  15370         }
  15371 #endif
  15372         else {
  15373             nh_id = intf_array[idx] - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  15374         }
  15375 
  15376         /* Validate that next hop is valid and in use */
  15377         if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, nh_id)) {
  15378             return (BCM_E_PARAM);
  15379         }
  15380     }
  15381     return (BCM_E_NONE);
  15382 }
  15383 
  15384 
  15385 /*
  15386  * Function:
  15387  *      _bcm_xgs3_l3_egress_intf_ref_count_update
  15388  * Purpose:
  15389  *      Update L3 egress object reference counts.
  15390  * Parameters:
  15391  *      unit        - (IN) bcm device.
  15392  *      intf_count  - (IN) Number of elements in intf_array.
  15393  *      intf_array  - (IN) Array of Egress forwarding objects.
  15394  *      inc_dec     - (IN) +/-1 Increment/Decrement.
  15395  * Returns:
  15396  *      BCM_E_XXX
  15397  */
  15398 int
  15399 _bcm_xgs3_l3_egress_intf_ref_count_update(int unit, int intf_count,
  15400                                           bcm_if_t *intf_array, int inc_dec)
  15401 {
  15402     _bcm_l3_tbl_t *tbl_ptr;      /* Unit next hop table pointer. */
  15403     int idx;                     /* Iteration index.             */
  15404     int nh_id;                   /* Next hop id.                 */
  15405 
  15406     /* Get next hop table pointer. */
  15407     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop);
  15408 
  15409     /* Initialize ecmp group next hop indexes. */
  15410     for (idx = 0; idx < intf_count; idx ++) {
  15411         /* Skip over members that are not NH indices */
  15412         if (soc_feature(unit, soc_feature_hierarchical_ecmp) ||
  15413             soc_feature(unit, soc_feature_multi_level_ecmp)) {
  15414             if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit,
  15415                                                    intf_array[idx])) {
  15416                 continue;
  15417             }
  15418         }
  15419         /* Calculate next hop index. */
  15420         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf_array[idx])) {
  15421             nh_id = intf_array[idx] - BCM_XGS3_EGRESS_IDX_MIN(unit);
  15422         } else {
  15423             nh_id = intf_array[idx] - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  15424         }
  15425 
  15426         /* Increment next hops reference counter. */
  15427         if (1 == inc_dec) {
  15428             BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_ptr, nh_id, _BCM_SINGLE_WIDE);
  15429         } else {
  15430             BCM_XGS3_L3_ENT_REF_CNT_DEC(tbl_ptr, nh_id, _BCM_SINGLE_WIDE);
  15431         }
  15432     }
  15433     return (BCM_E_NONE);
  15434 }
  15435 
  15436 STATIC INLINE int
  15437 _bcm_esw_l3_ecmp_grand_max_paths(int unit, uint32 ecmp_group_flags) {
  15438     int _max_paths = 0;
  15439 
  15440 #ifdef BCM_TOMAHAWK_SUPPORT
  15441     if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) &&
  15442         (ecmp_group_flags & BCM_L3_ECMP_RH_OPT)) {
  15443         _max_paths = BCM_XGS3_L3_ECMP_RH_MAX_PATHS(unit);
  15444     } else
  15445 #endif /* BCM_TOMAHAWK_SUPPORT */
  15446 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  15447     if (soc_feature(unit, soc_feature_ecmp_dlb_optimized) &&
  15448         (ecmp_group_flags & BCM_L3_ECMP_DLB_OPT)) {
  15449         _max_paths = 64;
  15450     } else if (soc_feature(unit, soc_feature_dgm) &&
  15451                (ecmp_group_flags & BCM_L3_ECMP_DGM_OPT)) {
  15452         _max_paths = 128;
  15453     } else
  15454 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/
  15455     {
  15456         _max_paths = BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  15457 #ifdef BCM_TOMAHAWK3_SUPPORT
  15458         if ((soc_feature(unit, soc_feature_l3_ecmp_weighted)) &&
  15459             !(ecmp_group_flags & BCM_L3_ECMP_WEIGHTED)) {
  15460             if (_max_paths > BCM_TH3_L3_ECMP_NON_WEIGHTED_MAX_PATHS) {
  15461                 _max_paths = BCM_TH3_L3_ECMP_NON_WEIGHTED_MAX_PATHS;
  15462             }
  15463         }
  15464 #endif
  15465     }
  15466 
  15467     return _max_paths;
  15468 }
  15469 
  15470 
  15471 /*
  15472  * Function:
  15473  *      _bcm_xgs3_l3_egress_multipath_to_ecmp_grp
  15474  * Purpose:
  15475  *      Map an Egress Multipath forwarding object to hw ecmp group.
  15476  * Parameters:
  15477  *      unit        - (IN) bcm device.
  15478  *      intf_count  - (IN) Number of elements in intf_array.
  15479  *      intf_array  - (IN) Array of Egress forwarding objects.
  15480  *      ref_cnt_inc - (IN) Increment next hops reference counters.
  15481  *      ecmp_group_flags  - (IN) ECMP group flags.
  15482  *      ecmp_group  - (OUT)Array of next hop indexes.
  15483  * Returns:
  15484  *      BCM_E_XXX
  15485  */
  15486 STATIC int
  15487 _bcm_xgs3_l3_egress_multipath_to_ecmp_grp(int unit, int intf_count,
  15488                                           bcm_if_t *intf_array,
  15489                                           int ref_cnt_inc, int *ecmp_group,
  15490                                           uint32 ecmp_group_flags)
  15491 {
  15492     int idx;                              /* Iteration index.             */
  15493 #ifdef BCM_TOMAHAWK3_SUPPORT
  15494     int ecmp_intfs = 0;
  15495 #endif
  15496 
  15497     /* Enforce maximum ecmp path's */
  15498     if (intf_count > _bcm_esw_l3_ecmp_grand_max_paths(unit, ecmp_group_flags)) {
  15499         return (BCM_E_RESOURCE);
  15500     }
  15501 
  15502 
  15503     /* Validate egress object interfaces array. */
  15504     BCM_IF_ERROR_RETURN
  15505         (_bcm_xgs3_l3_egress_intf_validate(unit, intf_count, intf_array,
  15506                                            ecmp_group_flags));
  15507 
  15508     /* Increment each individual next hop reference count. */
  15509     if (ref_cnt_inc) {
  15510         BCM_IF_ERROR_RETURN
  15511             (_bcm_xgs3_l3_egress_intf_ref_count_update(unit, intf_count,
  15512                                                        intf_array, 1));
  15513     }
  15514 
  15515     /* Initialize ecmp group next hop indexes. */
  15516     for (idx = 0; idx < intf_count; idx ++) {
  15517         /* Calculate next hop index. */
  15518         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf_array[idx])) {
  15519              ecmp_group[idx] = intf_array[idx] - BCM_XGS3_EGRESS_IDX_MIN(unit);
  15520         } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf_array[idx])){
  15521              ecmp_group[idx] = intf_array[idx] - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  15522         }
  15523 #ifdef BCM_TOMAHAWK3_SUPPORT
  15524         else if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf_array[idx])) {
  15525              ecmp_group[idx] = intf_array[idx] - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  15526         }
  15527 #endif
  15528 #ifdef BCM_TOMAHAWK_SUPPORT
  15529         if (soc_feature(unit, soc_feature_hierarchical_ecmp)) {
  15530             if (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  15531                                           ecmp_mode_hierarchical) {
  15532                 /*
  15533                  * If ECMP group is at level 1, group index is a valid member
  15534                  * intf_array[idx] has the absolute multipath index */
  15535                 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf_array[idx])) {
  15536                     ecmp_group[idx] = intf_array[idx];
  15537 #ifdef BCM_TOMAHAWK3_SUPPORT
  15538                     ecmp_intfs++;
  15539 #endif
  15540                 }
  15541 
  15542             }
  15543         }
  15544 #endif /* BCM_TOMAHAWK_SUPPORT */
  15545 #ifdef BCM_MULTI_LEVEL_ECMP_SUPPORT
  15546         if (soc_feature(unit, soc_feature_multi_level_ecmp)) {
  15547             if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) {
  15548                 /*
  15549                  * If ECMP group is at level 1, group index is a valid member
  15550                  * intf_array[idx] has the absolute multipath index */
  15551                 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf_array[idx])) {
  15552                     ecmp_group[idx] = intf_array[idx];
  15553                 }
  15554             }
  15555         }
  15556 #endif /* BCM_MULTI_LEVEL_ECMP_SUPPORT */
  15557 
  15558 
  15559 
  15560     }
  15561 #ifdef BCM_TOMAHAWK3_SUPPORT
  15562         if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) {
  15563             if (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  15564                                       ecmp_mode_hierarchical) {
  15565                 if ((ecmp_group_flags & BCM_L3_ECMP_OVERLAY) &&
  15566                     (ecmp_intfs != intf_count)) {
  15567                     if (ref_cnt_inc) {
  15568                         BCM_IF_ERROR_RETURN
  15569                             (_bcm_xgs3_l3_egress_intf_ref_count_update(unit, intf_count,
  15570                                                                        intf_array, -1));
  15571                     }
  15572                     return (BCM_E_PARAM);
  15573                 }
  15574             }
  15575         }
  15576 #endif
  15577     return (BCM_E_NONE);
  15578 }
  15579 
  15580 /*
  15581  * Function:
  15582  *      _bcm_xgs3_l3_egress_multipath_read
  15583  * Purpose:
  15584  *      Read an Egress Multipath forwarding object from hw.
  15585  * Parameters:
  15586  *      unit       - (IN) bcm device.
  15587  *      grp_idx    - (IN) Ecmp group index.
  15588  *      intf_size  - (IN) Maximum forwarding entries to read.
  15589  *      intf_array - (OUT) Array of Egress forwarding objects.
  15590  *      intf_count - (OUT) Number of entries of intf_count actually filled in.
  15591  * Returns:
  15592  *      BCM_E_XXX
  15593  */
  15594 STATIC int
  15595 _bcm_xgs3_l3_egress_multipath_read(int unit, int grp_idx, int intf_size,
  15596                                     bcm_if_t *intf_array, int *intf_count)
  15597 {
  15598     int *ecmp_grp;                      /* Ecmp group from hw.            */
  15599     int idx;                            /* Iteration index.               */
  15600     int rv;                             /* Operation return status.       */
  15601 #ifdef BCM_TRIDENT2_SUPPORT
  15602     char *egr_nh_tbl_ptr;               /* Dma egress nh table pointer. */
  15603     uint32 *egr_entry_ptr = NULL;       /* Egress next hop entry pointer. */
  15604 #endif
  15605 
  15606     /*Use BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID for chips like firebolt3 that
  15607      * does not have ECMP_GROUP*/
  15608     if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) {
  15609         if (!BCMI_XGS3_L3_MPATH_GROUP_IDX_VALID(unit, 
  15610                     (grp_idx + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)))) {
  15611             return (BCM_E_PARAM);
  15612         }
  15613     } else {
  15614         if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, 
  15615                     (grp_idx + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)))) {
  15616             return (BCM_E_PARAM);
  15617         }
  15618     }
  15619 
  15620     /* Allocate ecmp group buffer. */
  15621     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp));
  15622 
  15623     /* Read ecmp group from hw. */
  15624     rv = _bcm_xgs3_ecmp_tbl_read(unit, grp_idx,
  15625                                  ecmp_grp, intf_count);
  15626     if (BCM_FAILURE(rv)) {
  15627         sal_free(ecmp_grp);
  15628         return (rv);
  15629     }
  15630 
  15631     if (intf_size == 0) {
  15632         sal_free(ecmp_grp);
  15633         return  (BCM_E_NONE);
  15634     }
  15635 
  15636     if (NULL == intf_array) {
  15637         sal_free(ecmp_grp);
  15638         return (BCM_E_PARAM);
  15639     }
  15640 
  15641     /* Adjust number of read entries . */
  15642     if (*intf_count > intf_size) {
  15643         *intf_count = intf_size;
  15644     }
  15645 
  15646 #ifdef BCM_TRIDENT2_SUPPORT
  15647     if (soc_feature(unit, soc_feature_virtual_port_routing)) {
  15648         if (*intf_count > L3_ECMP_MEM_DMA_THRESHOLD) {
  15649             rv = bcm_xgs3_l3_tbl_dma(unit, EGR_L3_NEXT_HOPm,
  15650                                      sizeof(egr_l3_next_hop_entry_t), "egr_nh_tbl",
  15651                                      &egr_nh_tbl_ptr, NULL);
  15652             if (SOC_FAILURE(rv)) {
  15653                 sal_free(ecmp_grp);
  15654                 return rv;
  15655             }
  15656         }
  15657     }
  15658 #endif
  15659     /* Fill ecmp group info. */
  15660     for (idx = 0; idx < *intf_count; idx++) {
  15661 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
  15662         /* If this is already a multipath interface, skip adding base index */
  15663         if (soc_feature(unit, soc_feature_hierarchical_ecmp) ||
  15664             soc_feature(unit, soc_feature_multi_level_ecmp)) {
  15665             if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp_grp[idx])) {
  15666                 intf_array[idx] = ecmp_grp[idx];
  15667                 continue;
  15668             }
  15669         }
  15670 #endif /* BCM_TOMAHAWK_SUPPORT || BCM_MULTI_LEVEL_ECMP_SUPPORT */
  15671 #if defined(BCM_TOMAHAWK3_SUPPORT)
  15672         if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) &&
  15673            (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  15674                  ecmp_mode_hierarchical) &&
  15675             (grp_idx < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) {
  15676             intf_array[idx] =
  15677                 ecmp_grp[idx] + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  15678         } else
  15679 #endif
  15680         {
  15681             intf_array[idx] = ecmp_grp[idx] + BCM_XGS3_EGRESS_IDX_MIN(unit);
  15682         }
  15683 
  15684 #ifdef BCM_TRIDENT2_SUPPORT
  15685         if (soc_feature(unit, soc_feature_virtual_port_routing)) {
  15686             egr_l3_next_hop_entry_t egr_nh;
  15687             if (*intf_count > L3_ECMP_MEM_DMA_THRESHOLD) {
  15688                 egr_entry_ptr =
  15689                     soc_mem_table_idx_to_pointer(unit, EGR_L3_NEXT_HOPm,
  15690                                                  uint32 *, egr_nh_tbl_ptr,
  15691                                                  ecmp_grp[idx]);
  15692             } else {
  15693                 rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY,
  15694                                   ecmp_grp[idx], &egr_nh);
  15695                 if (SOC_FAILURE(rv)) {
  15696                     sal_free(ecmp_grp);
  15697                     return rv;
  15698                 }
  15699                 egr_entry_ptr = (uint32 *) &egr_nh;
  15700             }
  15701             
  15702             if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm, nh_entry_type_field[unit])) {
  15703                 if (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 
  15704                                         egr_entry_ptr, nh_entry_type_field[unit]) != 0) {
  15705                     continue;
  15706                 }
  15707 
  15708                 if (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 
  15709                                         egr_entry_ptr, L3__DVPf) == 0) {
  15710                     continue;
  15711                 }
  15712 
  15713                 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3__DVP_VALIDf)) {
  15714                     if (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 
  15715                                             egr_entry_ptr, L3__DVP_VALIDf)) {
  15716                         intf_array[idx] = ecmp_grp[idx] + 
  15717                                           BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  15718                      }
  15719                 } else {
  15720                     intf_array[idx] = ecmp_grp[idx] + 
  15721                                       BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  15722                 }
  15723             }           
  15724         }
  15725 #endif /* BCM_TRIDENT2_SUPPORT */
  15726     }
  15727 
  15728 #ifdef BCM_TRIDENT2_SUPPORT
  15729     if (soc_feature(unit, soc_feature_virtual_port_routing)) {
  15730         if (*intf_count > L3_ECMP_MEM_DMA_THRESHOLD) {
  15731             soc_cm_sfree(unit, egr_nh_tbl_ptr);
  15732         }
  15733     }
  15734 #endif
  15735 
  15736 #ifdef BCM_RIOT_SUPPORT
  15737     if ((BCMI_L3_ECMP_IS_MULTI_LEVEL(unit) ||
  15738         BCMI_RIOT_IS_ENABLED(unit)) &&
  15739         (soc_feature(unit, soc_feature_ing_l3_next_hop_encoded_dest) ||
  15740          soc_feature(unit, soc_feature_generic_dest))) {
  15741 
  15742         for (idx = 0; idx < *intf_count; idx++) {
  15743             ing_l3_next_hop_entry_t ing_nh_entry;
  15744             uint32 nh_dest = 0;
  15745             bcm_l3_egress_t nh;
  15746 
  15747             bcm_l3_egress_t_init(&nh);
  15748 #ifdef BCM_MULTI_LEVEL_ECMP_SUPPORT
  15749             /* Skip over members that are not NH indices */
  15750             if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp_grp[idx]) &&
  15751                 soc_feature(unit, soc_feature_multi_level_ecmp)) {
  15752                 continue;
  15753             }
  15754 #endif /* BCM_MULTI_LEVEL_ECMP_SUPPORT */
  15755 
  15756             rv = soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
  15757                           ecmp_grp[idx], &ing_nh_entry);
  15758 
  15759             if (SOC_FAILURE(rv)) {
  15760                 sal_free(ecmp_grp);
  15761                 return rv;
  15762             }
  15763 
  15764             nh_dest = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, &ing_nh_entry,
  15765                           DESTINATIONf);
  15766 #ifdef BCM_TRIDENT3_SUPPORT
  15767             if (soc_feature(unit, soc_feature_generic_dest)) {
  15768                 bcmi_td3_get_port_from_destination(unit, nh_dest, &nh);
  15769             } else
  15770 #endif /* BCM_TRIDENT3_SUPPORT */
  15771             {
  15772             bcmi_get_port_from_destination(unit, nh_dest, &nh);
  15773             }
  15774             if (_bcm_vp_is_vfi_type(unit, nh.port)) {
  15775                 intf_array[idx] = ecmp_grp[idx] +
  15776                           BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  15777             }
  15778         }
  15779     }
  15780 #endif
  15781     sal_free(ecmp_grp);
  15782     return (BCM_E_NONE);
  15783 }
  15784 
  15785 /*
  15786  * Function:
  15787  *     bcmi_xgs3_l3_egress_ref_count_update
  15788  * Purpose:
  15789  *      Update L3 egress object reference counts.
  15790  * Parameters:
  15791  *      unit        - (IN) bcm device.
  15792  *      intf_count  - (IN) Number of elements in intf_array.
  15793  *      intf_array  - (IN) Array of Egress forwarding objects.
  15794  *      incr        - (IN) +/-1 Increment/Decrement.
  15795  * Returns:
  15796  *      BCM_E_XXX
  15797  */
  15798 int
  15799 bcmi_xgs3_l3_egress_ref_count_update(int unit,
  15800                                          bcm_if_t intf,
  15801                                          uint32 flags,
  15802                                          int nh_ecmp_id,
  15803                                          int incr)
  15804 {
  15805     _bcm_l3_tbl_t *tbl_ptr;       /* Unit next hop table pointer. */
  15806     int nh_id;                    /* Next hop Id.*/
  15807 
  15808     if (flags & BCM_L3_MULTIPATH) {
  15809         /* Get next hop table pointer. */
  15810         tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  15811 #if defined(BCM_TOMAHAWK3_SUPPORT)
  15812     if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) &&
  15813         (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  15814                             ecmp_mode_hierarchical) &&
  15815         (nh_ecmp_id < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) {
  15816         tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp);
  15817     }
  15818 #endif
  15819         nh_id = nh_ecmp_id;
  15820     } else {
  15821         /* Get next hop table pointer. */
  15822         tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop);
  15823         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) {
  15824             nh_id = intf - BCM_XGS3_EGRESS_IDX_MIN(unit);
  15825         } else {
  15826             nh_id = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  15827         }
  15828     }
  15829 
  15830     if (incr) {
  15831         BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_ptr, nh_id, _BCM_SINGLE_WIDE);
  15832     } else {
  15833         BCM_XGS3_L3_ENT_REF_CNT_DEC(tbl_ptr, nh_id, _BCM_SINGLE_WIDE);
  15834     }
  15835 
  15836     return BCM_E_NONE;
  15837 }
  15838 
  15839 /*
  15840  * Function:
  15841  *      bcm_xgs3_l3_egress_multipath_max_create
  15842  * Purpose:
  15843  *      Create an Egress Multipath forwarding object.
  15844  * Parameters:
  15845  *      unit       - (IN) bcm device.
  15846  *      flags      - (IN) BCM_L3_REPLACE: replace existing.
  15847  *                        BCM_L3_WITH_ID: intf argument is given.
  15848  *      ecmp_flags - (IN) BCM_L3_ECMP_PATH_NO_SORTING: not resort members
  15849  *      intf_count - (IN) Number of elements in intf_array.
  15850  *      intf_array - (IN) Array of Egress forwarding objects.
  15851  *      mpintf     - (OUT) L3 interface id pointing to Egress multipath object.
  15852  *                         This is an IN argument if either BCM_L3_REPLACE
  15853  *                          or BCM_L3_WITH_ID are given in flags.
  15854  *      dlb_member_bitmap - (IN) ECMP DLB members.
  15855  * Returns:
  15856  *      BCM_E_XXX
  15857  */
  15858 int
  15859 bcm_xgs3_l3_egress_multipath_max_create(int unit, uint32 flags, uint32 ecmp_flags,
  15860                                         int max_paths, int intf_count,
  15861                                         bcm_if_t *intf_array, bcm_if_t *mpintf,
  15862                                         int primary_count,
  15863                                         SHR_BITDCL *dlb_member_bitmap)
  15864 {
  15865     int *ecmp_group = NULL;                     /* Next hop indexes array.      */
  15866     int *old_ecmp_group = NULL;                 /* Original nh indexes array.   */
  15867     int old_group_size;                  /* Original ecmp group size.    */
  15868     int ecmp_group_idx = -1;             /* Ecmp group index.            */
  15869     uint32 new_ecmp_flags = 0;                 /* ECMP group flags */
  15870     uint32  shr_flags;                   /* Table management flags.      */
  15871     int     rv = 0;                          /* Operation return status.     */
  15872     int    max_grp_paths = 0;    /* Configured Max ECMP Group paths */
  15873     int    _max_paths;
  15874     _bcm_l3_tbl_t  *tbl_ptr;        /* Unit ecmp table pointer. */
  15875 
  15876     /* Make sure unit supports multipath egress mode. */
  15877     BCM_IF_ERROR_RETURN(BCM_XGS3_L3_MPATH_EGRESS_UNSUPPORTED(unit));
  15878 
  15879     /* Input parameters check. */
  15880     if (NULL == mpintf) {
  15881         return (BCM_E_PARAM);
  15882     }
  15883 
  15884     /* Make sure device supports ecmp forwarding. */
  15885     if (0 == BCM_XGS3_L3_ECMP_MAX_PATHS(unit)) {
  15886         return (BCM_E_UNAVAIL);
  15887     }
  15888 
  15889     _max_paths = _bcm_esw_l3_ecmp_grand_max_paths(unit, ecmp_flags);
  15890 
  15891     if (max_paths == 0) {
  15892         max_paths = _max_paths;
  15893     } else if (max_paths < 2 ||
  15894                max_paths > _max_paths){
  15895         return BCM_E_PARAM;
  15896     }
  15897 
  15898     if (intf_count > max_paths) {
  15899         return (BCM_E_RESOURCE);
  15900     }
  15901 
  15902     if (primary_count > intf_count) {
  15903         return BCM_E_INTERNAL;
  15904     }
  15905 
  15906     if (primary_count < intf_count) {
  15907         if (soc_feature(unit, soc_feature_dgm) &&
  15908             (ecmp_flags & BCM_L3_ECMP_DGM_OPT)) {
  15909             /* Either primary or alternate cannot exceed half grand max paths */
  15910             if (primary_count > (_max_paths >> 1) ||
  15911                 (intf_count - primary_count) > (_max_paths >> 1)) {
  15912                 return (BCM_E_RESOURCE);
  15913             }
  15914 
  15915             /* Alternate count is not allowed to be equal to max paths */
  15916             if ((intf_count - primary_count) == max_paths) {
  15917                 return (BCM_E_PARAM);
  15918             }
  15919         } else {
  15920             return BCM_E_INTERNAL;
  15921         }
  15922     }
  15923 
  15924     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  15925 
  15926 #if defined(BCM_TOMAHAWK3_SUPPORT)
  15927     if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) &&
  15928         (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  15929                             ecmp_mode_hierarchical) &&
  15930         (ecmp_flags & BCM_L3_ECMP_OVERLAY)) {
  15931         tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp);
  15932     }
  15933 #endif
  15934     old_group_size = 0;
  15935     new_ecmp_flags = ecmp_flags;
  15936     /* Allocate ecmp group buffer. */
  15937     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_group));
  15938 
  15939 
  15940     /* Verify egress object range if BCM_L3_WITH_ID flag is set. */
  15941     if (flags & BCM_L3_WITH_ID) {
  15942 
  15943         /* Get ecmp group index. */
  15944         ecmp_group_idx = *mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  15945 
  15946         if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) {
  15947             if (!BCMI_XGS3_L3_MPATH_GROUP_IDX_VALID(unit, *mpintf)) {
  15948                 sal_free(ecmp_group);
  15949                 return (BCM_E_PARAM);
  15950             }
  15951         } else {
  15952             if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, *mpintf)) {
  15953                 sal_free(ecmp_group);
  15954                 return (BCM_E_PARAM);
  15955             }
  15956         }
  15957 
  15958         if (flags & BCM_L3_REPLACE) {
  15959             if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr,
  15960                                         ecmp_group_idx)) {
  15961                 sal_free(ecmp_group);
  15962                 return BCM_E_NOT_FOUND;
  15963             }
  15964 
  15965             rv = _bcm_xgs3_l3_ecmp_group_alloc(unit, &old_ecmp_group);
  15966             if (BCM_FAILURE(rv)) {
  15967                 sal_free (ecmp_group);
  15968                 return rv;
  15969             }
  15970 
  15971             /* for rh, it's dynamic_size  */
  15972             rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_idx,
  15973                                                  &max_grp_paths);
  15974             if (rv < 0) {
  15975                 sal_free(ecmp_group);
  15976                 sal_free(old_ecmp_group);
  15977                 return rv;
  15978             }
  15979 
  15980             /* Since the last entry of the L3_ECMP table is reserved for
  15981              * storing the group size, the last group size will be 1 less.
  15982              * This check ensures that user configures only those number of
  15983              * members.
  15984              */
  15985             if (intf_count > max_paths) {
  15986                 sal_free(ecmp_group);
  15987                 sal_free(old_ecmp_group);
  15988                 return BCM_E_PARAM;
  15989             }
  15990 
  15991             rv = _bcm_xgs3_l3_egress_multipath_read(unit, ecmp_group_idx,
  15992                                                  max_grp_paths, old_ecmp_group,
  15993                                                  &old_group_size);
  15994 
  15995             if (BCM_FAILURE(rv)) {
  15996                 sal_free(ecmp_group);
  15997                 sal_free(old_ecmp_group);
  15998                 return (rv);
  15999             }
  16000 
  16001             if (max_grp_paths != max_paths) {
  16002 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
  16003 #if defined(BCM_TRIDENT3_SUPPORT)
  16004                 if (soc_esw_ecmp_protected_enabled(unit)) {
  16005                     /* Do nothing. */
  16006                 } else
  16007 #endif /* BCM_TRIDENT3_SUPPORT */
  16008 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
  16009                 {
  16010                     rv = _bcm_xgs3_ecmp_group_max_size_update(unit, ecmp_flags,
  16011                                                               ecmp_group_idx, max_grp_paths, max_paths);
  16012                 }
  16013                 if (rv < 0) {
  16014                     sal_free(ecmp_group);
  16015                     sal_free(old_ecmp_group);
  16016                     return rv;
  16017                 }
  16018             }
  16019         }
  16020 
  16021         /*Both add and delete operation should with BCM_L3_WITH_ID set */
  16022         if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, ecmp_group_idx,
  16023                                                BCM_L3_ECMP_PATH_NO_SORTING)) {
  16024             new_ecmp_flags |= BCM_L3_ECMP_PATH_NO_SORTING;
  16025         }
  16026     }
  16027     /* Convert api flags to shared table management flags. */
  16028     rv = _bcm_xgs3_l3_flags_to_shr(flags, &shr_flags);
  16029     if (BCM_FAILURE(rv)) {
  16030         sal_free(ecmp_group);
  16031         if (old_ecmp_group != NULL) {
  16032             sal_free(old_ecmp_group);
  16033         }
  16034         return (rv);
  16035     }
  16036 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) \
  16037                               || defined(BCM_TOMAHAWK3_SUPPORT)
  16038     if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)
  16039 #if defined(BCM_TOMAHAWK3_SUPPORT)
  16040         || (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  16041                             ecmp_mode_hierarchical)
  16042 #endif
  16043        ) {
  16044 
  16045         if (ecmp_flags & BCM_L3_ECMP_OVERLAY) {
  16046             shr_flags |= _BCM_L3_SHR_OVERLAY_OBJECT;
  16047         }
  16048     } 
  16049 #endif
  16050 
  16051     /* Disable matching entry lookup. */
  16052     shr_flags |= _BCM_L3_SHR_MATCH_DISABLE;
  16053 
  16054     /* Convert egress multipath object to ecmp group. */
  16055     rv = _bcm_xgs3_l3_egress_multipath_to_ecmp_grp(unit, intf_count, intf_array,
  16056                                                    TRUE, ecmp_group, new_ecmp_flags);
  16057 
  16058     if (BCM_FAILURE(rv)) {
  16059         sal_free(ecmp_group);
  16060         if (old_ecmp_group != NULL) {
  16061             sal_free(old_ecmp_group);
  16062         }
  16063         return (rv );
  16064     }
  16065 
  16066     /* Create ecmp group. */
  16067     rv  = _bcm_xgs3_ecmp_group_add(unit, shr_flags, new_ecmp_flags, intf_count,
  16068                                    max_paths, ecmp_group, &ecmp_group_idx,
  16069                                    primary_count, dlb_member_bitmap);
  16070 
  16071     if (BCM_FAILURE(rv)) {
  16072         /* Decrement nh reference count - if ecmp group creation failed. */
  16073         _bcm_xgs3_ecmp_group_nh_delete(unit, ecmp_group, intf_count);
  16074         sal_free(ecmp_group);
  16075         if (old_ecmp_group != NULL) {
  16076             sal_free(old_ecmp_group);
  16077         }
  16078         return (rv);
  16079     } else if (old_group_size) {
  16080         /* Decrement nh reference count - for old ecmp group members. */
  16081         rv = _bcm_xgs3_l3_egress_intf_ref_count_update(unit, old_group_size,
  16082                                                        old_ecmp_group, -1);
  16083         if (BCM_FAILURE(rv)) {
  16084             sal_free(ecmp_group);
  16085             if (old_ecmp_group != NULL) {
  16086                 sal_free(old_ecmp_group);
  16087             }
  16088             return (rv);
  16089         }
  16090     }
  16091 
  16092     sal_free(ecmp_group);
  16093     if (old_ecmp_group != NULL) {
  16094         sal_free(old_ecmp_group);
  16095     }
  16096 
  16097     /* Return Egress object id 100K + nh_index */
  16098     *mpintf = BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit) + ecmp_group_idx;
  16099     return (BCM_E_NONE);
  16100 }
  16101 
  16102 /*
  16103  * Function:
  16104  *      bcm_xgs3_l3_egress_multipath_create
  16105  * Purpose:
  16106  *      Create an Egress Multipath forwarding object.
  16107  * Parameters:
  16108  *      unit       - (IN) bcm device.
  16109  *      flags      - (IN) BCM_L3_REPLACE: replace existing.
  16110  *                        BCM_L3_WITH_ID: intf argument is given.
  16111  *      ecmp_flags - (IN) BCM_L3_ECMP_PATH_NO_SORTING: not resort members
  16112  *      intf_count - (IN) Number of elements in intf_array.
  16113  *      intf_array - (IN) Array of Egress forwarding objects.
  16114  *      mpintf     - (OUT) L3 interface id pointing to Egress multipath object.
  16115  *                         This is an IN argument if either BCM_L3_REPLACE
  16116  *                          or BCM_L3_WITH_ID are given in flags.
  16117  *      ecmp_member_bitmap   - (IN) ECMP DLB members.
  16118  * Returns:
  16119  *      BCM_E_XXX
  16120  */
  16121 int
  16122 bcm_xgs3_l3_egress_multipath_create(int unit, uint32 flags, uint32 ecmp_flags,
  16123                                     int intf_count, bcm_if_t *intf_array,
  16124                                     bcm_if_t *mpintf, int primary_count,
  16125                                     SHR_BITDCL *dlb_member_bitmap)
  16126 {
  16127     return bcm_xgs3_l3_egress_multipath_max_create(unit, flags, ecmp_flags, 0,
  16128                                                    intf_count, intf_array, mpintf,
  16129                                                    primary_count, dlb_member_bitmap);
  16130   }
  16131 
  16132 /*
  16133  * Function:
  16134  *      bcm_xgs3_l3_egress_multipath_get
  16135  * Purpose:
  16136  *      Get an Egress Multipath forwarding object.
  16137  * Parameters:
  16138  *      unit       - (IN) bcm device.
  16139  *      mpintf     - (IN) L3 interface id pointing to Egress multipath object.
  16140  *      intf_size  - (IN) Size of allocated entries in intf_array.
  16141  *      intf_array - (OUT) Array of Egress forwarding objects.
  16142  *      intf_count - (OUT) Number of entries of intf_count actually filled in.
  16143  *                      This will be a value less than or equal to the value.
  16144  *                      passed in as intf_size unless intf_size is 0.  If
  16145  *                      intf_size is 0 then intf_array is ignored and
  16146  *                      intf_count is filled in with the number of entries
  16147  *                      that would have been filled into intf_array if
  16148  *                      intf_size was arbitrarily large.
  16149  * Returns:
  16150  *      BCM_E_XXX
  16151  */
  16152 int
  16153 bcm_xgs3_l3_egress_multipath_get(int unit, bcm_if_t mpintf, int intf_size,
  16154                                  bcm_if_t *intf_array, int *intf_count)
  16155 {
  16156     int grp_idx;                        /* Ecmp group index.              */
  16157 
  16158 #ifdef BCM_TRIDENT2_SUPPORT
  16159     int max_vp_lags = 0;
  16160 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
  16161     _bcm_l3_tbl_t  *tbl_ptr;        /* Unit ecmp table pointer. */
  16162 #endif
  16163 #endif /* BCM_TRIDENT2_SUPPORT */
  16164 
  16165 
  16166     /* Make sure unit supports multipath egress mode. */
  16167     BCM_IF_ERROR_RETURN(BCM_XGS3_L3_MPATH_EGRESS_UNSUPPORTED(unit));
  16168 
  16169     /* Input parameters sanity check. */
  16170     if ((NULL == intf_count) || ((NULL == intf_array) && (0 != intf_size))) {
  16171         return (BCM_E_PARAM);
  16172     }
  16173     if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, mpintf)) {
  16174         return (BCM_E_PARAM);
  16175     }
  16176 
  16177     /* Get ecmp group index. */
  16178     grp_idx = mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  16179 
  16180 #ifdef BCM_TRIDENT2_SUPPORT
  16181 
  16182     /* In Trident2, reserved indices for VP-LAG should not be got. */
  16183     if (soc_feature(unit, soc_feature_vp_lag)) {
  16184         max_vp_lags = soc_property_get(unit, spn_MAX_VP_LAGS,
  16185                           soc_mem_index_count(unit, EGR_VPLAG_GROUPm));
  16186 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
  16187         /*
  16188          * TD2P has split indexes for overlay and underlay.
  16189          * vp lags are in second range for underlay domain.
  16190          * therefore skip indexes which are reserved for vp lag.
  16191          */
  16192         tbl_ptr  = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  16193         if ((tbl_ptr->split_idx > 0)) {
  16194             if ((grp_idx >= tbl_ptr->split_idx) &&
  16195                 (grp_idx < tbl_ptr->split_idx + max_vp_lags)) {
  16196                 return (BCM_E_PARAM);
  16197             }
  16198         } else
  16199 #endif
  16200         {
  16201             if (grp_idx < max_vp_lags) {
  16202                 return (BCM_E_PARAM);
  16203             }
  16204         }
  16205     }
  16206 #endif /* BCM_TRIDENT2_SUPPORT */
  16207 
  16208     /* Read ecmp group from hardware. */
  16209     return _bcm_xgs3_l3_egress_multipath_read(unit, grp_idx, intf_size,
  16210                                               intf_array, intf_count);
  16211 }
  16212 
  16213 /*
  16214  * Function:
  16215  *      bcm_xgs3_l3_egress_ecmp_max_paths_get
  16216  * Purpose:
  16217  *      Get maximum number of next hop entries in ecmp group
  16218  * Parameters:
  16219  *      unit   - (IN) SOC unit number.
  16220  *      mpintf - (IN) L3 interface ID pointing to Egress multipath object.
  16221  *      max_paths - (OUT) Ecmp group max paths.
  16222  *      raw_max_paths - (OUT) Ecmp group raw max paths.
  16223  * Returns:
  16224  */
  16225 int
  16226 bcm_xgs3_l3_egress_ecmp_max_paths_get(int unit, bcm_if_t mpintf,
  16227                                       int *max_paths, int *raw_max_paths)
  16228 {
  16229     int ecmp_group_idx;
  16230     int raw_max = 0;
  16231 
  16232     ecmp_group_idx = mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  16233 
  16234 #ifdef BCM_TOMAHAWK_SUPPORT
  16235     if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) &&
  16236         bcm_opt_ecmp_group_is_rh(unit, ecmp_group_idx)) {
  16237         if (max_paths) {
  16238             BCM_IF_ERROR_RETURN(
  16239                 bcm_opt_ecmp_rh_multipath_get(unit, ecmp_group_idx,
  16240                                              0, NULL, NULL, max_paths));
  16241         }
  16242         if (raw_max_paths) {
  16243             BCM_IF_ERROR_RETURN(
  16244                 _bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_idx,
  16245                                                 raw_max_paths));
  16246         }
  16247 
  16248         return BCM_E_NONE;
  16249     }
  16250 #endif /* BCM_TOMAHAWK_SUPPORT */
  16251 
  16252     BCM_IF_ERROR_RETURN(
  16253         _bcm_xgs3_ecmp_max_grp_size_get(unit,
  16254                        ecmp_group_idx, &raw_max));
  16255     if (max_paths) {
  16256         *max_paths = raw_max;
  16257     }
  16258 
  16259     if (raw_max_paths) {
  16260         *raw_max_paths = raw_max;
  16261     }
  16262 
  16263     return BCM_E_NONE;
  16264 }
  16265 
  16266 /*
  16267  * Function:
  16268  *      bcm_xgs3_l3_egress_multipath_destroy
  16269  * Purpose:
  16270  *      Destroy an Egress Multipath forwarding object.
  16271  * Parameters:
  16272  *      unit    - (IN) bcm device.
  16273  *      mpintf  - (IN) L3 interface id pointing to Egress multipath object.
  16274  * Returns:
  16275  *      BCM_E_XXX
  16276  */
  16277 int
  16278 bcm_xgs3_l3_egress_multipath_destroy(int unit, bcm_if_t mpintf)
  16279 {
  16280     int ecmp_group_id;        /* Ecmp group id.             */
  16281     _bcm_l3_tbl_t *tbl_ptr;   /* Unit ecmp table pointer.   */
  16282 #if defined(BCM_TRIDENT2_SUPPORT)
  16283     int max_vp_lags = 0;
  16284 #endif /* BCM_TRIDENT2_SUPPORT */
  16285 
  16286     /* Make sure unit supports multipath egress mode. */
  16287     BCM_IF_ERROR_RETURN(BCM_XGS3_L3_MPATH_EGRESS_UNSUPPORTED(unit));
  16288 
  16289     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  16290 
  16291     /* Calculate ecmp group id. */
  16292     ecmp_group_id = mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  16293 #if defined(BCM_TOMAHAWK3_SUPPORT)
  16294     if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) &&
  16295        (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  16296              ecmp_mode_hierarchical) &&
  16297         (ecmp_group_id < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) {
  16298         tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp);
  16299     }
  16300 #endif
  16301 
  16302 #if defined(BCM_TRIDENT2_SUPPORT)
  16303     if (soc_feature(unit, soc_feature_vp_lag)) {
  16304         max_vp_lags = soc_property_get(unit, spn_MAX_VP_LAGS,
  16305                           soc_mem_index_count(unit, EGR_VPLAG_GROUPm));
  16306     }
  16307 #if defined(BCM_RIOT_SUPPORT) || defined (BCM_MULTI_LEVEL_ECMP_SUPPORT)
  16308     if (tbl_ptr->split_idx > 0) {
  16309         if ((ecmp_group_id >= tbl_ptr->split_idx) &&
  16310             (ecmp_group_id < (tbl_ptr->split_idx + max_vp_lags))) {
  16311             return BCM_E_PARAM;
  16312         }
  16313     } else
  16314 #endif /* BCM_RIOT_SUPPORT || BCM_MULTI_LEVEL_ECMP_SUPPORT */
  16315     {
  16316         if (ecmp_group_id < max_vp_lags) {
  16317             return BCM_E_PARAM;
  16318         }
  16319     }
  16320 
  16321 #endif /* BCM_TRIDENT2_SUPPORT */
  16322 
  16323     if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) {
  16324         if (!BCMI_XGS3_L3_MPATH_GROUP_IDX_VALID(unit, mpintf)) {
  16325             return (BCM_E_PARAM);
  16326         }
  16327     } else {
  16328         if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, mpintf)) {
  16329             return (BCM_E_PARAM);
  16330         }
  16331     }
  16332 
  16333     if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, ecmp_group_id)) {
  16334         return BCM_E_NOT_FOUND;
  16335     }
  16336 
  16337     /* If entry is used by routes - reject deletion */
  16338     if(1 < BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, ecmp_group_id)) {
  16339          return (BCM_E_BUSY);
  16340     }
  16341 
  16342     /* Delete ecmp group. */
  16343     BCM_IF_ERROR_RETURN(_bcm_xgs3_ecmp_group_remove(unit,
  16344                ecmp_group_id, TRUE));
  16345 
  16346     /* Reset ecmp group flags. */
  16347     l3_module_data[unit]->l3_ecmp_info.ecmp_flags[ecmp_group_id] = 0;
  16348 
  16349     return (BCM_E_NONE);
  16350 }
  16351 
  16352 /*
  16353  * Function:
  16354  *      bcm_xgs3_l3_egress_multipath_add
  16355  * Purpose:
  16356  *      Add an Egress forwarding object to an Egress Multipath
  16357  *      forwarding object.
  16358  * Parameters:
  16359  *      unit    - (IN) bcm device.
  16360  *      mpintf  - (IN) L3 interface id pointing to Egress multipath object.
  16361  *      intf    - (IN) L3 interface id pointing to Egress forwarding object.
  16362  * Returns:
  16363  *      BCM_E_XXX
  16364  */
  16365 int
  16366 bcm_xgs3_l3_egress_multipath_add(int unit, bcm_if_t mpintf, bcm_if_t intf)
  16367 {
  16368     int ecmp_grp_sz;                    /* Ecmp group size.        */
  16369     int *ecmp_grp;                      /* Ecmp group from hw.     */
  16370     int rv;                             /* Operation return status.*/
  16371     int ecmp_group_idx;                  /* Ecmp group index.            */
  16372     int max_grp_paths = 0;    /* Configured Max ECMP Group paths */
  16373 
  16374 #if defined(BCM_HURRICANE_SUPPORT)
  16375     if (SOC_IS_HURRICANE(unit) || SOC_IS_HURRICANE2(unit)) {
  16376         return (BCM_E_UNAVAIL);
  16377     }
  16378 #endif
  16379     if (soc_feature(unit, soc_feature_l3_no_ecmp)) {
  16380         return (BCM_E_UNAVAIL);
  16381     }
  16382 
  16383     if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, mpintf)) {
  16384         return (BCM_E_PARAM);
  16385     }
  16386     /* Validate added interface. */
  16387     if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) {
  16388         return (BCM_E_PARAM);
  16389     }
  16390 
  16391     /* Allocate ecmp group buffer. */
  16392     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp));
  16393     ecmp_group_idx = mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  16394     rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_idx, &max_grp_paths);
  16395     if (rv < 0) {
  16396         sal_free (ecmp_grp);
  16397         return rv;
  16398     }
  16399 
  16400     /* Get multipath egress object from hw. */
  16401     rv = bcm_xgs3_l3_egress_multipath_get (unit, mpintf,
  16402                                            max_grp_paths,
  16403                                            ecmp_grp, &ecmp_grp_sz);
  16404     if (BCM_FAILURE(rv)) {
  16405         sal_free(ecmp_grp);
  16406         return (rv);
  16407     }
  16408 
  16409 
  16410     /* Check if there is room in ecmp grp buffer */
  16411     if (ecmp_grp_sz == BCM_XGS3_L3_ECMP_MAX(unit)) {
  16412         sal_free(ecmp_grp);
  16413         return (BCM_E_FULL);
  16414     }
  16415 
  16416     ecmp_grp[ecmp_grp_sz] = intf;
  16417 
  16418     /* Update multipath egress object. */
  16419     rv = bcm_xgs3_l3_egress_multipath_create(unit,
  16420                                              BCM_L3_REPLACE | BCM_L3_WITH_ID,
  16421                                              0,
  16422                                              ecmp_grp_sz + 1, ecmp_grp,
  16423                                              &mpintf, ecmp_grp_sz + 1, NULL);
  16424     sal_free(ecmp_grp);
  16425     return (rv);
  16426 }
  16427 
  16428 /*
  16429  * Function:
  16430  *      bcm_xgs3_l3_egress_multipath_delete
  16431  * Purpose:
  16432  *      Delete an Egress forwarding object to an Egress Multipath
  16433  *      forwarding object.
  16434  * Parameters:
  16435  *      unit    - (IN) bcm device.
  16436  *      mpintf  - (IN) L3 interface id pointing to Egress multipath object
  16437  *      intf    - (IN) L3 interface id pointing to Egress forwarding object
  16438  * Returns:
  16439  *      BCM_E_XXX
  16440  */
  16441 int
  16442 bcm_xgs3_l3_egress_multipath_delete(int unit, bcm_if_t mpintf, bcm_if_t intf)
  16443 {
  16444     int ecmp_grp_sz;                    /* Ecmp group size.        */
  16445     int *ecmp_grp;                      /* Ecmp group from hw.     */
  16446     int idx;                            /* Iteration index.        */
  16447     int rv;                             /* Operation return status.*/
  16448     int ecmp_group_idx;                  /* Ecmp group index.            */
  16449     int max_grp_paths = 0;    /* Configured Max ECMP Group paths */
  16450 
  16451 #if defined(BCM_HURRICANE_SUPPORT)
  16452     if (SOC_IS_HURRICANE(unit) || SOC_IS_HURRICANE2(unit)) {
  16453         return (BCM_E_UNAVAIL);
  16454     }
  16455 
  16456 #endif
  16457     if (soc_feature(unit, soc_feature_l3_no_ecmp)) {
  16458         return (BCM_E_UNAVAIL);
  16459     }
  16460 
  16461     if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, mpintf)) {
  16462         return (BCM_E_PARAM);
  16463     }
  16464     /* Validate deleted interface. */
  16465     if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) {
  16466         return (BCM_E_PARAM);
  16467     }
  16468 
  16469     /* Allocate ecmp group buffer. */
  16470     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp));
  16471     ecmp_group_idx = mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  16472     rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_idx, &max_grp_paths);
  16473     if (rv < 0) {
  16474         sal_free(ecmp_grp);
  16475         return rv;
  16476     }
  16477 
  16478     /* Get multipath egress object from hw. */
  16479     rv = bcm_xgs3_l3_egress_multipath_get(unit, mpintf,
  16480                                           max_grp_paths,
  16481                                           ecmp_grp, &ecmp_grp_sz);
  16482     if (BCM_FAILURE(rv)) {
  16483         sal_free(ecmp_grp);
  16484         return (rv);
  16485     }
  16486 
  16487     /* Remove interface from egress object. */
  16488     for (idx = 0; idx < ecmp_grp_sz; idx++) {
  16489         if (ecmp_grp[idx] == intf) {
  16490             ecmp_grp[idx] = 0;
  16491             break;
  16492         }
  16493     }
  16494 
  16495     /* Check if deleted interface was found. */
  16496     if (idx == ecmp_grp_sz) {
  16497         sal_free(ecmp_grp);
  16498         return (BCM_E_NOT_FOUND);
  16499     }
  16500 
  16501     /* Copy last object interface to the deleted one spot. */
  16502     if (idx != (--ecmp_grp_sz)) {
  16503         ecmp_grp[idx] = ecmp_grp[ecmp_grp_sz];
  16504     }
  16505 
  16506     /* Update multipath egress object. */
  16507     rv = bcm_xgs3_l3_egress_multipath_max_create(unit,
  16508                                            BCM_L3_REPLACE | BCM_L3_WITH_ID,
  16509                                            0,
  16510                                            max_grp_paths, ecmp_grp_sz, ecmp_grp,
  16511                                            &mpintf,
  16512                                            ecmp_grp_sz, NULL);
  16513     sal_free(ecmp_grp);
  16514     return (rv);
  16515 }
  16516 
  16517 /*
  16518  * Function:
  16519  *      bcm_xgs3_l3_egress_multipath_find
  16520  * Purpose:
  16521  *      Find an egress multipath forwarding object.
  16522  * Parameters:
  16523  *      unit       - (IN) bcm device.
  16524  *      intf_count - (IN) Number of elements in intf_array.
  16525  *      intf_array - (IN) Array of egress forwarding objects.
  16526  *      intf       - (OUT) L3 interface id pointing to egress multipath object
  16527  *                         if found.
  16528  * Returns:
  16529  *      BCM_E_XXX
  16530  */
  16531 int
  16532 bcm_xgs3_l3_egress_multipath_find(int unit, int intf_count, bcm_if_t
  16533                                  *intf_array, bcm_if_t *mpintf)
  16534 {
  16535     _bcm_l3_tbl_op_t data;         /* Operation data.          */
  16536     int *ecmp_group;               /* Next hop indexes array.  */
  16537     int rv;                        /* Operation return status. */
  16538     uint32 ecmp_group_flags = 0;
  16539     _bcm_l3_ecmp_group_buffer_t ecmp_buf;
  16540 
  16541     /* Make sure unit supports multipath egress mode. */
  16542     BCM_IF_ERROR_RETURN(BCM_XGS3_L3_MPATH_EGRESS_UNSUPPORTED(unit));
  16543 
  16544     /* Input parameters check. */
  16545     if (NULL == mpintf) {
  16546         return (BCM_E_PARAM);
  16547     }
  16548 
  16549     /* Allocate ecmp group buffer. */
  16550     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_group));
  16551 
  16552     if (soc_feature(unit, soc_feature_hierarchical_ecmp) ||
  16553         soc_feature(unit, soc_feature_multi_level_ecmp)) {
  16554         /*
  16555          * Set ECMP Level to 1 to permit group members to be ecmp group id
  16556          * or next hop ids
  16557          */
  16558 #ifdef BCM_TOMAHAWK3_SUPPORT
  16559         if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) {
  16560             if (intf_count &&
  16561                 (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf_array[0]))) {
  16562                 ecmp_group_flags = BCM_L3_ECMP_OVERLAY;
  16563             }
  16564         } else
  16565 #endif
  16566         {
  16567             ecmp_group_flags = BCM_L3_ECMP_OVERLAY;
  16568         }
  16569     }
  16570 
  16571 #ifdef BCM_TOMAHAWK3_SUPPORT
  16572     if ((intf_count > BCM_TH3_L3_ECMP_NON_WEIGHTED_MAX_PATHS) &&
  16573         (soc_feature(unit, soc_feature_l3_ecmp_weighted))) {
  16574         ecmp_group_flags |= BCM_L3_ECMP_WEIGHTED;
  16575     }
  16576 #endif
  16577 
  16578     /* Convert egress multipath object to ecmp group. */
  16579     rv = _bcm_xgs3_l3_egress_multipath_to_ecmp_grp(unit, intf_count, intf_array,
  16580                                                    FALSE, ecmp_group, ecmp_group_flags);
  16581     if (BCM_FAILURE(rv)) {
  16582         sal_free(ecmp_group);
  16583         return (rv);
  16584     }
  16585 
  16586     /*
  16587      * Next hop indexes must be sorted in the group
  16588      * in order to produce identical hash every time.
  16589      */
  16590     _shr_sort(ecmp_group, intf_count, sizeof(int), _bcm_xgs3_cmp_int);
  16591 
  16592     /* Initialization */
  16593     sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t));
  16594     data.tbl_ptr =  BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  16595     data.width = _BCM_SINGLE_WIDE;
  16596     ecmp_buf.group_buffer = ecmp_group;
  16597     /* Called by application without DLB filler */
  16598     ecmp_buf.dlb_group_buffer = NULL;
  16599     data.entry_buffer = (void *)&ecmp_buf;
  16600     data.hash_func = _bcm_xgs3_ecmp_grp_hash_calc;
  16601     data.cmp_func  = _bcm_xgs3_ecmp_grp_cmp;
  16602 #ifdef BCM_TOMAHAWK3_SUPPORT
  16603     if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) &&
  16604         (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, intf_array[0]))) {
  16605         data.tbl_ptr =  BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp);
  16606     }
  16607 #endif
  16608     /* Find next hop entry. */
  16609     rv = _bcm_xgs3_tbl_match(unit, &data);
  16610     sal_free(ecmp_group);
  16611 #ifdef BCM_TOMAHAWK_SUPPORT
  16612     /* If this is a RH group on Tomahawk, find member array from _th_info */
  16613     if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) &&
  16614         rv == BCM_E_NOT_FOUND) {
  16615         return bcm_opt_l3_egress_rh_ecmp_find(unit, intf_count,
  16616                                              intf_array,
  16617                                              mpintf);
  16618     }
  16619 #endif
  16620     if (BCM_FAILURE(rv)) {
  16621         return (rv);
  16622     }
  16623 
  16624     /* Return Egress object id 100K + nh_index */
  16625     *mpintf = BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit) + data.entry_index;
  16626     return (BCM_E_NONE);
  16627 }
  16628 /*
  16629  * Function:
  16630  *      bcm_xgs3_l3_egress_multipath_traverse
  16631  * Purpose:
  16632  *      Goes through multipath egress objects table and runs the user callback
  16633  *      function at each multipath egress objects entry passing back the
  16634  *      information for that multipath object.
  16635  * Parameters:
  16636  *      unit       - (IN) bcm device.
  16637  *      trav_fn    - (IN) Callback function.
  16638  *      user_data  - (IN) User data to be passed to callback function.
  16639  * Returns:
  16640  *      BCM_E_XXX
  16641  */
  16642 int
  16643 bcm_xgs3_l3_egress_multipath_traverse(int unit,
  16644                           bcm_l3_egress_multipath_traverse_cb trav_fn,
  16645                           void *user_data)
  16646 {
  16647     bcm_if_t *intf_array;                      /* Ecmp group from hw.      */
  16648     _bcm_l3_tbl_t  *tbl_ptr;                   /* Unit ecmp table pointer. */
  16649     int intf_count;                            /* Egress interfaces count. */
  16650     int idx;                                   /* Iteration index.         */
  16651     int rv;                                    /* Operation return status. */
  16652     int max_grp_paths = 0;    /* Configured Max ECMP Group paths */
  16653 #ifdef BCM_TRIDENT2_SUPPORT
  16654     int max_vp_lags = 0;
  16655 #endif
  16656 
  16657     /* Make sure unit supports multipath egress mode. */
  16658     BCM_IF_ERROR_RETURN(BCM_XGS3_L3_MPATH_EGRESS_UNSUPPORTED(unit));
  16659 
  16660     /* Input parameters check. */
  16661     if (NULL == trav_fn) {
  16662         return (BCM_E_PARAM);
  16663     }
  16664 
  16665     /* Check if unit supports ecmp. */
  16666     if (!BCM_XGS3_L3_ECMP_MAX_PATHS(unit)) {
  16667         return (BCM_E_NONE);
  16668     }
  16669 
  16670     /* Allocate ecmp group buffer. */
  16671     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &intf_array));
  16672 
  16673     tbl_ptr  = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  16674     idx = tbl_ptr->idx_min;
  16675 
  16676 #ifdef BCM_TRIDENT2_SUPPORT
  16677     /* In Trident2, reserved indices for VP-LAG should not be reported */
  16678     if (soc_feature(unit, soc_feature_vp_lag)) {
  16679         max_vp_lags = soc_property_get(unit, spn_MAX_VP_LAGS,
  16680                 soc_mem_index_count(unit, EGR_VPLAG_GROUPm));
  16681     }
  16682 #endif /* BCM_TRIDENT2_SUPPORT */
  16683 
  16684     for (idx = 0; idx <= tbl_ptr->idx_maxused; idx++) {
  16685 
  16686 #ifdef BCM_TRIDENT2_SUPPORT
  16687         /* In Trident2, VP LAGs share the same table as ECMP group table.
  16688          * The first N entries are reserved for VP LAGs, where N is the
  16689          * value of the config property max_vp_lags.
  16690          */
  16691         if (soc_feature(unit, soc_feature_vp_lag)) {
  16692 
  16693 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
  16694             /*
  16695              * TD2P has split indexes for overlay and underlay.
  16696              * vp lags are in second range for underlay domain.
  16697              * therefore skip indexes which are reserved for vp lag.
  16698              */ 
  16699             if ((tbl_ptr->split_idx > 0)) {
  16700 
  16701                 if ((idx >= tbl_ptr->split_idx) &&
  16702                     (idx <= tbl_ptr->split_idx + max_vp_lags - 1)) {
  16703 
  16704                     idx = tbl_ptr->split_idx + max_vp_lags - 1;
  16705                     continue;
  16706                 }
  16707             } else 
  16708 #endif
  16709             {
  16710                 if (idx < max_vp_lags) {
  16711                     idx = max_vp_lags - 1;
  16712                     continue;
  16713                 }
  16714             }    
  16715         }
  16716 #endif /* BCM_TRIDENT2_SUPPORT */
  16717 
  16718          /* If group is not in use continue to the next one. */
  16719          if (!BCM_XGS3_L3_ENT_REF_CNT (tbl_ptr, idx)) {
  16720               continue;
  16721          }
  16722 
  16723          /*
  16724           *    COVERITY
  16725           *
  16726           *    In case the flag BCM_CB_ABORT_ON_ERR is defined, the value of
  16727           *    rv from (*trav_fn) is being used - so it's a false alarm that 
  16728           *    the value is being overwritten before use
  16729           */
  16730 
  16731           /*   coverity[value_overwrite : FALSE]    */
  16732          rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, idx, &max_grp_paths);
  16733          if (rv < 0) {
  16734               sal_free(intf_array);
  16735               return rv;
  16736          }
  16737 
  16738          /* Read group nexthops. */
  16739 #ifdef BCM_TOMAHAWK_SUPPORT
  16740          if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) &&
  16741              bcm_opt_ecmp_group_is_rh(unit, idx)) {
  16742              rv = bcm_opt_ecmp_rh_multipath_get(unit, idx,
  16743                                                BCM_XGS3_L3_ECMP_MAX(unit),
  16744                                                intf_array,
  16745                                                &intf_count,
  16746                                                NULL);
  16747          } else
  16748 #endif
  16749          {
  16750              rv = _bcm_xgs3_l3_egress_multipath_read(unit, idx,
  16751                                          max_grp_paths,
  16752                                          intf_array, &intf_count);
  16753          }
  16754          if (BCM_FAILURE(rv)) {
  16755                sal_free(intf_array);
  16756               return (rv);
  16757          }
  16758 
  16759          /*
  16760           *    COVERITY
  16761           *
  16762           *    In case the flag BCM_CB_ABORT_ON_ERR is defined, the value of
  16763           *    rv from (*trav_fn) is being used below - so it's a false alarm 
  16764           *    that the returned value is being overwritten before use.
  16765           */
  16766 
  16767           /*   coverity[returned_value : FALSE]  */
  16768          rv = (*trav_fn)(unit, (idx + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)),
  16769                          intf_count, intf_array, user_data);
  16770 #if defined(BCM_SCORPION_SUPPORT) || defined(BCM_TRIUMPH_SUPPORT)
  16771         if (SOC_IS_SCORPION(unit) || SOC_IS_TRIUMPH(unit)) {
  16772             /* Group index matches base index in ECMP table */
  16773             idx += (max_grp_paths - 1);
  16774         } else
  16775 #endif /* BCM_SCORPION_SUPPORT || BCM_TRIUMPH_SUPPORT */
  16776 
  16777         if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group) &&
  16778                 !BCM_XGS3_L3_MAX_ECMP_MODE(unit)) {
  16779             /* Each group takes two entries */
  16780             idx++;
  16781         }
  16782 #ifdef BCM_CB_ABORT_ON_ERR
  16783          if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
  16784              sal_free(intf_array);
  16785              return (rv);
  16786          }
  16787 #endif
  16788     }
  16789 #ifdef BCM_TOMAHAWK3_SUPPORT
  16790     if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) &&
  16791          (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  16792                                      ecmp_mode_hierarchical)) {
  16793         tbl_ptr  = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp);
  16794         idx = tbl_ptr->idx_min;
  16795 
  16796         for (idx = 0; idx <= tbl_ptr->idx_maxused; idx++) {
  16797 
  16798              /* If group is not in use continue to the next one. */
  16799              if (!BCM_XGS3_L3_ENT_REF_CNT (tbl_ptr, idx)) {
  16800                   continue;
  16801              }
  16802 
  16803              /*
  16804               *    COVERITY
  16805               *
  16806               *    In case the flag BCM_CB_ABORT_ON_ERR is defined, the value of
  16807               *    rv from (*trav_fn) is being used - so it's a false alarm that
  16808               *    the value is being overwritten before use
  16809               */
  16810 
  16811               /*   coverity[value_overwrite : FALSE]    */
  16812              rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, idx, &max_grp_paths);
  16813              if (rv < 0) {
  16814                   sal_free(intf_array);
  16815                   return rv;
  16816              }
  16817 
  16818              /* Read group nexthops. */
  16819              if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) &&
  16820                  bcm_opt_ecmp_group_is_rh(unit, idx)) {
  16821                  rv = bcm_opt_ecmp_rh_multipath_get(unit, idx,
  16822                                                    BCM_XGS3_L3_ECMP_MAX(unit),
  16823                                                    intf_array,
  16824                                                    &intf_count,
  16825                                                    NULL);
  16826              } else
  16827              {
  16828                  rv = _bcm_xgs3_l3_egress_multipath_read(unit, idx,
  16829                                              max_grp_paths,
  16830                                              intf_array, &intf_count);
  16831              }
  16832              if (BCM_FAILURE(rv)) {
  16833                    sal_free(intf_array);
  16834                   return (rv);
  16835              }
  16836 
  16837              /*
  16838               *    COVERITY
  16839               *
  16840               *    In case the flag BCM_CB_ABORT_ON_ERR is defined, the value of
  16841               *    rv from (*trav_fn) is being used below - so it's a false alarm
  16842               *    that the returned value is being overwritten before use.
  16843               */
  16844 
  16845               /*   coverity[returned_value : FALSE]  */
  16846              rv = (*trav_fn)(unit, (idx + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)),
  16847                              intf_count, intf_array, user_data);
  16848 
  16849             if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group) &&
  16850                     !BCM_XGS3_L3_MAX_ECMP_MODE(unit)) {
  16851                 /* Each group takes two entries */
  16852                 idx++;
  16853             }
  16854 #ifdef BCM_CB_ABORT_ON_ERR
  16855              if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
  16856                  sal_free(intf_array);
  16857                  return (rv);
  16858              }
  16859 #endif
  16860         }
  16861     }
  16862 #endif
  16863     sal_free(intf_array);
  16864     return (BCM_E_NONE);
  16865 }
  16866 
  16867 /*
  16868  * Function:
  16869  *      bcm_xgs3_l3_egress_ecmp_traverse
  16870  * Purpose:
  16871  *      Goes through ECMP egress objects table and runs the user callback
  16872  *      function at each ECMP egress object entry passing back the
  16873  *      information for that ECMP object.
  16874  * Parameters:
  16875  *      unit       - (IN) bcm device.
  16876  *      trav_fn    - (IN) Callback function.
  16877  *      user_data  - (IN) User data to be passed to callback function.
  16878  * Returns:
  16879  *      BCM_E_XXX
  16880  */
  16881 int
  16882 bcm_xgs3_l3_egress_ecmp_traverse(int unit,
  16883                           bcm_l3_egress_ecmp_traverse_cb trav_fn,
  16884                           void *user_data)
  16885 {
  16886     bcm_if_t *intf_array;                      /* Ecmp group from hw.      */
  16887     _bcm_l3_tbl_t  *tbl_ptr;                   /* Unit ecmp table pointer. */
  16888     int intf_count;                            /* Egress interfaces count. */
  16889     int idx;                                   /* Iteration index.         */
  16890     int rv;                                    /* Operation return status. */
  16891     int max_grp_paths = 0;    /* Configured Max ECMP Group paths */
  16892     bcm_l3_egress_ecmp_t ecmp;
  16893 
  16894     /* Make sure unit supports multipath egress mode. */
  16895     BCM_IF_ERROR_RETURN(BCM_XGS3_L3_MPATH_EGRESS_UNSUPPORTED(unit));
  16896 
  16897     /* Input parameters check. */
  16898     if (NULL == trav_fn) {
  16899         return (BCM_E_PARAM);
  16900     }
  16901 
  16902     /* Check if unit supports ecmp. */
  16903     if (!BCM_XGS3_L3_ECMP_MAX_PATHS(unit)) {
  16904         return (BCM_E_NONE);
  16905     }
  16906 
  16907     /* Allocate ecmp group buffer. */
  16908     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &intf_array));
  16909 
  16910     tbl_ptr  = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  16911     idx = tbl_ptr->idx_min;
  16912 
  16913     /* TD3 supports unequal partition ecmp feature. If all the ecmp groups
  16914      * are assigned to either OL or UL the table index should be from 0-4095 */
  16915     if (SOC_IS_TRIDENT3X(unit) && (tbl_ptr->idx_maxused ==
  16916         BCM_XGS3_L3_ECMP_MAX_GROUPS(unit))) {
  16917         tbl_ptr->idx_maxused = tbl_ptr->idx_maxused - 1;
  16918     }
  16919 
  16920     for (idx =0; idx <= tbl_ptr->idx_maxused; idx++) {
  16921 
  16922 #ifdef BCM_TRIDENT2_SUPPORT
  16923         /* In Trident2, reserved indices for VP-LAG should not be reported */
  16924         if (soc_feature(unit, soc_feature_vp_lag)) {
  16925             int max_vp_lags = 0;
  16926             max_vp_lags = soc_property_get(unit, spn_MAX_VP_LAGS,
  16927                     soc_mem_index_count(unit, EGR_VPLAG_GROUPm));
  16928 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
  16929             /*
  16930              * TD2P has split indexes for overlay and underlay.
  16931              * vp lags are in second range for underlay domain.
  16932              * therefore skip indexes which are reserved for vp lag.
  16933              */
  16934             if ((tbl_ptr->split_idx > 0)) {
  16935 
  16936                 if ((idx >= tbl_ptr->split_idx) &&
  16937                     (idx <= tbl_ptr->split_idx + max_vp_lags - 1)) {
  16938                     
  16939                     idx = tbl_ptr->split_idx + max_vp_lags - 1;
  16940                     continue;
  16941                 }
  16942             } else
  16943 #endif
  16944             {   
  16945                 if (idx < max_vp_lags) {
  16946                     idx = max_vp_lags - 1;
  16947                     continue;
  16948                 }
  16949 
  16950             }
  16951         }
  16952 #endif /* BCM_TRIDENT2_SUPPORT */
  16953 
  16954          /* If group is not in use continue to the next one. */
  16955          if (!BCM_XGS3_L3_ENT_REF_CNT (tbl_ptr, idx)) {
  16956               continue;
  16957          }
  16958 
  16959         /*
  16960          *    COVERITY
  16961          *
  16962          *    In case the flag BCM_CB_ABORT_ON_ERR is defined, the value of
  16963          *    rv from (*trav_fn) is being used - so it's a false alarm that
  16964          *    the value is being overwritten before use
  16965          */
  16966 
  16967         /*    coverity[value_overwrite : FALSE]  */
  16968          rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, idx, &max_grp_paths);
  16969          if (rv < 0) {
  16970               sal_free(intf_array);
  16971               return rv;
  16972          }
  16973 
  16974          /* Read group nexthops. */
  16975          rv = _bcm_xgs3_l3_egress_multipath_read(unit, idx,
  16976                                         max_grp_paths,
  16977                                         intf_array, &intf_count);
  16978          if (BCM_FAILURE(rv)) {
  16979                sal_free(intf_array);
  16980               return (rv);
  16981          }
  16982          /* TBD Skip over 256 reserved ECMP group entries */
  16983 
  16984          bcm_l3_egress_ecmp_t_init(&ecmp);
  16985          ecmp.ecmp_intf = idx + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  16986          ecmp.max_paths = max_grp_paths;
  16987 
  16988 #ifdef BCM_TRIUMPH3_SUPPORT
  16989          if (soc_feature(unit, soc_feature_ecmp_dlb)) {
  16990 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  16991             if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
  16992                 rv = bcm_th2_l3_egress_ecmp_dlb_get(unit, &ecmp);
  16993 
  16994                 if (BCM_FAILURE(rv)) {
  16995                     sal_free(intf_array);
  16996                     return (rv);
  16997                 }
  16998 
  16999                 if (BCM_TH2_ECMP_IS_DLB(unit, ecmp.dynamic_mode)) {
  17000                     int i = 0, j = 0;
  17001                     SHR_BITDCL *group_bitmap_ptr = NULL;
  17002 
  17003                     /* Exclude filler members from expanded DLB group */
  17004                     group_bitmap_ptr =
  17005                         BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, idx);
  17006                     for (i = 0; i < intf_count; i++) {
  17007                         if (SHR_BITGET(group_bitmap_ptr, i)) {
  17008                             if (i > j) {
  17009                                 intf_array[j++] = intf_array[i];
  17010                             } else {
  17011                                 j++;
  17012                             }
  17013                         }
  17014                     }
  17015                     intf_count = j;
  17016                 }
  17017             } else
  17018 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/
  17019             {
  17020                 rv = bcm_tr3_l3_egress_ecmp_dlb_get(unit, &ecmp);
  17021             if (BCM_FAILURE(rv)) {
  17022                 sal_free(intf_array);
  17023                 return (rv);
  17024             }
  17025          }
  17026 
  17027          }
  17028 #endif /* BCM_TRIUMPH3_SUPPORT */
  17029 
  17030 #ifdef BCM_TRIDENT2_SUPPORT
  17031          if ((SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT3X(unit)) &&
  17032              soc_feature(unit, soc_feature_ecmp_resilient_hash)) {
  17033              rv = bcm_td2_l3_egress_ecmp_rh_get(unit, &ecmp);
  17034              if (BCM_FAILURE(rv)) {
  17035                  sal_free(intf_array);
  17036                  return (rv);
  17037              }
  17038          }
  17039 #endif /* BCM_TRIDENT2_SUPPORT */
  17040 
  17041 #ifdef BCM_TOMAHAWK_SUPPORT
  17042          /* Get ECMP Level flags */
  17043          if (soc_feature(unit, soc_feature_hierarchical_ecmp)) {
  17044              if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit,
  17045                       (ecmp.ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)),
  17046                        BCM_L3_ECMP_OVERLAY)) {
  17047                  ecmp.ecmp_group_flags |= BCM_L3_ECMP_OVERLAY;
  17048              }
  17049              if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit,
  17050                       (ecmp.ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)),
  17051                        BCM_L3_ECMP_UNDERLAY)) {
  17052                  ecmp.ecmp_group_flags |= BCM_L3_ECMP_UNDERLAY;
  17053              }
  17054          }
  17055 
  17056         /* Get ECMP group's existing interface array */
  17057          if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) {
  17058              rv = bcm_opt_l3_egress_ecmp_lb_get(unit, &ecmp);
  17059              if (BCM_FAILURE(rv)) {
  17060                  sal_free(intf_array);
  17061                  return (rv);
  17062              }
  17063 
  17064              if (ecmp.dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) {
  17065                  rv = bcm_opt_ecmp_rh_multipath_get(unit,
  17066                            (ecmp.ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)),
  17067                                     BCM_XGS3_L3_ECMP_MAX(unit),
  17068                                     intf_array,
  17069                                     &intf_count,
  17070                                     &ecmp.max_paths);
  17071                  if (BCM_FAILURE(rv)) {
  17072                      sal_free(intf_array);
  17073                      return (rv);
  17074                  }
  17075              }
  17076          } 
  17077 #endif /* BCM_TOMAHAWK_SUPPORT */
  17078          /*
  17079           *    COVERITY
  17080           *
  17081           *    In case the flag BCM_CB_ABORT_ON_ERR is defined, the value of
  17082           *    rv from (*trav_fn) is being used below - so it's a false alarm 
  17083           *    that the returned value is being overwritten before use.
  17084           */
  17085 
  17086           /*    coverity[returned_value : FALSE]   */
  17087          rv = (*trav_fn)(unit, &ecmp, intf_count, intf_array, user_data);
  17088 #if defined(BCM_SCORPION_SUPPORT) || defined(BCM_TRIUMPH_SUPPORT)
  17089          if (SOC_IS_SCORPION(unit) || SOC_IS_TRIUMPH(unit) || SOC_IS_ENDURO(unit)) {
  17090              /* Group index matches base index in ECMP table */
  17091              idx += (max_grp_paths - 1);
  17092          } else
  17093 #endif /* BCM_SCORPION_SUPPORT || BCM_TRIUMPH_SUPPORT */
  17094          if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group) &&
  17095                  !BCM_XGS3_L3_MAX_ECMP_MODE(unit)) {
  17096              /* Each group takes two entries */
  17097              idx++;
  17098          }
  17099 #ifdef BCM_CB_ABORT_ON_ERR
  17100          if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
  17101              sal_free(intf_array);
  17102              return (rv);
  17103          }
  17104 #endif
  17105     }
  17106 #ifdef BCM_TOMAHAWK3_SUPPORT
  17107     if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) &&
  17108          (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  17109                                      ecmp_mode_hierarchical)) {
  17110         tbl_ptr  = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp);
  17111         for (idx =0; idx <= tbl_ptr->idx_maxused; idx++) {
  17112 
  17113              /* If group is not in use continue to the next one. */
  17114              if (!BCM_XGS3_L3_ENT_REF_CNT (tbl_ptr, idx)) {
  17115                   continue;
  17116              }
  17117 
  17118             /*
  17119              *    COVERITY
  17120              *
  17121              *    In case the flag BCM_CB_ABORT_ON_ERR is defined, the value of
  17122              *    rv from (*trav_fn) is being used - so it's a false alarm that
  17123              *    the value is being overwritten before use
  17124              */
  17125 
  17126             /*    coverity[value_overwrite : FALSE]  */
  17127              rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, idx, &max_grp_paths);
  17128              if (rv < 0) {
  17129                   sal_free(intf_array);
  17130                   return rv;
  17131              }
  17132 
  17133              /* Read group nexthops. */
  17134              rv = _bcm_xgs3_l3_egress_multipath_read(unit, idx,
  17135                                             max_grp_paths,
  17136                                             intf_array, &intf_count);
  17137              if (BCM_FAILURE(rv)) {
  17138                    sal_free(intf_array);
  17139                   return (rv);
  17140              }
  17141              /* TBD Skip over 256 reserved ECMP group entries */
  17142 
  17143              bcm_l3_egress_ecmp_t_init(&ecmp);
  17144              ecmp.ecmp_intf = idx + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  17145              ecmp.max_paths = max_grp_paths;
  17146 
  17147              /* Get ECMP Level flags */
  17148              if (soc_feature(unit, soc_feature_hierarchical_ecmp)) {
  17149                  if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit,
  17150                           (ecmp.ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)),
  17151                            BCM_L3_ECMP_OVERLAY)) {
  17152                      ecmp.ecmp_group_flags |= BCM_L3_ECMP_OVERLAY;
  17153                  }
  17154                  if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit,
  17155                           (ecmp.ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)),
  17156                            BCM_L3_ECMP_UNDERLAY)) {
  17157                      ecmp.ecmp_group_flags |= BCM_L3_ECMP_UNDERLAY;
  17158                  }
  17159              }
  17160 
  17161             /* Get ECMP group's existing interface array */
  17162              if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) {
  17163                  rv = bcm_opt_l3_egress_ecmp_lb_get(unit, &ecmp);
  17164                  if (BCM_FAILURE(rv)) {
  17165                      sal_free(intf_array);
  17166                      return (rv);
  17167                  }
  17168 
  17169                  if (ecmp.dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) {
  17170                      rv = bcm_opt_ecmp_rh_multipath_get(unit,
  17171                                (ecmp.ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)),
  17172                                         BCM_XGS3_L3_ECMP_MAX(unit),
  17173                                         intf_array,
  17174                                         &intf_count,
  17175                                         &ecmp.max_paths);
  17176                      if (BCM_FAILURE(rv)) {
  17177                          sal_free(intf_array);
  17178                          return (rv);
  17179                      }
  17180                  }
  17181              }
  17182              /*
  17183               *    COVERITY
  17184               *
  17185               *    In case the flag BCM_CB_ABORT_ON_ERR is defined, the value of
  17186               *    rv from (*trav_fn) is being used below - so it's a false alarm
  17187               *    that the returned value is being overwritten before use.
  17188               */
  17189 
  17190               /*    coverity[returned_value : FALSE]   */
  17191              rv = (*trav_fn)(unit, &ecmp, intf_count, intf_array, user_data);
  17192              if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group) &&
  17193                      !BCM_XGS3_L3_MAX_ECMP_MODE(unit)) {
  17194                  /* Each group takes two entries */
  17195                  idx++;
  17196              }
  17197 #ifdef BCM_CB_ABORT_ON_ERR
  17198              if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
  17199                  sal_free(intf_array);
  17200                  return (rv);
  17201              }
  17202 #endif
  17203         }
  17204     }
  17205 
  17206 #endif
  17207     sal_free(intf_array);
  17208     return (BCM_E_NONE);
  17209 }
  17210 
  17211 
  17212 int
  17213 _bcm_xgs3_l3_ecmp_info_get(
  17214     int unit, 
  17215     bcm_l3_egress_ecmp_t *ecmp_info)
  17216 {
  17217     int ecmp_group_idx;
  17218 #ifdef BCM_TRIDENT3_SUPPORT
  17219     int lb_mode = 0;
  17220 #endif
  17221     _bcm_l3_tbl_t  *tbl_ptr;
  17222 
  17223     if (ecmp_info == NULL) {
  17224         return BCM_E_PARAM;
  17225     }
  17226 
  17227     if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp_info->ecmp_intf)) {
  17228         return BCM_E_PARAM;
  17229     }
  17230 
  17231     /* Get ecmp group index. */
  17232     ecmp_group_idx = ecmp_info->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 
  17233 
  17234     /* Make sure entry is inuse. */
  17235 #ifdef BCM_TOMAHAWK3_SUPPORT
  17236     if (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl) &&
  17237         (ecmp_group_idx < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2)) &&
  17238         (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  17239                                          ecmp_mode_hierarchical)) {
  17240         tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp);
  17241     } else
  17242 #endif
  17243     {
  17244         tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  17245     }
  17246     if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, ecmp_group_idx)) {
  17247         return (BCM_E_NOT_FOUND);
  17248     }
  17249 
  17250     /* Start to get the ECMP group's information */
  17251     ecmp_info->flags = 0;
  17252 
  17253     BCM_IF_ERROR_RETURN(
  17254         bcm_xgs3_l3_egress_ecmp_max_paths_get(unit, ecmp_info->ecmp_intf,
  17255                                               &ecmp_info->max_paths, NULL));
  17256     if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, ecmp_group_idx,
  17257                                            BCM_L3_ECMP_PATH_NO_SORTING)) {
  17258         ecmp_info->ecmp_group_flags = BCM_L3_ECMP_PATH_NO_SORTING; 
  17259     } else {    
  17260         ecmp_info->ecmp_group_flags = 0;
  17261     }
  17262 #ifdef BCM_TOMAHAWK_SUPPORT
  17263     /* Get ECMP Level flags */
  17264     if (soc_feature(unit, soc_feature_hierarchical_ecmp)) {
  17265         if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, ecmp_group_idx,
  17266                                                BCM_L3_ECMP_UNDERLAY)) {
  17267             ecmp_info->ecmp_group_flags |= BCM_L3_ECMP_UNDERLAY; 
  17268         }
  17269     }
  17270 #endif
  17271 
  17272 #if defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
  17273     /* Get ECMP Overlay Flag */
  17274     if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) {
  17275         if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, ecmp_group_idx,
  17276                     BCM_L3_ECMP_OVERLAY)) {
  17277             ecmp_info->ecmp_group_flags |= BCM_L3_ECMP_OVERLAY;
  17278         }
  17279     }
  17280 #endif
  17281 
  17282     ecmp_info->dynamic_mode = 0;
  17283     ecmp_info->dynamic_size = 0;
  17284     ecmp_info->dynamic_age  = 0;
  17285     ecmp_info->dynamic_load_exponent = 0;
  17286     ecmp_info->dynamic_expected_load_exponent = 0;
  17287     ecmp_info->dgm.threshold = 0;
  17288     ecmp_info->dgm.cost = 0;
  17289     ecmp_info->dgm.bias = 0;
  17290 
  17291 #ifdef BCM_TRIUMPH3_SUPPORT
  17292     if (soc_feature(unit, soc_feature_ecmp_dlb)) {
  17293 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  17294             if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
  17295                 BCM_IF_ERROR_RETURN(
  17296                     bcm_th2_l3_egress_ecmp_dlb_get(unit, ecmp_info));
  17297             } else
  17298 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/
  17299             {
  17300                 BCM_IF_ERROR_RETURN(
  17301                     bcm_tr3_l3_egress_ecmp_dlb_get(unit, ecmp_info));
  17302             }
  17303     }
  17304 #endif /* BCM_TRIUMPH3_SUPPORT */
  17305 
  17306 #ifdef BCM_TRIDENT2_SUPPORT
  17307     if ((SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT3X(unit)) &&
  17308         soc_feature(unit, soc_feature_ecmp_resilient_hash)) {
  17309 #ifdef BCM_TRIDENT3_SUPPORT
  17310         if (SOC_IS_TRIDENT3X(unit)) {
  17311            int ecmp_group;
  17312            ecmp_count_entry_t ecmp_count_entry;
  17313 
  17314            if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp_info->ecmp_intf)) {
  17315                ecmp_group = ecmp_info->ecmp_intf -
  17316                                 BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  17317 
  17318                BCM_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY,
  17319                            ecmp_group, &ecmp_count_entry));
  17320                lb_mode = soc_L3_ECMP_COUNTm_field32_get(unit,
  17321                                   &ecmp_count_entry, LB_MODEf);
  17322            }
  17323         }
  17324 #endif
  17325         if ( (!(SOC_IS_TRIDENT3X(unit))) 
  17326 #ifdef BCM_TRIDENT3_SUPPORT
  17327              || ((lb_mode == BCM_ECMP_LB_MODE_ENHANCED_HASH)
  17328                                        && (ecmp_info->dynamic_mode == 0))
  17329 #endif
  17330            ) {
  17331             BCM_IF_ERROR_RETURN(
  17332                 bcm_td2_l3_egress_ecmp_rh_get(unit, ecmp_info));
  17333         }
  17334     }
  17335 #endif /* BCM_TRIDENT2_SUPPORT */
  17336 
  17337 #ifdef BCM_TOMAHAWK_SUPPORT
  17338 
  17339     if (
  17340 #ifdef BCM_TRIDENT3_SUPPORT
  17341         ( ((SOC_IS_TRIDENT3X(unit)) && (lb_mode != BCM_ECMP_LB_MODE_ENHANCED_HASH))) ||
  17342 #endif
  17343                 soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) {
  17344         BCM_IF_ERROR_RETURN(
  17345             bcm_opt_l3_egress_ecmp_lb_get(unit, ecmp_info));
  17346     }
  17347 #endif /* BCM_TOMAHAWK_SUPPORT */
  17348 #if defined(BCM_TOMAHAWK3_SUPPORT)
  17349        if (ecmp_info->ecmp_group_flags & BCM_L3_ECMP_WEIGHTED) {
  17350             /* Weighted groups are never sorted */
  17351             ecmp_info->ecmp_group_flags &= ~BCM_L3_ECMP_PATH_NO_SORTING;
  17352        }
  17353 #endif
  17354 
  17355     return BCM_E_NONE;
  17356 }
  17357 
  17358 /*
  17359  * Function:
  17360  *      _bcm_xgs3_l3_ecmp_member_alloc
  17361  * Purpose:
  17362  *      Allocate l3 ecmp group members array.
  17363  * Parameters:
  17364  *      unit    -  (IN) BCM device number.
  17365  *      ptr     -  (IN) Allocated group pointer
  17366  * Returns:
  17367  *      BCM_X_XXX
  17368  */
  17369 int
  17370 _bcm_xgs3_l3_ecmp_member_alloc(int unit, bcm_l3_ecmp_member_t **ptr)
  17371 {
  17372     int alloc_size;
  17373 
  17374     /*  Make sure module was initialized. */
  17375     if (NULL == ptr) {
  17376         return (BCM_E_NONE);
  17377     }
  17378 
  17379 
  17380     alloc_size = sizeof(bcm_l3_ecmp_member_t) * BCM_XGS3_L3_ECMP_MAX(unit);
  17381 
  17382     *ptr = NULL;
  17383     BCM_XGS3_L3_ALLOC((*ptr), alloc_size, "ecmp members array");
  17384 
  17385     /* Input parameters check */
  17386     if (NULL == *ptr) {
  17387         return (BCM_E_MEMORY);
  17388     }
  17389     return (BCM_E_NONE);
  17390 }
  17391 
  17392 /*
  17393  * Function:
  17394  *      _bcm_xgs3_l3_ecmp_member_failover_set
  17395  * Purpose:
  17396  *      Set the Ethertypes that are eligible or ineligible for
  17397  *      ECMP dynamic load balancing or resilient hashing.
  17398  * Parameters:
  17399  *      unit         - Unit number.
  17400  *      ecmp_info    - ECMP group information.
  17401  *      member_index - member offset in ECMP group.
  17402  *      ecmp_member  - ECMP member's information.
  17403  * Returns:
  17404  *      BCM_E_XXX
  17405  */
  17406 STATIC int 
  17407 _bcm_xgs3_l3_ecmp_member_failover_set(
  17408     int unit, 
  17409     bcm_l3_egress_ecmp_t *ecmp_info,
  17410     int member_index,
  17411     bcm_l3_ecmp_member_t *ecmp_member)
  17412 {
  17413     int rv = BCM_E_NONE;
  17414 
  17415 #ifdef BCM_TRIUMPH2_SUPPORT
  17416     if (soc_feature(unit, soc_feature_ecmp_failover)) {
  17417         int grp_idx;
  17418         int nh_index, prot_nh_index;
  17419         int failover_id, failover_egress_if;
  17420         int failover_id_valid = FALSE;
  17421 
  17422         if (_bcm_esw_failover_id_check(
  17423             unit, ecmp_member->failover_id) == BCM_E_NONE) {
  17424             failover_id_valid = TRUE;
  17425         }
  17426 
  17427 #ifdef BCM_TOMAHAWK2_SUPPORT
  17428         if (soc_feature(unit, soc_feature_ecmp_failover_config_check)) {
  17429             if (ecmp_info->dynamic_mode) {
  17430                 /* ECMP failover is only available to static hash */
  17431                 rv = failover_id_valid ? BCM_E_PARAM : BCM_E_NONE;
  17432                 return rv;
  17433             } else {
  17434                 if (soc_feature(unit, soc_feature_hierarchical_ecmp) &&
  17435                     BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit,
  17436                                                        ecmp_member->egress_if)) {
  17437                     /* Failover is not suitable for ecmp group */
  17438                     rv = failover_id_valid ? BCM_E_PARAM : BCM_E_NONE;
  17439                     return rv;
  17440                 }
  17441             }
  17442         } else
  17443 #endif /* BCM_TOMAHAWK2_SUPPORT */
  17444         if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit,
  17445                                                ecmp_member->egress_if)) {
  17446             rv = failover_id_valid ? BCM_E_PARAM : BCM_E_NONE;
  17447             return rv;
  17448         }
  17449 
  17450         if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp_info->ecmp_intf)) {
  17451             return (BCM_E_PARAM);
  17452         }
  17453 
  17454         if (! (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, ecmp_member->egress_if) ||
  17455            (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, ecmp_member->egress_if)))) {
  17456             return (BCM_E_PARAM);
  17457         }
  17458 
  17459 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
  17460 #if defined(BCM_TRIDENT3_SUPPORT)
  17461         if (soc_feature(unit, soc_feature_l3_ecmp_protected_access)) {
  17462             if (ecmp_info->ecmp_group_flags & BCM_L3_ECMP_OVERLAY ||
  17463                 ecmp_info->ecmp_group_flags & BCM_L3_ECMP_UNDERLAY) {
  17464                 /* Failover is not supported in Hierarchical ECMP configuration. */
  17465                 if (failover_id_valid) {
  17466                     return (BCM_E_PARAM);
  17467                 }
  17468             }
  17469         }
  17470 #endif /* BCM_TRIDENT3_SUPPORT */
  17471 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
  17472 
  17473         grp_idx  = ecmp_info->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  17474         if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, ecmp_member->egress_if)){
  17475           nh_index = ecmp_member->egress_if - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  17476         } else {
  17477           nh_index = ecmp_member->egress_if - BCM_XGS3_EGRESS_IDX_MIN(unit);
  17478         }
  17479         failover_id = ecmp_member->failover_id;
  17480         failover_egress_if = ecmp_member->failover_egress_if;
  17481 
  17482         if (failover_id_valid &&
  17483             BCM_XGS3_L3_EGRESS_IDX_VALID(unit, failover_egress_if)) {
  17484             prot_nh_index = 
  17485                 ecmp_member->failover_egress_if - BCM_XGS3_EGRESS_IDX_MIN(unit);
  17486 
  17487             rv = _bcm_esw_failover_ecmp_prot_nhi_create(unit, grp_idx, 
  17488                                                         member_index,
  17489                                                         nh_index, failover_id,
  17490                                                         prot_nh_index);
  17491         } else {
  17492             rv = _bcm_esw_failover_ecmp_prot_nhi_cleanup(unit, grp_idx, 
  17493                                                          member_index,
  17494                                                          nh_index);
  17495         }
  17496     }
  17497 #endif /* BCM_TRIUMPH2_SUPPORT */
  17498 
  17499     return rv;
  17500 }
  17501 
  17502 /*
  17503  * Function:
  17504  *      _bcm_xgs3_l3_ecmp_member_failover_get
  17505  * Purpose:
  17506  *      Get the Ethertypes that are eligible or ineligible for
  17507  *      ECMP dynamic load balancing or resilient hashing.
  17508  * Parameters:
  17509  *      unit         - Unit number.
  17510  *      ecmp_info    - ECMP group information.
  17511  *      member_index - member offset in ECMP group.
  17512  *      ecmp_member  - ECMP member's information.
  17513  * Returns:
  17514  *      BCM_E_XXX
  17515  */
  17516 
  17517 STATIC int 
  17518 _bcm_xgs3_l3_ecmp_member_failover_get(
  17519     int unit, 
  17520     bcm_l3_egress_ecmp_t *ecmp_info,
  17521     int member_index,
  17522     bcm_l3_ecmp_member_t *ecmp_member)
  17523 {
  17524     int rv = BCM_E_NONE;
  17525 
  17526 #ifdef BCM_TRIUMPH2_SUPPORT
  17527     if (soc_feature(unit, soc_feature_ecmp_failover)) {
  17528         int nh_index, prot_nh_index;
  17529         int grp_idx, failover_id, failover_intf;
  17530 
  17531 #ifdef BCM_TOMAHAWK2_SUPPORT
  17532         if (soc_feature(unit, soc_feature_ecmp_failover_config_check)) {
  17533             if (ecmp_info->dynamic_mode) {
  17534                 /* ECMP failover is only available to static hash */
  17535                 return (BCM_E_NONE);
  17536             } else {
  17537                 if (soc_feature(unit, soc_feature_hierarchical_ecmp) &&
  17538                     BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(
  17539                         unit, ecmp_member->egress_if)) {
  17540                     /* Failover is not suitable for ecmp group */
  17541                     return (BCM_E_NONE);
  17542                 }
  17543             }
  17544         } else
  17545 #endif /* BCM_TOMAHAWK2_SUPPORT */
  17546         if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit,
  17547                                                ecmp_member->egress_if)) {
  17548             rv = BCM_E_NONE;
  17549             return rv;
  17550         }
  17551 
  17552         if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp_info->ecmp_intf)) {
  17553             return (BCM_E_PARAM);
  17554         }
  17555 
  17556         if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, ecmp_member->egress_if)) {
  17557             return (BCM_E_PARAM);
  17558         }
  17559 
  17560         grp_idx  = ecmp_info->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  17561         nh_index = ecmp_member->egress_if - BCM_XGS3_EGRESS_IDX_MIN(unit);
  17562 
  17563         rv = _bcm_esw_failover_ecmp_prot_nhi_get(unit, grp_idx,
  17564                                                  member_index, nh_index,
  17565                                                  &failover_id, &prot_nh_index);
  17566         if (BCM_SUCCESS(rv)) {
  17567             failover_intf = prot_nh_index + BCM_XGS3_EGRESS_IDX_MIN(unit);
  17568             ecmp_member->failover_id   = failover_id;
  17569             ecmp_member->failover_egress_if = failover_intf;
  17570         }
  17571     }
  17572 #endif /* BCM_TRIUMPH2_SUPPORT */
  17573 
  17574     return rv;
  17575 }
  17576 
  17577 
  17578 int
  17579 _bcm_xgs3_l3_ecmp_member_get(
  17580     int unit, 
  17581     bcm_l3_egress_ecmp_t *ecmp_info, 
  17582     int ecmp_member_size, 
  17583     bcm_l3_ecmp_member_t *ecmp_member_array, 
  17584     int *ecmp_member_count)
  17585 {
  17586     int rv, i;
  17587     int alloc_size, intf_count;
  17588     bcm_if_t *intf_array = NULL;
  17589 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  17590     int alternate_count = 0;
  17591 #endif
  17592     if (ecmp_info == NULL) {
  17593         return BCM_E_PARAM;
  17594     }
  17595 
  17596     /* Start to get the ECMP member's information */
  17597     if (ecmp_member_size > 0) {
  17598         alloc_size = ecmp_member_size * sizeof(bcm_if_t);
  17599         intf_array = sal_alloc(alloc_size, "L3 ECMP intf_array");
  17600         if (intf_array == NULL) {
  17601             rv = BCM_E_MEMORY;
  17602             goto clean_up;
  17603         }
  17604     }
  17605 
  17606     /* Get ECMP group's existing interface array */
  17607     rv = bcm_esw_l3_egress_multipath_get(unit, ecmp_info->ecmp_intf, ecmp_member_size,
  17608                                          intf_array, &intf_count);
  17609     if (BCM_FAILURE(rv)) {
  17610         goto clean_up;
  17611     }
  17612 
  17613     *ecmp_member_count = intf_count;
  17614 
  17615     if (ecmp_member_size > 0) {
  17616         for (i = 0; i < *ecmp_member_count; i++) {
  17617             /* Get ECMP member's interface id */
  17618             ecmp_member_array[i].egress_if = intf_array[i];
  17619 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  17620             if (soc_feature(unit, soc_feature_dgm)) {
  17621                 alternate_count = BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit)
  17622                     [ecmp_info->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)];
  17623                 if (i >= (intf_count - alternate_count)) {
  17624                     ecmp_member_array[i].flags |= BCM_L3_ECMP_MEMBER_DGM_ALTERNATE;
  17625                 }
  17626             }
  17627 #endif
  17628             /* Get ECMP member's failover information */
  17629             rv = _bcm_xgs3_l3_ecmp_member_failover_get(unit, ecmp_info,
  17630                                                        i, &ecmp_member_array[i]);
  17631             if (rv == BCM_E_NOT_FOUND) {
  17632                 rv = BCM_E_NONE;
  17633             }
  17634             if (BCM_FAILURE(rv)) {
  17635                 goto clean_up;
  17636             }
  17637         }
  17638     }
  17639 clean_up:
  17640     if (intf_array) {
  17641         sal_free(intf_array);
  17642         intf_array = NULL;
  17643     }
  17644 
  17645     return rv;
  17646 }
  17647 
  17648 int
  17649 _bcm_xgs3_l3_ecmp_member_set(
  17650     int unit, 
  17651     bcm_l3_egress_ecmp_t *ecmp_info, 
  17652     int ecmp_member_count, 
  17653     bcm_l3_ecmp_member_t *ecmp_member)
  17654 {
  17655     int rv = BCM_E_NONE;
  17656     int i;
  17657 
  17658     /*
  17659      * Next hop indexes must be sorted in the group
  17660      * in order to produce identical hash every time.
  17661      */
  17662     if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) ||
  17663         !((SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT(unit) ||
  17664            SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) &&
  17665          (ecmp_info->ecmp_group_flags & BCM_L3_ECMP_PATH_NO_SORTING)))  {
  17666 #if defined(BCM_TOMAHAWK3_SUPPORT)
  17667           if (!(ecmp_info->ecmp_group_flags & BCM_L3_ECMP_WEIGHTED))
  17668 #endif
  17669         _shr_sort(ecmp_member, ecmp_member_count, sizeof(bcm_l3_ecmp_member_t),
  17670                   _bcm_xgs3_cmp_ecmp_member);
  17671     }
  17672 
  17673     /* Configure the member's attributions */
  17674     for (i = 0; i < ecmp_member_count; i++) {
  17675         /* Configure the failover_id and failover_intf */
  17676         rv = _bcm_xgs3_l3_ecmp_member_failover_set(unit, ecmp_info,
  17677                                                    i, &ecmp_member[i]);
  17678 
  17679         if (BCM_FAILURE(rv)) {
  17680             return rv;
  17681         }
  17682     }
  17683 
  17684 
  17685     return rv;
  17686 }
  17687 
  17688 int
  17689 bcm_xgs3_l3_ecmp_destroy(
  17690     int unit, 
  17691     bcm_if_t ecmp_group_id)
  17692 {
  17693     int rv;
  17694 
  17695     rv = bcm_xgs3_l3_egress_multipath_destroy(unit, ecmp_group_id);
  17696 
  17697 #ifdef BCM_TRIUMPH3_SUPPORT
  17698     if (BCM_SUCCESS(rv)) {
  17699         if (soc_feature(unit, soc_feature_ecmp_dlb)) {
  17700 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  17701             if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
  17702                 rv = bcm_th2_l3_egress_ecmp_dlb_destroy(unit, ecmp_group_id);
  17703             } else
  17704 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/
  17705             {
  17706                 rv = bcm_tr3_l3_egress_ecmp_dlb_destroy(unit, ecmp_group_id);
  17707             }
  17708         }
  17709     }
  17710 #endif /* BCM_TRIUMPH3_SUPPORT */
  17711 
  17712 #ifdef BCM_TRIDENT2_SUPPORT
  17713     if (BCM_SUCCESS(rv)) {
  17714         if (soc_feature(unit, soc_feature_ecmp_resilient_hash)) {
  17715 #ifdef BCM_TRIDENT3_SUPPORT
  17716             int lb_mode = 0;
  17717             int ecmp_group;
  17718             ecmp_count_entry_t ecmp_count_entry;
  17719 
  17720             if (SOC_IS_TRIDENT3X(unit)) {
  17721                if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp_group_id)) {
  17722 
  17723                    ecmp_group = ecmp_group_id -
  17724                                     BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  17725 
  17726                    BCM_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY,
  17727                                ecmp_group, &ecmp_count_entry));
  17728                    lb_mode = soc_L3_ECMP_COUNTm_field32_get(unit,
  17729                                       &ecmp_count_entry, LB_MODEf);
  17730                }
  17731             }
  17732 #endif
  17733             if ( (!(SOC_IS_TRIDENT3X(unit))) 
  17734 #ifdef BCM_TRIDENT3_SUPPORT
  17735                    || (lb_mode == BCM_ECMP_LB_MODE_ENHANCED_HASH)
  17736 #endif
  17737             ) {
  17738                 rv = bcm_td2_l3_egress_ecmp_rh_destroy(unit, ecmp_group_id);
  17739             }
  17740         }
  17741     }
  17742 #endif /* BCM_TRIDENT2_SUPPORT */
  17743 
  17744 #ifdef BCM_TOMAHAWK_SUPPORT
  17745     if (BCM_SUCCESS(rv)) {
  17746         if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) {
  17747             rv = bcm_opt_l3_egress_ecmp_rh_destroy(unit, ecmp_group_id);
  17748         }
  17749     }
  17750     if (BCM_SUCCESS(rv) &&
  17751         soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) {
  17752         rv = bcm_opt_ecmp_lb_mode_reset(unit, ecmp_group_id);
  17753     }
  17754     if (BCM_SUCCESS(rv) && soc_feature(unit, soc_feature_hierarchical_ecmp)) {
  17755         /* Reset the group flags */
  17756         BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit,
  17757                                            ecmp_group_id -
  17758                                            BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit),
  17759                                            BCM_L3_ECMP_OVERLAY);
  17760         BCM_XGS3_L3_ECMP_GROUP_FLAGS_RESET(unit,
  17761                                            ecmp_group_id -
  17762                                            BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit),
  17763                                            BCM_L3_ECMP_UNDERLAY);
  17764     }
  17765 #endif /* BCM_TOMAHAWK_SUPPORT */
  17766 
  17767     return rv;
  17768 }
  17769 
  17770 int
  17771 bcm_xgs3_l3_ecmp_get(
  17772     int unit, 
  17773     bcm_l3_egress_ecmp_t *ecmp_info, 
  17774     int ecmp_member_size, 
  17775     bcm_l3_ecmp_member_t *ecmp_member_array, 
  17776     int *ecmp_member_count)
  17777 {
  17778     int rv;
  17779 
  17780     if (ecmp_info == NULL) {
  17781         return BCM_E_PARAM;
  17782     }
  17783 
  17784     /* Get the ECMP group's information */
  17785     rv = _bcm_xgs3_l3_ecmp_info_get(unit, ecmp_info);
  17786     BCM_IF_ERROR_RETURN(rv);
  17787 
  17788     /* Get the ECMP member's information */
  17789     rv = _bcm_xgs3_l3_ecmp_member_get(unit, ecmp_info, ecmp_member_size, 
  17790                                       ecmp_member_array, ecmp_member_count);
  17791     BCM_IF_ERROR_RETURN(rv);
  17792 
  17793     return rv;
  17794 }
  17795 
  17796 int
  17797 bcm_xgs3_l3_ecmp_find(
  17798     int unit, 
  17799     int ecmp_member_count, 
  17800     bcm_l3_ecmp_member_t *ecmp_member_array, 
  17801     bcm_l3_egress_ecmp_t *ecmp_info)
  17802 {
  17803     int rv, i, intf_count;
  17804     bcm_if_t *intf_array = NULL;
  17805 
  17806     if (ecmp_member_count == 0 || 
  17807         ecmp_member_array == NULL || 
  17808         ecmp_info == NULL) {
  17809         return BCM_E_PARAM;
  17810     }
  17811 
  17812     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &intf_array));
  17813 
  17814     intf_count = ecmp_member_count;
  17815 
  17816     for (i = 0; i < intf_count; i++) {
  17817         intf_array[i] = ecmp_member_array[i].egress_if;
  17818     }
  17819 
  17820     rv = bcm_xgs3_l3_egress_multipath_find(unit, intf_count, intf_array, 
  17821                                            &ecmp_info->ecmp_intf);
  17822 
  17823     if (BCM_FAILURE(rv)) {
  17824         goto clean_up;
  17825     }
  17826 
  17827     rv = _bcm_xgs3_l3_ecmp_info_get(unit, ecmp_info);
  17828     if (BCM_FAILURE(rv)) {
  17829         goto clean_up;
  17830     }
  17831 
  17832 clean_up:
  17833     if (intf_array) {
  17834         sal_free(intf_array);
  17835         intf_array = NULL;
  17836     }
  17837 
  17838     return rv;
  17839 }
  17840 
  17841 
  17842 int
  17843 _bcm_xgs3_l3_ecmp_range_traverse(int unit, int start, int end, _bcm_l3_tbl_t *tbl_ptr,
  17844     bcm_l3_ecmp_member_t *ecmp_member_array, bcm_l3_ecmp_traverse_cb trav_fn,
  17845     void *user_data)
  17846 {
  17847     int rv = 0;
  17848     int idx = 0;
  17849     bcm_l3_egress_ecmp_t ecmp_info;
  17850     int ecmp_member_count;                          /* Egress interfaces count. */
  17851 
  17852     for (idx = start; idx <= end; idx++) {
  17853         /* If group is not in use continue to the next one. */
  17854         if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, idx)) {
  17855             continue;
  17856         }
  17857 
  17858         bcm_l3_egress_ecmp_t_init(&ecmp_info);
  17859         
  17860         ecmp_info.ecmp_intf = idx + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  17861 
  17862         rv = bcm_esw_l3_ecmp_get(unit, &ecmp_info, BCM_XGS3_L3_ECMP_MAX(unit),
  17863                                   ecmp_member_array, &ecmp_member_count);
  17864         if (BCM_FAILURE(rv)) {
  17865             return rv;
  17866         }
  17867 
  17868         rv = (*trav_fn)(unit, &ecmp_info, ecmp_member_count, ecmp_member_array,
  17869                         user_data);
  17870 #if defined(BCM_SCORPION_SUPPORT) || defined(BCM_TRIUMPH_SUPPORT)
  17871         if (SOC_IS_SCORPION(unit) || SOC_IS_TRIUMPH(unit)) {
  17872             /* Group index matches base index in ECMP table */
  17873             idx += (ecmp_info.max_paths - 1);
  17874         } else
  17875 #endif /* BCM_SCORPION_SUPPORT || BCM_TRIUMPH_SUPPORT */
  17876         if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group) &&
  17877                 !BCM_XGS3_L3_MAX_ECMP_MODE(unit)) {
  17878             /* Each group takes two entries */
  17879             idx++;
  17880         }
  17881 #ifdef BCM_CB_ABORT_ON_ERR
  17882         if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
  17883             return rv;
  17884         }
  17885 #endif
  17886     }
  17887     return rv;
  17888 }
  17889 
  17890 
  17891 int
  17892 bcm_xgs3_l3_ecmp_traverse(
  17893     int unit,
  17894     bcm_l3_ecmp_traverse_cb trav_fn,
  17895     void *user_data)
  17896 {
  17897     int rv = BCM_E_NONE, idx; 
  17898     _bcm_l3_tbl_t  *tbl_ptr;                        /* Unit ecmp table pointer. */
  17899     bcm_l3_ecmp_member_t *ecmp_member_array = NULL; /* Ecmp group from hw.    */
  17900 
  17901     /* Make sure unit supports multipath egress mode. */
  17902     BCM_IF_ERROR_RETURN(BCM_XGS3_L3_MPATH_EGRESS_UNSUPPORTED(unit));
  17903 
  17904     /* Input parameters check. */
  17905     if (NULL == trav_fn) {
  17906         return (BCM_E_PARAM);
  17907     }
  17908 
  17909     /* Check if unit supports ecmp. */
  17910     if (!BCM_XGS3_L3_ECMP_MAX_PATHS(unit)) {
  17911         return (BCM_E_NONE);
  17912     }
  17913 
  17914     /* Allocate ecmp group buffer. */
  17915     BCM_IF_ERROR_RETURN(
  17916         _bcm_xgs3_l3_ecmp_member_alloc(unit, &ecmp_member_array));
  17917 
  17918     tbl_ptr  = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  17919     idx = tbl_ptr->idx_min;
  17920 
  17921 #ifdef BCM_TRIDENT2_SUPPORT
  17922     /* In Trident2/Tomahawk, reserved indices for VP-LAG should not be reported */
  17923     if (soc_feature(unit, soc_feature_vp_lag)) {
  17924         idx = soc_property_get(unit, spn_MAX_VP_LAGS,
  17925                                soc_mem_index_count(unit, EGR_VPLAG_GROUPm));
  17926     }
  17927 #endif /* BCM_TRIDENT2_SUPPORT */
  17928 
  17929 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
  17930    /*
  17931     * TD2P has split indexes for overlay and underlay.
  17932     * vp lags are in second range for underlay domain.
  17933     * therefore skip indexes which are reserved for vp lag.
  17934     */
  17935     if ((tbl_ptr->split_idx > 0)) {
  17936         idx += tbl_ptr->split_idx; 
  17937 
  17938         /* traverse overlay indexes */    
  17939         rv = _bcm_xgs3_l3_ecmp_range_traverse(unit, tbl_ptr->idx_min,
  17940               tbl_ptr->split_maxused, tbl_ptr, ecmp_member_array, trav_fn, user_data);
  17941 
  17942         if (BCM_FAILURE(rv)) {
  17943             goto clean_up;
  17944         }
  17945     }
  17946 #endif
  17947 #if defined(BCM_TOMAHAWK3_SUPPORT)
  17948     if ((soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) &&
  17949             (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  17950             ecmp_mode_hierarchical)) {
  17951         tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp);
  17952 
  17953         idx = tbl_ptr->idx_min;
  17954 
  17955         /* traverse overlay indexes */
  17956         rv = _bcm_xgs3_l3_ecmp_range_traverse(unit, idx, tbl_ptr->idx_maxused, tbl_ptr,
  17957                                    ecmp_member_array, trav_fn, user_data);
  17958         tbl_ptr  = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  17959         idx = tbl_ptr->idx_min;
  17960     }
  17961 #endif
  17962     /* traverse underlay indexes */
  17963     rv = _bcm_xgs3_l3_ecmp_range_traverse(unit, idx, tbl_ptr->idx_maxused, tbl_ptr,
  17964                                    ecmp_member_array, trav_fn, user_data);
  17965     if (BCM_FAILURE(rv)) {
  17966         goto clean_up;
  17967     }
  17968 
  17969 clean_up:
  17970     if (ecmp_member_array) {
  17971         sal_free(ecmp_member_array);
  17972         ecmp_member_array = NULL;
  17973     }
  17974     return (rv);
  17975 }
  17976 
  17977 /*
  17978  * Function:
  17979  *      bcm_xgs3_host_to_route
  17980  * Purpose:
  17981  *      Service routine used to copy host data in a route format
  17982  * Parameters:
  17983  *      unit    - (IN)SOC unit number.
  17984  *      l3cfg   - (IN) Host information.
  17985  *      lpm_cfg - (OUT) Corresponding route info.
  17986  * Returns:
  17987  *      BCM_E_XXX
  17988  */
  17989 STATIC INLINE int
  17990 bcm_xgs3_host_to_route(int unit, _bcm_l3_cfg_t *l3cfg,
  17991                        _bcm_defip_cfg_t *lpm_cfg)
  17992 {
  17993     /* Input parameters check. */
  17994     if ((NULL == l3cfg) || (NULL == lpm_cfg)) {
  17995         return (BCM_E_PARAM);
  17996     }
  17997     /* Reset destination buffer. */
  17998     sal_memset(lpm_cfg, 0, sizeof(_bcm_defip_cfg_t));
  17999 
  18000     /* Prepare route entry. */
  18001     lpm_cfg->defip_flags = (l3cfg->l3c_flags | BCM_L3_HOST_AS_ROUTE);
  18002     lpm_cfg->defip_vrf = l3cfg->l3c_vrf;
  18003 
  18004     if (l3cfg->l3c_flags & BCM_L3_IP6)  {
  18005         sal_memcpy(lpm_cfg->defip_ip6_addr, l3cfg->l3c_ip6, sizeof(bcm_ip6_t));
  18006         lpm_cfg->defip_sub_len = BCM_XGS3_L3_IPV6_PREFIX_LEN;
  18007     } else {
  18008         lpm_cfg->defip_ip_addr =  l3cfg->l3c_ip_addr;
  18009         lpm_cfg->defip_sub_len = BCM_XGS3_L3_IPV4_PREFIX_LEN;
  18010     }
  18011     sal_memcpy(lpm_cfg->defip_mac_addr, l3cfg->l3c_mac_addr,
  18012                sizeof(bcm_mac_t));
  18013     lpm_cfg->defip_intf = l3cfg->l3c_intf;
  18014     lpm_cfg->defip_port_tgid = l3cfg->l3c_port_tgid;
  18015     lpm_cfg->defip_modid = l3cfg->l3c_modid;
  18016     lpm_cfg->defip_vid = l3cfg->l3c_vid;
  18017     return (BCM_E_NONE);
  18018 }
  18019 
  18020 /*
  18021  * Function:
  18022  *      bcm_xgs3_route_to_host
  18023  * Purpose:
  18024  *      Service routine used to copy route data in a host format
  18025  * Parameters:
  18026  *      unit    - (IN)SOC unit number.
  18027  *      lpm_cfg - (IN) Route info.
  18028  *      l3cfg   - (OUT) Host information.
  18029  * Returns:
  18030  *      BCM_E_XXX
  18031  */
  18032 STATIC INLINE int
  18033 bcm_xgs3_route_to_host(int unit, _bcm_defip_cfg_t *lpm_cfg,
  18034                        _bcm_l3_cfg_t *l3cfg)
  18035 {
  18036     /* Input parameters check. */
  18037     if ((NULL == l3cfg) || (NULL == lpm_cfg)) {
  18038         return (BCM_E_PARAM);
  18039     }
  18040 
  18041     /* Reset destination buffer. */
  18042     sal_memset(l3cfg, 0, sizeof(_bcm_l3_cfg_t));
  18043 
  18044     /* Prepare host entry. */
  18045     if (lpm_cfg->defip_flags & BCM_L3_IP6)  {
  18046         if (lpm_cfg->defip_sub_len != BCM_XGS3_L3_IPV6_PREFIX_LEN) {
  18047             return (BCM_E_NOT_FOUND);
  18048         }
  18049         sal_memcpy(l3cfg->l3c_ip6, lpm_cfg->defip_ip6_addr, sizeof(bcm_ip6_t));
  18050     } else {
  18051         if (lpm_cfg->defip_sub_len != BCM_XGS3_L3_IPV4_PREFIX_LEN) {
  18052             return (BCM_E_NOT_FOUND);
  18053         }
  18054         l3cfg->l3c_ip_addr = lpm_cfg->defip_ip_addr;
  18055     }
  18056 
  18057     l3cfg->l3c_flags = (lpm_cfg->defip_flags | BCM_L3_HOST_AS_ROUTE);
  18058     l3cfg->l3c_vrf = lpm_cfg->defip_vrf;
  18059 
  18060     sal_memcpy(l3cfg->l3c_mac_addr, lpm_cfg->defip_mac_addr,
  18061                sizeof(bcm_mac_t));
  18062     l3cfg->l3c_intf = lpm_cfg->defip_intf;
  18063     l3cfg->l3c_port_tgid = lpm_cfg->defip_port_tgid;
  18064     l3cfg->l3c_modid = lpm_cfg->defip_modid;
  18065     l3cfg->l3c_vid = lpm_cfg->defip_vid;
  18066     return (BCM_E_NONE);
  18067 }
  18068 
  18069 /*
  18070  * Function:
  18071  *      _bcm_xgs3_host_ecmp_del
  18072  * Purpose:
  18073  *      Delete IP host with multipaths from L3 entry table table
  18074  * Parameters:
  18075  *      unit          - (IN)SOC unit number.
  18076  *      _bcm_l3_cfg_t - (IN)Host Entry data.
  18077  *      ecmp_group_id - (IN)Ecmp group id.
  18078  * Returns:
  18079  *      BCM_E_XXX
  18080  */
  18081 STATIC int
  18082 _bcm_xgs3_host_ecmp_del(int unit, _bcm_l3_cfg_t *l3cfg,
  18083                          int ecmp_group_id)
  18084 {
  18085     int ecmp_count;             /* Next hop count in the group.       */
  18086     int *ecmp_grp;              /* Ecmp group from hw.                */
  18087     int rv;                     /* Internal operations status.        */
  18088 
  18089 
  18090     /* Input parameters check. */
  18091     /* ECMP support for Host Entries */
  18092     if (NULL == l3cfg ||
  18093         !soc_feature(unit, soc_feature_l3_host_ecmp_group)) {
  18094         return (BCM_E_PARAM);
  18095     }
  18096 
  18097     /* Only supported in egress mode */
  18098     if (!BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  18099         return BCM_E_UNAVAIL;
  18100     }
  18101 
  18102     /* Allocate ecmp group buffer. */
  18103     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp));
  18104 
  18105     /* Read ecmp group members from the hw. */
  18106     rv = _bcm_xgs3_ecmp_tbl_read(unit, ecmp_group_id,
  18107                                  ecmp_grp, &ecmp_count);
  18108     if (BCM_FAILURE(rv)) {
  18109         sal_free(ecmp_grp);
  18110         return (rv);
  18111     }
  18112 
  18113     /* Delete entry from  hw. */
  18114     if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_del)) {
  18115         BCM_XGS3_L3_MODULE_LOCK(unit);
  18116         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_del) (unit, l3cfg);
  18117         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  18118     } else {
  18119         sal_free(ecmp_grp);
  18120         return (BCM_E_UNAVAIL);
  18121     }
  18122 
  18123     
  18124     rv = bcm_xgs3_ecmp_group_del(unit, ecmp_group_id, 0);
  18125     sal_free(ecmp_grp);
  18126     return rv;
  18127 }
  18128 
  18129 
  18130 
  18131 /*
  18132  * Function:
  18133  *      bcm_xgs3_host_as_route
  18134  * Purpose:
  18135  *      Service routine used to operate host entry as route.
  18136  *      Host inserted as route in case host table is full.
  18137  * Parameters:
  18138  *      unit      - (IN) SOC unit number.
  18139  *      l3cfg     - (IN) Deleted host information.
  18140  *      operation - (IN) Host table operation.
  18141  *      orig_rv     (IN) Host as route is not supported on
  18142  *                       some devices/configurations.
  18143  * Returns:
  18144  *      BCM_E_XXX
  18145  */
  18146 int
  18147 bcm_xgs3_host_as_route(int unit, _bcm_l3_cfg_t *l3cfg,
  18148                        int operation, int orig_rv)
  18149 {
  18150     _bcm_defip_cfg_t lpm_cfg; /* Route info.             */
  18151     int retval;               /* Operation return value. */
  18152 
  18153     /* Input parameters check. */
  18154     if (NULL == l3cfg) {
  18155         return (BCM_E_PARAM);
  18156     }
  18157 
  18158     if (l3cfg->l3c_flags & BCM_L3_IP6) {
  18159         if (!soc_feature(unit, soc_feature_lpm_prefix_length_max_128) ||
  18160             !(soc_property_get(unit, spn_IPV6_LPM_128B_ENABLE, 1))) {
  18161             return (orig_rv);
  18162         }
  18163     } else {
  18164         if (BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) == 0) {
  18165             return (orig_rv);
  18166         }
  18167     }
  18168 
  18169     BCM_IF_ERROR_RETURN(bcm_xgs3_host_to_route(unit, l3cfg, &lpm_cfg));
  18170 
  18171     switch (operation){
  18172       case BCM_XGS3_L3_OP_GET:
  18173          retval = bcm_xgs3_defip_get(unit, &lpm_cfg);
  18174          if (BCM_SUCCESS(retval)) {
  18175             BCM_IF_ERROR_RETURN(bcm_xgs3_route_to_host(unit, &lpm_cfg, l3cfg));
  18176          }
  18177          break;
  18178       case BCM_XGS3_L3_OP_ADD:
  18179          retval = bcm_xgs3_defip_add(unit, &lpm_cfg);
  18180          break;
  18181       case BCM_XGS3_L3_OP_DEL:
  18182          retval = bcm_xgs3_defip_del(unit, &lpm_cfg);
  18183          break;
  18184       default:
  18185          retval = BCM_E_INTERNAL;
  18186     }
  18187     return (retval);
  18188 }
  18189 
  18190 
  18191 /*
  18192  * Function:
  18193  *      bcm_xgs3_l3_get
  18194  * Purpose:
  18195  *      Get an entry from L3 table.
  18196  * Parameters:
  18197  *      unit  - (IN)SOC unit number.
  18198  *      l3cfg - (IN/OUT)Structure to fill l3 entry information.
  18199  * Returns:
  18200  *      BCM_E_XXX
  18201  */
  18202 int
  18203 bcm_xgs3_l3_get(int unit, _bcm_l3_cfg_t *l3cfg)
  18204 {
  18205     int nh_idx;                 /* Next hop index.          */
  18206     int rv = BCM_E_UNAVAIL;     /* Operation return status. */
  18207 
  18208     /*  Make sure module was initialized. */
  18209     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  18210         return (BCM_E_INIT);
  18211     }
  18212 
  18213     /* Input parameters check */
  18214     if (NULL == l3cfg) {
  18215         return (BCM_E_PARAM);
  18216     }
  18217 
  18218     /* Check if address is multicast. */
  18219     if (BCM_XGS3_L3_MCAST_ENTRY(l3cfg)) {
  18220         /* Read multicast entry. */
  18221         if (BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_get)) {
  18222             BCM_XGS3_L3_MODULE_LOCK(unit);
  18223             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_get) (unit, l3cfg);
  18224             BCM_XGS3_L3_MODULE_UNLOCK(unit);
  18225         }
  18226     } else {
  18227         /* Unicast handling. */
  18228         /* Read l3 host entry. */
  18229         if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_get)) {
  18230             BCM_XGS3_L3_MODULE_LOCK(unit);
  18231             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get) (unit, l3cfg, &nh_idx);
  18232             BCM_XGS3_L3_MODULE_UNLOCK(unit);
  18233         }
  18234 
  18235         if (BCM_SUCCESS(rv)) {
  18236             BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_get_nh_info(unit, l3cfg, nh_idx));
  18237         } else if (((BCM_E_NOT_FOUND == rv) || (BCM_E_DISABLED == rv)) &&
  18238                    !soc_property_get(unit, spn_HOST_AS_ROUTE_DISABLE, 0)) {
  18239             rv = bcm_xgs3_host_as_route(unit, l3cfg, BCM_XGS3_L3_OP_GET, rv);
  18240             if (BCM_SUCCESS(rv)) {
  18241                 /* Special return value - as entry retrieved from ROUTE table */
  18242                 (void) bcm_xgs3_l3_host_as_route_return_get(unit, &rv);
  18243             }
  18244         }
  18245     }
  18246     return rv;
  18247 }
  18248 /*
  18249  * Function:
  18250  *      bcm_xgs3_l3_add
  18251  * Purpose:
  18252  *      Add an entry in L3 table.
  18253  * Parameters:
  18254  *      unit  - (IN)SOC unit number.
  18255  *      l3cfg - (IN)Structure with l3 entry information.
  18256  * Returns:
  18257  *      BCM_E_XXX
  18258  */
  18259 int
  18260 bcm_xgs3_l3_add(int unit, _bcm_l3_cfg_t *l3cfg)
  18261 {
  18262     int nh_idx;                 /* Next hop index.        */
  18263     int rv = BCM_E_UNAVAIL;     /* Operation return value */
  18264     int mpath = 0;              /* Multipath */
  18265 
  18266     /*  Make sure module was initialized. */
  18267     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  18268         return (BCM_E_INIT);
  18269     }
  18270 
  18271     /* Input parameters check */
  18272     if (NULL == l3cfg) {
  18273         return (BCM_E_PARAM);
  18274     }
  18275 
  18276     if (BCM_XGS3_L3_MCAST_ENTRY(l3cfg)) {
  18277         if (BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_add)) {
  18278             BCM_XGS3_L3_MODULE_LOCK(unit);
  18279             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_add) (unit, l3cfg);
  18280             BCM_XGS3_L3_MODULE_UNLOCK(unit);
  18281         } else {
  18282             return (BCM_E_UNAVAIL);
  18283         }
  18284     } else {
  18285         /* Multipath is only supported in Egress Switching Mode */
  18286         if (soc_feature(unit, soc_feature_l3_host_ecmp_group)) {
  18287             mpath = l3cfg->l3c_flags & BCM_L3_MULTIPATH;
  18288             if (mpath) {
  18289                 if (!BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  18290                     return BCM_E_UNAVAIL;
  18291                 }
  18292                 if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit,
  18293                                                         l3cfg->l3c_intf)) {
  18294                     return BCM_E_PARAM;
  18295                 }
  18296             }
  18297             if (!mpath &&
  18298                 BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, l3cfg->l3c_intf)) {
  18299                 return BCM_E_PARAM;
  18300             }
  18301         } else {
  18302             if (l3cfg->l3c_flags & BCM_L3_MULTIPATH) {
  18303                 return BCM_E_UNAVAIL;
  18304             }
  18305             if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, l3cfg->l3c_intf)) {
  18306                 return BCM_E_PARAM;
  18307             }
  18308         }
  18309 
  18310         if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) {
  18311             /* Trunk id validation. */
  18312             BCM_XGS3_L3_IF_INVALID_TGID_RETURN(unit, l3cfg->l3c_flags,
  18313                                                l3cfg->l3c_port_tgid);
  18314         }
  18315 
  18316         if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_get)) {
  18317             BCM_XGS3_L3_MODULE_LOCK(unit);
  18318             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get) (unit, l3cfg, NULL);
  18319             BCM_XGS3_L3_MODULE_UNLOCK(unit);
  18320         }
  18321 
  18322         /* Any reason why replace is not checked? */
  18323         BCM_XGS3_IF_ERROR_OR_ENTRY_EXISTS_RETURN(rv);
  18324         if (BCM_GPORT_IS_BLACK_HOLE(l3cfg->l3c_port_tgid) ||
  18325              (l3cfg->l3c_flags & BCM_L3_DST_DISCARD)) {
  18326              nh_idx = BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit);
  18327         } else {
  18328              /* Get next hop index. */
  18329              BCM_IF_ERROR_RETURN(_bcm_xgs3_nh_init_add(unit, l3cfg, NULL, &nh_idx));
  18330         }
  18331 
  18332 #ifdef BCM_TOMAHAWK_SUPPORT
  18333         if (soc_feature(unit, soc_feature_extended_view_no_trunk_support) &&
  18334             BCM_TD2_L3_USE_EMBEDDED_NEXT_HOP(unit, l3cfg->l3c_intf, nh_idx) &&
  18335             (l3cfg->l3c_flags & BCM_L3_TGID)) {
  18336             return BCM_E_UNAVAIL;
  18337         }
  18338 #endif /* BCM_TOMAHAWK_SUPPORT */
  18339 
  18340         /* Write entry to hw. */
  18341         l3cfg->l3c_hw_index = BCM_XGS3_L3_INVALID_INDEX;        /* Add /No overrite. */
  18342         if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_add)) {
  18343             BCM_XGS3_L3_MODULE_LOCK(unit);
  18344             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_add) (unit, l3cfg, nh_idx);
  18345             BCM_XGS3_L3_MODULE_UNLOCK(unit);
  18346         } else {
  18347             rv = BCM_E_UNAVAIL;
  18348         }
  18349 
  18350         /* Do best effort clean_up if needed. */
  18351         if (BCM_FAILURE(rv)) {
  18352             if (mpath) {
  18353                 /*    coverity[negative_returns : FALSE]    */
  18354                 bcm_xgs3_ecmp_group_del(unit, nh_idx, 0);
  18355             } else {
  18356                 bcm_xgs3_nh_del(unit, 0, nh_idx);
  18357             }
  18358         }
  18359         /* If l3 table full or disabled customer allowed to write */
  18360         /* the entry to lpm table.                                */
  18361         if (((BCM_E_FULL == rv) || (BCM_E_DISABLED == rv)) &&
  18362             (l3cfg->l3c_flags & BCM_L3_HOST_AS_ROUTE) &&
  18363             !soc_property_get(unit, spn_HOST_AS_ROUTE_DISABLE, 0)) {
  18364             rv = bcm_xgs3_host_as_route(unit, l3cfg, BCM_XGS3_L3_OP_ADD, rv);
  18365             if (BCM_SUCCESS(rv)) {
  18366                 /* Special return value - as entry added to ROUTE table */
  18367                 (void) bcm_xgs3_l3_host_as_route_return_get(unit, &rv);
  18368             }
  18369         }
  18370     }
  18371 
  18372     return rv;
  18373 }
  18374 
  18375 /*
  18376  * Function:
  18377  *      bcm_xgs3_l3_del
  18378  * Purpose:
  18379  *      Delete an entry in L3 table.
  18380  * Parameters:
  18381  *      unit - SOC unit number.
  18382  *      l3cfg - Pointer to memory for l3 table related information.
  18383  * Returns:
  18384  *      BCM_E_XXX
  18385  */
  18386 int
  18387 bcm_xgs3_l3_del(int unit, _bcm_l3_cfg_t *l3cfg)
  18388 {
  18389     int nh_idx;                 /* Next hop index.          */
  18390     int rv = BCM_E_UNAVAIL;     /* Operation return status. */
  18391 
  18392     /*  Make sure module was initialized. */
  18393     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  18394         return (BCM_E_INIT);
  18395     }
  18396 
  18397     /* Input parameters check */
  18398     if (NULL == l3cfg) {
  18399         return (BCM_E_PARAM);
  18400     }
  18401 
  18402     if (BCM_XGS3_L3_MCAST_ENTRY(l3cfg)) {
  18403         /* Delete entry from  hw. */
  18404         if (BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_del)) {
  18405             BCM_XGS3_L3_MODULE_LOCK(unit);
  18406             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_del) (unit, l3cfg);
  18407             BCM_XGS3_L3_MODULE_UNLOCK(unit);
  18408         }
  18409         BCM_IF_ERROR_RETURN(rv);
  18410     } else {
  18411         /* Read l3 host entry to get next hop index. */
  18412         if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_get)) {
  18413             BCM_XGS3_L3_MODULE_LOCK(unit);
  18414             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get) (unit, l3cfg, &nh_idx);
  18415             BCM_XGS3_L3_MODULE_UNLOCK(unit);
  18416         }
  18417 
  18418         if (((BCM_E_NOT_FOUND == rv) || (BCM_E_DISABLED == rv)) &&
  18419             !soc_property_get(unit, spn_HOST_AS_ROUTE_DISABLE, 0)) {
  18420             rv =  bcm_xgs3_host_as_route(unit, l3cfg, BCM_XGS3_L3_OP_DEL, rv);
  18421             if (BCM_SUCCESS(rv)) {
  18422                 /* Special return value - as entry deleted from ROUTE table */
  18423                 (void) bcm_xgs3_l3_host_as_route_return_get(unit, &rv);
  18424             }
  18425             return rv;
  18426         }
  18427         BCM_IF_ERROR_RETURN(rv);
  18428 
  18429         if (l3cfg->l3c_flags & BCM_L3_MULTIPATH) {
  18430             rv = _bcm_xgs3_host_ecmp_del(unit, l3cfg, nh_idx);
  18431         } else {
  18432             /* Delete entry from  hw. */
  18433             if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_del)) {
  18434                 BCM_XGS3_L3_MODULE_LOCK(unit);
  18435                 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_del) (unit, l3cfg);
  18436                 BCM_XGS3_L3_MODULE_UNLOCK(unit);
  18437             } else {
  18438                 return (BCM_E_UNAVAIL);
  18439             }
  18440 
  18441             /* Release next hop index. */
  18442             if(BCM_SUCCESS(rv)) {
  18443                 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_del(unit, 0, nh_idx));
  18444             }
  18445         }
  18446     }
  18447     return rv;
  18448 }
  18449 
  18450 /*
  18451  * Function:
  18452  *      _bcm_xgs3_l3_nh_intf_cmp
  18453  * Purpose:
  18454  *      Compare interface of next hop with a given interface index.
  18455  * Parameters:
  18456  *      unit      - (IN)SOC unit number.
  18457  *      ifindex   - (IN)Interface index.
  18458  *      nh_idx    - (IN)Next hop index.
  18459  *      cmp_result- (OUT)Comparison result.
  18460  * Returns:
  18461  *      BCM_E_XXX
  18462  */
  18463 int
  18464 _bcm_xgs3_l3_nh_intf_cmp(int unit, int ifindex, int nh_idx, int *cmp_result)
  18465 {
  18466     bcm_l3_egress_t nh_info;  /* Next hop info buffer.    */
  18467 
  18468     /* If next hop is trap to cpu - don't read nh table. */
  18469     if (nh_idx == BCM_XGS3_L3_L2CPU_NH_IDX(unit)) {
  18470         *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  18471         return (BCM_E_NONE);
  18472     }
  18473 
  18474     /* Get next hop entry from hw. */
  18475     BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, nh_idx, &nh_info));
  18476 
  18477     if (ifindex != nh_info.intf) {
  18478         *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  18479     } else {
  18480         *cmp_result = BCM_L3_CMP_EQUAL;
  18481     }
  18482     return (BCM_E_NONE);
  18483 }
  18484 
  18485 /*
  18486  * Function:
  18487  *      _bcm_xgs3_l3_prefix_cmp
  18488  * Purpose:
  18489  *      Compare prefix & vrf of l3 entry.
  18490  * Parameters:
  18491  *      unit      - (IN)SOC unit number.
  18492  *      pattern   - (IN)Match pattern.
  18493  *      data1     - (IN)L3 entry.
  18494  *      data2     - UNUSED.
  18495  *      cmp_result- (OUT)Comparison result.
  18496  * Returns:
  18497  *      BCM_E_XXX
  18498  */
  18499 static INLINE int
  18500 _bcm_xgs3_l3_prefix_cmp(int unit, void *pattern,
  18501                         void *data1, void *data2, int *cmp_result)
  18502 {
  18503     int idx;                    /* Iteration index.              */
  18504     int ipv6;                   /* ipv6 entry flag.              */
  18505 
  18506     _bcm_l3_cfg_t *l3_entry = (_bcm_l3_cfg_t *) data1;
  18507     _bcm_l3_cfg_t *l3cfg = (_bcm_l3_cfg_t *) pattern;
  18508 
  18509     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
  18510 
  18511     if (l3_entry->l3c_vrf != l3cfg->l3c_vrf) {
  18512         *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  18513         return (BCM_E_NONE);
  18514     }
  18515 
  18516     if (ipv6) {
  18517         /* Compare ipv6 ip address. */
  18518         for (idx = 0; idx < BCM_IP6_ADDRLEN; idx++) {
  18519             /* coverity[copy_paste_error : FALSE] */
  18520             if ((l3_entry->l3c_ip6[idx] & l3cfg->l3c_ip6_mask[idx]) !=
  18521                 (l3cfg->l3c_ip6[idx] & l3cfg->l3c_ip6_mask[idx])) {
  18522                 *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  18523                 return (BCM_E_NONE);
  18524             }
  18525         }
  18526     } else {
  18527         /* Compare ipv4 ip address. */
  18528         if ((l3_entry->l3c_ip_addr & l3cfg->l3c_ip_mask) !=
  18529             (l3cfg->l3c_ip_addr & l3cfg->l3c_ip_mask)) {
  18530             *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  18531             return (BCM_E_NONE);
  18532         }
  18533     }
  18534     *cmp_result = BCM_L3_CMP_EQUAL;
  18535     return (BCM_E_NONE);
  18536 
  18537 }
  18538 
  18539 /*
  18540  * Function:
  18541  *      _bcm_xgs3_l3_intf_cmp
  18542  * Purpose:
  18543  *      Compare l3 entry interface with a given interface id.
  18544  * Parameters:
  18545  *      unit      - (IN)SOC unit number.
  18546  *      pattern   - (IN)Match pattern (interface id & negate).
  18547  *      data1     - UNUSED.
  18548  *      data2     - (IN)Next hop index.
  18549  *      cmp_result- (OUT)Comparison result.
  18550  *
  18551  * Returns:
  18552  *      BCM_E_XXX
  18553  */
  18554 int
  18555 _bcm_xgs3_l3_intf_cmp(int unit, void *pattern, void *data1,
  18556                       void *data2, int *cmp_result)
  18557 {
  18558     _bcm_if_del_pattern_t *trv_data;    /* Interface & negate combination. */
  18559     int if_cmp_result;                  /* Interface comparison return.   */
  18560     int nh_idx = *(int *)data2;         /* Next hop index.                */
  18561     _bcm_l3_cfg_t *l3cfg_info = NULL;
  18562 
  18563     trv_data = (_bcm_if_del_pattern_t *) pattern;
  18564 
  18565     COMPILER_REFERENCE(l3cfg_info);
  18566 #ifdef BCM_TRIDENT3_SUPPORT
  18567     l3cfg_info = (_bcm_l3_cfg_t *) data1;
  18568     if (soc_feature(unit, soc_feature_flex_flow) &&
  18569        (l3cfg_info->l3c_flow_handle)) {
  18570         if ((l3cfg_info->l3c_flags & BCM_L3_IPMC)) {
  18571             /*Flex flow L3 Entry IPMC cannot be deleted by
  18572              * l3c_intf */
  18573             *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  18574             return BCM_E_NONE;
  18575         }
  18576     }
  18577 #endif /* BCM_TRIDENT3_SUPPORT */
  18578 #ifdef BCM_TRIUMPH3_SUPPORT
  18579     if (nh_idx == BCM_XGS3_L3_INVALID_INDEX &&
  18580         soc_feature(unit, soc_feature_l3_extended_host_entry)) {
  18581         l3cfg_info = (_bcm_l3_cfg_t *) data1;
  18582         if (l3cfg_info->l3c_intf == trv_data->l3_intf) {
  18583             if_cmp_result = BCM_L3_CMP_EQUAL;
  18584         } else {
  18585             if_cmp_result = BCM_L3_CMP_NOT_EQUAL;
  18586         }
  18587     } else
  18588 #endif /* BCM_TRIUMPH3_SUPPORT */
  18589     {
  18590 
  18591         /*    coverity[negative_returns : FALSE]    */
  18592         BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_nh_intf_cmp(unit, trv_data->l3_intf,
  18593                                                      nh_idx, &if_cmp_result));
  18594     }
  18595 
  18596     /* Calculate final result based on negate and interface index comparison. */
  18597     if (BCM_XGS3_L3_IS_EQUAL(if_cmp_result, trv_data->negate)) {
  18598         *cmp_result = BCM_L3_CMP_EQUAL;
  18599     } else {
  18600         *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  18601     }
  18602     return (BCM_E_NONE);
  18603 }
  18604 
  18605 /*
  18606  * Function:
  18607  *      _bcm_xgs3_l3_cmp_hit
  18608  * Purpose:
  18609  *      Check l3 entry hit bit.
  18610  * Parameters:
  18611  *      unit      - (IN)SOC unit number.
  18612  *      pattern   - (IN)Match pattern (l3cfg hit flag)
  18613  *      data1     - (IN)L3 entry.
  18614  *      data2     - UNUSED.
  18615  *      cmp_result- (OUT)Comparison result.
  18616  * Returns:
  18617  *      BCM_E_XXX
  18618  */
  18619 static INLINE int
  18620 _bcm_xgs3_l3_cmp_hit(int unit, void *pattern, void *data1,
  18621                      void *data2, int *cmp_result)
  18622 {
  18623     uint32 flags = *(uint32 *)pattern;
  18624     _bcm_l3_cfg_t *l3cfg = (_bcm_l3_cfg_t *) data1;
  18625     int nh_idx = 0;
  18626 
  18627     COMPILER_REFERENCE(nh_idx);
  18628 #ifdef BCM_TRIUMPH3_SUPPORT
  18629     nh_idx = *(int *)data2;
  18630     if (nh_idx == BCM_XGS3_L3_INVALID_INDEX &&
  18631         soc_feature(unit, soc_feature_l3_extended_host_entry)) {
  18632         *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  18633         return (BCM_E_NONE);
  18634     } else
  18635 #endif /* BCM_TRIUMPH3_SUPPORT */
  18636     {
  18637         /* If compare function provided match the entry against pattern */
  18638         if ((flags & BCM_L3_HIT_CLEAR) && (l3cfg->l3c_flags & BCM_L3_HIT)) {
  18639             *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  18640             return (BCM_E_NONE);
  18641         }
  18642     }
  18643 
  18644     /* Unused entry -> matches "not hit" pattern. */
  18645     *cmp_result = BCM_L3_CMP_EQUAL;
  18646     return (BCM_E_NONE);
  18647 }
  18648 
  18649 /*
  18650  * Function:
  18651  *      _bcm_xgs3_host_ent_init
  18652  * Purpose:
  18653  *      Fill host entry for callbacks.
  18654  * Parameters:
  18655  *      unit      - (IN)SOC unit number.
  18656  *      l3cfg    -  (IN)L3 entry info.
  18657  *      nh_valid -  (IN)Flag indicates passed next hop info is valid.
  18658  *      host_info - (OUT)Buffer to be filled.
  18659  * Returns:
  18660  *      void
  18661  */
  18662 void
  18663 _bcm_xgs3_host_ent_init(int unit, _bcm_l3_cfg_t *l3cfg, int nh_valid,
  18664                         bcm_l3_host_t *host_info)
  18665 {
  18666 
  18667     /* Input parameters sanity. */
  18668     if ((NULL == host_info) || (NULL == l3cfg)) {
  18669         return;
  18670     }
  18671 
  18672     /* Init host entry. */
  18673     bcm_l3_host_t_init(host_info);
  18674 
  18675     /* Set vrf. */
  18676     host_info->l3a_vrf = l3cfg->l3c_vrf;
  18677 
  18678     /* Set ip address. */
  18679     if (l3cfg->l3c_flags & BCM_L3_IP6) {
  18680         sal_memcpy(host_info->l3a_ip6_addr, l3cfg->l3c_ip6, sizeof(bcm_ip6_t));
  18681     } else {
  18682         host_info->l3a_ip_addr = l3cfg->l3c_ip_addr;
  18683     }
  18684     /* Set flags. */
  18685     host_info->l3a_flags = l3cfg->l3c_flags;
  18686 
  18687     /* For devices that support the overlaid_address_range, if the RPE
  18688        field is '0', the 4 bits of PRI are the upper 4 bits
  18689        (of total 10 bits) of the classId, the lower 6 come from classId
  18690        as usual, for rest of the cases, the classID and PRI are copied
  18691        over directly.
  18692     */
  18693     if (soc_feature(unit, soc_feature_overlaid_address_class) &&
  18694         !BCM_L3_RPE_SET(l3cfg->l3c_flags)) {
  18695             host_info->l3a_lookup_class = ((l3cfg->l3c_prio & 0xF) << 6);
  18696             host_info->l3a_lookup_class |= (l3cfg->l3c_lookup_class & 0x3F);
  18697     } else {
  18698         host_info->l3a_lookup_class = l3cfg->l3c_lookup_class;
  18699     }
  18700 
  18701     if (nh_valid) {
  18702         /* Set mac address. */
  18703         sal_memcpy(host_info->l3a_nexthop_mac, l3cfg->l3c_mac_addr,
  18704                    sizeof(bcm_mac_t));
  18705         /* Set module id. */
  18706         host_info->l3a_modid = l3cfg->l3c_modid;
  18707         /* Set port/trunk id. */
  18708         host_info->l3a_port_tgid = l3cfg->l3c_port_tgid;
  18709         /* Set interface index. */
  18710         host_info->l3a_intf = l3cfg->l3c_intf;
  18711     }
  18712 }
  18713 
  18714 /*
  18715  * Function:
  18716  *      _bcm_xgs3_trvrs_flags_cmp
  18717  * Purpose:
  18718  *      Service routine used to compare l3 entry flags with
  18719  *      travers input parameters and update iteration index accordingly.
  18720  * Parameters:
  18721  *      unit      - (IN)SOC unit number.
  18722  *      req_flags - (IN)Travers request flags.
  18723  *      ent_flags - (IN)Entry flags.
  18724  *      idx       - (OUT)Traverse index.
  18725  * Returns:
  18726  *      BCM_L3_CMP_EQUAL if flags match
  18727  *      BCM_L3_CMP_NOT_EQUAL otherwise.
  18728  */
  18729 int
  18730 _bcm_xgs3_trvrs_flags_cmp(int unit, int req_flags, int ent_flags, int *idx)
  18731 {
  18732     /* If protocol doesn't match skip the entry. */
  18733     if (req_flags & BCM_L3_IP6) {
  18734         if (!(ent_flags & BCM_L3_IP6)) {
  18735             return (BCM_L3_CMP_NOT_EQUAL);
  18736         }
  18737     } else if (ent_flags & BCM_L3_IP6) {
  18738 #ifdef BCM_FIREBOLT_SUPPORT
  18739         BCM_XGS3_INC_IF_FIREBOLT(unit, (*idx));
  18740 #endif /* BCM_FIREBOLT_SUPPORT */
  18741         return (BCM_L3_CMP_NOT_EQUAL);
  18742     }
  18743 
  18744     /* Check ipmc flag. */
  18745     if ((!(req_flags & BCM_L3_IPMC)) && (ent_flags & BCM_L3_IPMC)) {
  18746 #ifdef BCM_FIREBOLT_SUPPORT
  18747         if (req_flags & BCM_L3_IP6) {
  18748             BCM_XGS3_INC_IF_FIREBOLT(unit, (*idx));
  18749         }
  18750 #endif /* BCM_FIREBOLT_SUPPORT */
  18751         return (BCM_L3_CMP_NOT_EQUAL);
  18752     }
  18753     return (BCM_L3_CMP_EQUAL);
  18754 }
  18755 
  18756 /*
  18757  * Function:
  18758  *      _bcm_xgs3_l3_del_match
  18759  * Purpose:
  18760  *      Delete an entry in L3 table matches a certain rule.
  18761  * Parameters:
  18762  *      unit      - (IN)SOC unit number.
  18763  *      flags.    - (IN)Generic l3 flags.
  18764  *      pattern   - (IN)Comparison match argurment.
  18765  *      cmp_func  - (IN)Comparison function.
  18766  *      notify_cb - (IN)Delete notification callback.
  18767  *      user_data - (IN)User provided cookie for callback.
  18768  * Returns:
  18769  *      BCM_E_XXX
  18770  */
  18771 STATIC int
  18772 _bcm_xgs3_l3_del_match(int unit, int flags, void *pattern,
  18773                        bcm_xgs3_ent_op_cb cmp_func,
  18774                        bcm_l3_host_traverse_cb notify_cb, void *user_data)
  18775 {
  18776     _bcm_l3_cfg_t l3cfg;        /* Hw entry info.                  */
  18777     bcm_l3_host_t info;         /* Host cb buffer.                 */
  18778     int cmp_result;             /* Compare against pattern result. */
  18779     soc_mem_t mem;              /* Table memory.                   */
  18780     int idx_max;                /* Maximum iteration index.        */
  18781     int idx_min;                /* Minimum iteration index.        */
  18782     int nh_idx;                 /* Next hop index.                 */
  18783     int ipv6;                   /* IPv6/IPv4 lookup flag.          */
  18784     int idx;                    /* Iteration index.                */
  18785     int rv;                     /* Operation return value.         */
  18786 
  18787 
  18788     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, l3_get_by_idx)) {
  18789         return (BCM_E_UNAVAIL);
  18790     }
  18791     /* Init iteration parameters. */
  18792 
  18793     /* Check Protocol. */
  18794     ipv6 = (flags & BCM_L3_IP6) ? TRUE : FALSE;
  18795 
  18796     /* Get table boundaries. */
  18797 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \
  18798     defined(BCM_HAWKEYE_SUPPORT)
  18799     if (soc_feature(unit, soc_feature_fp_based_routing)) {
  18800         /* Table is not present on this device. */
  18801         idx_min = 1;
  18802         idx_max = BCM_XGS3_L3_RP_MAX_PREFIXES(unit);
  18803     } else
  18804 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */
  18805     {
  18806         /* Get table memory. */
  18807         mem = (ipv6) ? BCM_XGS3_L3_MEM(unit, v6) : BCM_XGS3_L3_MEM(unit, v4);
  18808         idx_max = soc_mem_index_max(unit, mem);
  18809         idx_min =  soc_mem_index_min(unit, mem);
  18810     }
  18811 
  18812     /* Iterate over all the entries - delete matching ones. */
  18813     for (idx = idx_min; idx <= idx_max; idx++) {
  18814 
  18815         sal_memset(&l3cfg, 0, sizeof(l3cfg));
  18816         /* Set protocol. */
  18817         l3cfg.l3c_flags = flags;
  18818 
  18819         /* Get entry from  hw. */
  18820         BCM_XGS3_L3_MODULE_LOCK(unit);
  18821         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get_by_idx) (unit, NULL, idx,
  18822                                                            &l3cfg, &nh_idx);
  18823         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  18824 
  18825         /* Check for read errors & invalid entries. */
  18826         if (rv < 0) {
  18827             if (rv != BCM_E_NOT_FOUND) {
  18828                 return rv;
  18829             }
  18830             continue;
  18831         }
  18832 
  18833  #if defined(BCM_TRIDENT3_SUPPORT)
  18834         if (soc_feature(unit, soc_feature_flex_flow)
  18835             && (l3cfg.l3c_flow_handle)
  18836             && (l3cfg.l3c_flags & BCM_L3_IPMC))  {
  18837             LOG_VERBOSE(BSL_LS_BCM_L3,
  18838                        (BSL_META_U(unit,
  18839                    "L3 host: IPMC do not compare the l3 entry flags.")));
  18840             if (BCM_L3_CMP_EQUAL !=
  18841                 _bcm_td3_l3_flex_entry_flags_cmp(unit, flags, l3cfg.l3c_flags, &idx)) {
  18842                 continue;
  18843             }
  18844         } else
  18845 #endif /* BCM_TRIDENT3_SUPPORT */
  18846         {
  18847             /* Check read entry flags & update index accordingly. */
  18848             if (BCM_L3_CMP_EQUAL !=
  18849                 _bcm_xgs3_trvrs_flags_cmp(unit, flags, l3cfg.l3c_flags, &idx)) {
  18850                 continue;
  18851             }
  18852         }
  18853 
  18854         /* If compare function provided match the entry against pattern */
  18855         if (cmp_func) {
  18856             BCM_IF_ERROR_RETURN((*cmp_func) (unit, pattern, (void *)&l3cfg,
  18857                                              (void *)&nh_idx, &cmp_result));
  18858             /* If entry doesn't match the pattern don't delete it. */
  18859             if (BCM_L3_CMP_EQUAL != cmp_result) {
  18860                 continue;
  18861             }
  18862         }
  18863 
  18864         /* Entry matches the rule -> delete it. */
  18865         BCM_IF_ERROR_RETURN(bcm_xgs3_l3_del(unit, &l3cfg));
  18866 
  18867         /* Update ECMP refernce count */
  18868         if (l3cfg.l3c_flags & BCM_L3_MULTIPATH) {
  18869             if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  18870                 rv = _bcm_xgs3_host_ecmp_del(unit, &l3cfg, nh_idx);
  18871             }
  18872         }
  18873 
  18874         /* Check if notification required. */
  18875         if (notify_cb) {
  18876             /* Fill host info. */
  18877             _bcm_xgs3_host_ent_init(unit, &l3cfg, FALSE, &info);
  18878             /* Call notification callback. */
  18879             (*notify_cb) (unit, idx, &info, user_data);
  18880         }
  18881     }
  18882     return (BCM_E_NONE);
  18883 }
  18884 
  18885 
  18886 /*
  18887  * Function:
  18888  *      bcm_xgs3_l3_del_prefix
  18889  * Purpose:
  18890  *      Delete an entry in L3 table.
  18891  * Parameters:
  18892  *      unit  - (IN)SOC unit number.
  18893  *      l3cfg - (IN)Pointer to memory for l3 table related information.
  18894  * Returns:
  18895  *      BCM_E_XXX
  18896  */
  18897 int
  18898 bcm_xgs3_l3_del_prefix(int unit, _bcm_l3_cfg_t *l3cfg)
  18899 {
  18900     int rv;
  18901     /*  Make sure module was initialized. */
  18902     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  18903         return (BCM_E_INIT);
  18904     }
  18905 
  18906     /* Input parameters check */
  18907     if (NULL == l3cfg) {
  18908         return (BCM_E_PARAM);
  18909     }
  18910 
  18911     BCM_XGS3_L3_MODULE_LOCK(unit);
  18912     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_del_match)
  18913                                (unit, l3cfg->l3c_flags,
  18914                                 (void *)l3cfg,
  18915                                 _bcm_xgs3_l3_prefix_cmp,
  18916                                 NULL, NULL);
  18917     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  18918     return rv;
  18919 }
  18920 
  18921 /*
  18922  * Function:
  18923  *      bcm_xgs3_l3_del_intf
  18924  * Purpose:
  18925  *      Delete all the entries in L3 table with nh matching a certain
  18926  *      interface.
  18927  * Parameters:
  18928  *      unit   - (IN)SOC unit number.
  18929  *      l3cfg  - (IN)Pointer to memory for l3 table related information.
  18930  *      negate - (IN)0 means interface match; 1 means not match
  18931  * Returns:
  18932  *      BCM_E_XXX
  18933  */
  18934 int
  18935 bcm_xgs3_l3_del_intf(int unit, _bcm_l3_cfg_t *l3cfg, int negate)
  18936 {
  18937     _bcm_if_del_pattern_t pattern;      /* Interface & negate combination
  18938                                            to be used for every l3 entry
  18939                                            comparision.                  */
  18940     bcm_l3_egress_t egr;                /* Egress object.                */
  18941     int nh_index;                       /* Next hop index.               */
  18942     bcm_if_t intf;                      /* Deleted interface id.         */
  18943     int tmp_rv;                         /* First error occured.          */
  18944     int rv;                             /* Operation return status.      */
  18945 
  18946     /*  Make sure module was initialized. */
  18947     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  18948         return (BCM_E_INIT);
  18949     }
  18950 
  18951     /* Input parameters check */
  18952     if (NULL == l3cfg) {
  18953         return (BCM_E_PARAM);
  18954     }
  18955 
  18956     intf = l3cfg->l3c_intf;
  18957 
  18958     /* Check l3 switching mode. */
  18959     if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  18960         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf) ||
  18961             BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) {
  18962             if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) {
  18963                 nh_index = intf - BCM_XGS3_EGRESS_IDX_MIN(unit);
  18964             } else {
  18965                 nh_index = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  18966             }
  18967             /* Get egress object information. */
  18968             BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, nh_index, &egr));
  18969             /* Use egress object interface for iteration */
  18970             intf = egr.intf;
  18971         }
  18972     }
  18973 
  18974     pattern.l3_intf = intf;
  18975     pattern.negate = negate;
  18976 
  18977     /* Delete all ipv4 entries matching the interface. */
  18978     tmp_rv = _bcm_xgs3_l3_del_match(unit, 0, (void *)&pattern,
  18979                                     _bcm_xgs3_l3_intf_cmp, NULL, NULL);
  18980 
  18981     /* Delete all ipv6 entries matching the interface. */
  18982     rv = _bcm_xgs3_l3_del_match(unit, BCM_L3_IP6, (void *)&pattern,
  18983                                 _bcm_xgs3_l3_intf_cmp, NULL, NULL);
  18984     return (tmp_rv < 0) ? tmp_rv : rv;
  18985 }
  18986 
  18987 /*
  18988  * Function:
  18989  *      bcm_xgs3_l3_del_all
  18990  * Purpose:
  18991  *      Delete all entries in L3 table.
  18992  * Parameters:
  18993  *      unit - (IN)SOC unit number.
  18994  * Returns:
  18995  *      BCM_E_XXX
  18996  */
  18997 int
  18998 bcm_xgs3_l3_del_all(int unit)
  18999 {
  19000     int tmp_rv;         /* First error occured.          */
  19001     int rv;             /* Operation return status.      */
  19002 
  19003     /*  Make sure module was initialized. */
  19004     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  19005         return (BCM_E_INIT);
  19006     }
  19007 
  19008     /* Delete all ipv4 entries. */
  19009     BCM_XGS3_L3_MODULE_LOCK(unit);
  19010     tmp_rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_del_match)
  19011                        (unit, 0, NULL, NULL, NULL, NULL);
  19012 
  19013     /* Delete all ipv6 entries. */
  19014     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_del_match)
  19015                    (unit, BCM_L3_IP6, NULL, NULL, NULL, NULL);
  19016 
  19017     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  19018 
  19019     return (tmp_rv < 0) ? tmp_rv : rv;
  19020 }
  19021 
  19022 /*
  19023  * Function:
  19024  *      bcm_xgs3_l3_age
  19025  * Purpose:
  19026  *      Age out the l3 entry based on L3SH, L3DH or both.
  19027  * Parameters:
  19028  *      unit      - (IN)SOC unit number.
  19029  *      flags     - (IN)The criteria used to age or reset entry hit .
  19030  *      age_out   - (IN)Call back routine.
  19031  *      user_data - (IN)User provided cookie for callback.
  19032  * Returns:
  19033  *      BCM_E_XXX.
  19034  */
  19035 int
  19036 bcm_xgs3_l3_age(int unit, uint32 flags, bcm_l3_host_traverse_cb age_out,
  19037                 void *user_data)
  19038 {
  19039     int tmp_rv;         /* First error occured.          */
  19040     int rv;             /* Operation return status.      */
  19041 
  19042     /*  Make sure module was initialized. */
  19043     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  19044         return (BCM_E_INIT);
  19045     }
  19046 
  19047     /* Reset set flags to reset hit if required.  */
  19048     /* SEEMS LIKE API INCONSISTENCY. */
  19049     if (flags & BCM_L3_HIT) {
  19050         flags = BCM_L3_HIT_CLEAR;
  19051     }
  19052 
  19053     BCM_XGS3_L3_MODULE_LOCK(unit);
  19054     /* Age all ipv4 entries. */
  19055     tmp_rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_del_match)
  19056                                      (unit, flags, (void *)&flags,
  19057                                       _bcm_xgs3_l3_cmp_hit, age_out, user_data);
  19058 
  19059     /* Age all ipv6 entries. */
  19060     flags |= BCM_L3_IP6;
  19061     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_del_match)
  19062                                  (unit, flags, (void *)&flags,
  19063                                   _bcm_xgs3_l3_cmp_hit, age_out, user_data);
  19064 
  19065     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  19066 
  19067     return (tmp_rv < 0) ? tmp_rv : rv;
  19068 }
  19069 
  19070 /*
  19071  * Function:
  19072  *      bcm_xgs3_l3_replace
  19073  * Purpose:
  19074  *      Replace an entry in L3 table.
  19075  * Parameters:
  19076  *      unit -  (IN)SOC unit number.
  19077  *      l3cfg - (IN)L3 entry information.
  19078  * Returns:
  19079  *      BCM_E_XXX
  19080  */
  19081 int
  19082 bcm_xgs3_l3_replace(int unit, _bcm_l3_cfg_t *l3cfg)
  19083 {
  19084     _bcm_l3_cfg_t entry;        /* Original l3 entry.             */
  19085     int nh_idx_old;             /* Original entry next hop index. */
  19086     int nh_idx_new;             /* New allocated next hop index   */
  19087     int rv = BCM_E_UNAVAIL;     /* Operation return status.       */
  19088 
  19089     /*  Make sure module was initialized. */
  19090     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  19091         return (BCM_E_INIT);
  19092     }
  19093 
  19094     /* Input parameters check. */
  19095     if (NULL == l3cfg) {
  19096         return (BCM_E_PARAM);
  19097     }
  19098 
  19099     /* Set lookup key. */
  19100     entry = *l3cfg;
  19101 
  19102     if (BCM_XGS3_L3_MCAST_ENTRY(l3cfg)) {
  19103         /* ipmc_get here is to retrieve base flex counter id
  19104            previous attached if any */
  19105         if (BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_get)) {
  19106             BCM_XGS3_L3_MODULE_LOCK(unit);
  19107             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_get) (unit, &entry);
  19108             if (BCM_E_NONE == rv) {
  19109                 l3cfg->l3c_flex_ctr_base_id = entry.l3c_flex_ctr_base_id;
  19110                 l3cfg->l3c_flex_ctr_mode = entry.l3c_flex_ctr_mode;
  19111                 l3cfg->l3c_flex_ctr_pool = entry.l3c_flex_ctr_pool;
  19112             }
  19113             BCM_XGS3_L3_MODULE_UNLOCK(unit);
  19114         } else {
  19115             return (BCM_E_UNAVAIL);
  19116         }
  19117         if (BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_add)) {
  19118             BCM_XGS3_L3_MODULE_LOCK(unit);
  19119             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_add) (unit, l3cfg);
  19120             BCM_XGS3_L3_MODULE_UNLOCK(unit);
  19121         } else {
  19122             return (BCM_E_UNAVAIL);
  19123         }
  19124     } else {
  19125         if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) {
  19126             /* Trunk id validation. */
  19127             BCM_XGS3_L3_IF_INVALID_TGID_RETURN(unit, l3cfg->l3c_flags,
  19128                                                l3cfg->l3c_port_tgid);
  19129         }
  19130 
  19131         if ((l3cfg->l3c_flags & BCM_L3_MULTIPATH) &&
  19132             (!soc_feature(unit, soc_feature_l3_host_ecmp_group))) {
  19133             return BCM_E_UNAVAIL;
  19134         }
  19135 
  19136         /* Check if identical entry exits. */
  19137         if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_get)) {
  19138             BCM_XGS3_L3_MODULE_LOCK(unit);
  19139             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get) (unit, &entry,
  19140                                                         &nh_idx_old);
  19141             BCM_XGS3_L3_MODULE_UNLOCK(unit);
  19142         }
  19143         if (((BCM_E_NOT_FOUND == rv) || (BCM_E_DISABLED == rv)) &&
  19144             !soc_property_get(unit, spn_HOST_AS_ROUTE_DISABLE, 0)) {
  19145             rv =  bcm_xgs3_host_as_route(unit, l3cfg, BCM_XGS3_L3_OP_ADD, rv);
  19146             if (BCM_SUCCESS(rv)) {
  19147                 /* Special return value - as entry Replaced within ROUTE table */
  19148                 (void) bcm_xgs3_l3_host_as_route_return_get(unit, &rv);
  19149             }
  19150             return rv;
  19151         } else if (BCM_FAILURE(rv)) {
  19152             return rv;
  19153         }
  19154 
  19155         if (BCM_GPORT_IS_BLACK_HOLE(l3cfg->l3c_port_tgid)) {
  19156              nh_idx_new = 0;
  19157         } else {
  19158               /* Get next hop index. */
  19159               BCM_IF_ERROR_RETURN
  19160                    (_bcm_xgs3_nh_init_add(unit, l3cfg, NULL, &nh_idx_new));
  19161         }
  19162 
  19163 #ifdef BCM_TOMAHAWK_SUPPORT
  19164         if (soc_feature(unit, soc_feature_extended_view_no_trunk_support) &&
  19165             BCM_TD2_L3_USE_EMBEDDED_NEXT_HOP(unit, l3cfg->l3c_intf, nh_idx_new) &&
  19166             (l3cfg->l3c_flags & BCM_L3_TGID)) {
  19167             return BCM_E_UNAVAIL;
  19168         }
  19169 #endif /* BCM_TOMAHAWK_SUPPORT */
  19170 
  19171         /* Write entry to hw. */
  19172         l3cfg->l3c_hw_index = entry.l3c_hw_index; /*Replacement index & flag. */
  19173         if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_add)) {
  19174             BCM_XGS3_L3_MODULE_LOCK(unit);
  19175             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_add)(unit, l3cfg, nh_idx_new);
  19176             BCM_XGS3_L3_MODULE_UNLOCK(unit);
  19177         } else {
  19178             rv = BCM_E_UNAVAIL;
  19179         }
  19180 
  19181         /* Do best effort clean_up if needed. */
  19182         if (BCM_FAILURE(rv)) {
  19183             if (l3cfg->l3c_flags & BCM_L3_MULTIPATH) {
  19184                 /*    coverity[negative_returns : FALSE]    */
  19185                 bcm_xgs3_ecmp_group_del(unit, nh_idx_new, 0);
  19186             } else {
  19187                 bcm_xgs3_nh_del(unit, 0, nh_idx_new);
  19188             }
  19189         } else {
  19190             /* Free original next hop index. */
  19191             if (entry.l3c_flags & BCM_L3_MULTIPATH) {
  19192                 BCM_IF_ERROR_RETURN(
  19193                     bcm_xgs3_ecmp_group_del(unit, nh_idx_old, 0));
  19194             } else {
  19195                 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_del(unit, 0, nh_idx_old));
  19196             }
  19197         }
  19198     }
  19199     return rv;
  19200 }
  19201 
  19202 /*
  19203  * Function:
  19204  *      _bcm_xgs3_l3_traverse
  19205  * Purpose:
  19206  *      Walk over range of entries in l3 in the table.
  19207  * Parameters:
  19208  *      unit - SOC unit number.
  19209  *      flags - L3 entry flags to match during traverse.
  19210  *      start - First index to read.
  19211  *      end - Last index to read.
  19212  *      cb  - Caller notification callback.
  19213  *      user_data - User cookie, which should be returned in cb.
  19214  * Returns:
  19215  *      BCM_E_XXX
  19216  */
  19217 STATIC int
  19218 _bcm_xgs3_l3_traverse(int unit, int flags, uint32 start, uint32 end,
  19219                       bcm_l3_host_traverse_cb cb, void *user_data)
  19220 {
  19221     _bcm_l3_cfg_t l3cfg;        /* HW entry info.                  */
  19222     bcm_l3_host_t info;         /* Callback info buffer.           */
  19223     int table_ent_size;         /* Table entry size. */
  19224     int table_size;          /* Number of entries in the table. */
  19225     soc_mem_t mem;              /* Table memory.                   */
  19226     int idx_max;                /* Maximum iteration index.        */
  19227     int idx_min;                /* Minimum iteration index.        */
  19228     int nh_idx;                 /* Next hop index.                 */
  19229     int ipv6;                   /* Protocol IPv6/IPv4.             */
  19230     int idx;                    /* Iterator index.                 */
  19231     char *l3_tbl_ptr = NULL;    /* Table dma pointer.              */
  19232     int total = 0;              /* Total number of entries walked. */
  19233     int rv = BCM_E_NONE;        /* Operation return value.         */
  19234 
  19235     /* If no callback provided, we are done.  */
  19236     if (NULL == cb) {
  19237         return (BCM_E_NONE);
  19238     }
  19239 
  19240     /* Make sure required hw call is defined. */
  19241     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, l3_get_by_idx)) {
  19242         return (BCM_E_UNAVAIL);
  19243     }
  19244 
  19245     ipv6 = (flags & BCM_L3_IP6) ? TRUE : FALSE;
  19246     /* If table is empty -> there is nothing to read. */
  19247     if (ipv6 && (!BCM_XGS3_L3_IP6_CNT(unit))) {
  19248         return (BCM_E_NONE);
  19249     }
  19250     if (!ipv6 && (!BCM_XGS3_L3_IP4_CNT(unit))) {
  19251         return (BCM_E_NONE);
  19252     }
  19253 
  19254     /* Get table boundaries. */
  19255 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \
  19256     defined(BCM_HAWKEYE_SUPPORT)
  19257     if (soc_feature(unit, soc_feature_fp_based_routing)) {
  19258         /* Table is not present on this device. */
  19259         idx_min = 1;
  19260         idx_max = BCM_XGS3_L3_RP_MAX_PREFIXES(unit);
  19261         table_size = idx_max;
  19262     } else
  19263 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */
  19264     {
  19265         /* Get table memory. */
  19266         mem = (ipv6) ? BCM_XGS3_L3_MEM(unit, v6) : BCM_XGS3_L3_MEM(unit, v4);
  19267         idx_max = soc_mem_index_max(unit, mem);
  19268         idx_min =  soc_mem_index_min(unit, mem);
  19269         /* Get single entry size. */
  19270         table_ent_size =
  19271            (ipv6) ? BCM_XGS3_L3_ENT_SZ(unit, v6) : BCM_XGS3_L3_ENT_SZ(unit, v4);
  19272 
  19273         /* Dma the table - to speed up operation. */
  19274         BCM_IF_ERROR_RETURN
  19275              (bcm_xgs3_l3_tbl_dma(unit, mem, table_ent_size,
  19276                                   "l3_tbl", &l3_tbl_ptr, &table_size));
  19277     }
  19278 
  19279     /* Input indexes sanity. */
  19280     if (start > (uint32)table_size || start > end) {
  19281         return (BCM_E_NOT_FOUND);
  19282     }
  19283 
  19284 
  19285     /* Iterate over all the entries - show matching ones. */
  19286     for (idx = idx_min; idx <= idx_max; idx++) {
  19287         /* Reset buffer before read. */
  19288         sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
  19289         l3cfg.l3c_flags = flags;
  19290 
  19291         /* Get entry from  hw. */
  19292         BCM_XGS3_L3_MODULE_LOCK(unit);
  19293         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get_by_idx) (unit, l3_tbl_ptr,
  19294                                                            idx, &l3cfg,
  19295                                                            &nh_idx);
  19296         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  19297 
  19298         /* Check for read errors & invalid entries. */
  19299         if (rv < 0) {
  19300             if (rv != BCM_E_NOT_FOUND) {
  19301                 break;
  19302             }
  19303             continue;
  19304         }
  19305 
  19306         /* Check read entry flags & update index accordingly. */
  19307         if (BCM_L3_CMP_EQUAL !=
  19308             _bcm_xgs3_trvrs_flags_cmp(unit, flags, l3cfg.l3c_flags, &idx)) {
  19309             continue;
  19310         }
  19311 
  19312         /* Valid entry found -> increment total table_sizeer */
  19313         total++;
  19314         if ((uint32)total < start) {
  19315             continue;
  19316         }
  19317 
  19318         /* Don't read beyond last required index. */
  19319         if ((uint32)total > end) {
  19320             break;
  19321         }
  19322 
  19323         /* Get next hop info. */
  19324         rv = _bcm_xgs3_l3_get_nh_info(unit, &l3cfg, nh_idx);
  19325         if (rv < 0) {
  19326             continue;
  19327         }
  19328 
  19329         /* Fill host info. */
  19330         _bcm_xgs3_host_ent_init(unit, &l3cfg, TRUE, &info);
  19331         rv = (*cb) (unit, total, &info, user_data);
  19332 #ifdef BCM_CB_ABORT_ON_ERR
  19333         if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
  19334             break;
  19335         }
  19336 #endif
  19337     }
  19338 
  19339     if(l3_tbl_ptr) {
  19340         soc_cm_sfree(unit, l3_tbl_ptr);
  19341     }
  19342 
  19343     /* Reset last read status. */
  19344     if (BCM_E_NOT_FOUND == rv) {
  19345         rv = BCM_E_NONE;
  19346     }
  19347 
  19348     return (rv);
  19349 }
  19350 
  19351 /*
  19352  * Function:
  19353  *      bcm_xgs3_l3_ip4_traverse
  19354  * Purpose:
  19355  *      Walk over range of entries in l3 in the table.
  19356  * Parameters:
  19357  *      unit - SOC unit number.
  19358  *      start - First index to read.
  19359  *      end - Last index to read.
  19360  *      cb  - Caller notification callback.
  19361  *      user_data - User cookie, which should be returned in cb.
  19362  * Returns:
  19363  *      BCM_E_XXX
  19364  */
  19365 int
  19366 bcm_xgs3_l3_ip4_traverse(int unit, uint32 flags, uint32 start,
  19367                          uint32 end, bcm_l3_host_traverse_cb cb,
  19368                          void *user_data)
  19369 {
  19370     int rv;
  19371     /*  Make sure module was initialized. */
  19372     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  19373         return (BCM_E_INIT);
  19374     }
  19375 
  19376     BCM_XGS3_L3_MODULE_LOCK(unit);
  19377     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_traverse)
  19378                          (unit, flags, start, end, cb, user_data);
  19379     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  19380     return rv;
  19381 }
  19382 
  19383 /*
  19384  * Function:
  19385  *      bcm_xgs3_l3_ip6_traverse
  19386  * Purpose:
  19387  *      Walk over range of entries in l3 in the table.
  19388  * Parameters:
  19389  *      unit - SOC unit number.
  19390  *      start - First index to read.
  19391  *      end - Last index to read.
  19392  *      cb  - Caller notification callback.
  19393  *      user_data - User cookie, which should be returned in cb.
  19394  * Returns:
  19395  *      BCM_E_XXX
  19396  */
  19397 int
  19398 bcm_xgs3_l3_ip6_traverse(int unit, uint32 flags, uint32 start,
  19399                          uint32 end, bcm_l3_host_traverse_cb cb,
  19400                          void *user_data)
  19401 {
  19402     int rv;
  19403     /*  Make sure module was initialized. */
  19404     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  19405         return (BCM_E_INIT);
  19406     }
  19407 
  19408     BCM_XGS3_L3_MODULE_LOCK(unit);
  19409     rv = (BCM_XGS3_L3_HWCALL_EXEC(unit, l3_traverse)
  19410                          (unit, flags, start, end, cb, user_data));
  19411     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  19412     return rv;
  19413 }
  19414 
  19415 /*
  19416  * Function:
  19417  *      _bcm_xgs3_ip_key_to_l3cfg
  19418  * Purpose:
  19419  *      Translate l3 key to l3_cfg structure, which can be submitted for
  19420  *      hw lookup.
  19421  * Parameters:
  19422  *      unit     - (IN)SOC unit number.
  19423  *      ipkey    - (IN)IP address key.
  19424  *      l3cfg    - (IN)Lookup structure to fill.
  19425  * Returns:
  19426  *      BCM_E_XXX
  19427  */
  19428 STATIC INLINE int
  19429 _bcm_xgs3_ip_key_to_l3cfg(int unit, bcm_l3_key_t *ipkey, _bcm_l3_cfg_t *l3cfg)
  19430 {
  19431     int ipv6;           /* IPV6 key.                     */
  19432 
  19433     /* Input parameters check */
  19434     if ((NULL == ipkey) || (NULL == l3cfg)) {
  19435         return (BCM_E_PARAM);
  19436     }
  19437 
  19438     /* Reset destination buffer first. */
  19439     sal_memset(l3cfg, 0, sizeof(_bcm_l3_cfg_t));
  19440 
  19441     ipv6 = (ipkey->l3k_flags & BCM_L3_IP6);
  19442 
  19443     /* Set vrf id. */
  19444     l3cfg->l3c_vrf = ipkey->l3k_vrf;
  19445     l3cfg->l3c_vid = ipkey->l3k_vid;
  19446 
  19447     if (ipv6) {
  19448         if (BCM_IP6_MULTICAST(ipkey->l3k_ip6_addr)) {
  19449             /* Copy ipv6 group, source & vid. */
  19450             sal_memcpy(l3cfg->l3c_ip6, ipkey->l3k_ip6_addr, sizeof(bcm_ip6_t));
  19451             sal_memcpy(l3cfg->l3c_sip6, ipkey->l3k_sip6_addr,
  19452                        sizeof(bcm_ip6_t));
  19453             l3cfg->l3c_vid = ipkey->l3k_vid;
  19454             l3cfg->l3c_flags = (BCM_L3_IP6 | BCM_L3_IPMC);
  19455         } else {
  19456             /* Copy ipv6 address. */
  19457             sal_memcpy(l3cfg->l3c_ip6, ipkey->l3k_ip6_addr, sizeof(bcm_ip6_t));
  19458             l3cfg->l3c_flags = BCM_L3_IP6;
  19459         }
  19460     } else {
  19461         if (BCM_IP4_MULTICAST(ipkey->l3k_ip_addr)) {
  19462             /* Copy ipv4 mcast group, source & vid. */
  19463             l3cfg->l3c_ip_addr = ipkey->l3k_ip_addr;
  19464             l3cfg->l3c_src_ip_addr = ipkey->l3k_sip_addr;
  19465             l3cfg->l3c_vid = ipkey->l3k_vid;
  19466             l3cfg->l3c_flags = BCM_L3_IPMC;
  19467         } else {
  19468             /* Copy ipv4 address . */
  19469             l3cfg->l3c_ip_addr = ipkey->l3k_ip_addr;
  19470         }
  19471     }
  19472     return (BCM_E_NONE);
  19473 }
  19474 
  19475 /*
  19476  * Function:
  19477  *      _bcm_xgs3_l3cfg_to_ipkey
  19478  * Purpose:
  19479  *      Translate ipkey to l3_cfg structure, which can be submitted for
  19480  *      hw lookup.
  19481  * Parameters:
  19482  *      unit     - (IN)SOC unit number.
  19483  *      ipkey    - (IN)IP address key.
  19484  *      l3cfg    - (IN)Lookup structure to fill.
  19485  * Returns:
  19486  *      BCM_E_XXX
  19487  */
  19488 STATIC INLINE int
  19489 _bcm_xgs3_l3cfg_to_ipkey(int unit, bcm_l3_key_t *ipkey, _bcm_l3_cfg_t *l3cfg)
  19490 {
  19491     /* Input parameters check */
  19492     if ((NULL == ipkey) || (NULL == l3cfg)) {
  19493         return (BCM_E_PARAM);
  19494     }
  19495 
  19496     /* Reset destination buffer first. */
  19497     sal_memset(ipkey, 0, sizeof(bcm_l3_key_t));
  19498 
  19499     ipkey->l3k_vrf = l3cfg->l3c_vrf;
  19500     ipkey->l3k_vid = l3cfg->l3c_vid;
  19501 
  19502     if (l3cfg->l3c_flags & BCM_L3_IP6) {
  19503         if (l3cfg->l3c_flags & BCM_L3_IPMC) {
  19504             /* Copy ipv6 group, source & vid. */
  19505             sal_memcpy(ipkey->l3k_ip6_addr, l3cfg->l3c_ip6, sizeof(bcm_ip6_t));
  19506             sal_memcpy(ipkey->l3k_sip6_addr, l3cfg->l3c_sip6,
  19507                        sizeof(bcm_ip6_t));
  19508             ipkey->l3k_vid = l3cfg->l3c_vid;
  19509         } else {
  19510             /* Copy ipv6 address. */
  19511             sal_memcpy(ipkey->l3k_ip6_addr, l3cfg->l3c_ip6, sizeof(bcm_ip6_t));
  19512         }
  19513     } else {
  19514         if (l3cfg->l3c_flags & BCM_L3_IPMC) {
  19515             /* Copy ipv4 mcast group, source & vid. */
  19516             ipkey->l3k_ip_addr = l3cfg->l3c_ip_addr;
  19517             ipkey->l3k_sip_addr = l3cfg->l3c_src_ip_addr;
  19518             ipkey->l3k_vid = l3cfg->l3c_vid;
  19519         } else {
  19520             /* Copy ipv4 address . */
  19521             ipkey->l3k_ip_addr = l3cfg->l3c_ip_addr;
  19522         }
  19523     }
  19524     /* Store entry flags. */
  19525     ipkey->l3k_flags = l3cfg->l3c_flags;
  19526     return (BCM_E_NONE);
  19527 }
  19528 
  19529 
  19530 /*
  19531  * Function:
  19532  *      bcm_xgs3_l3_get_by_index
  19533  * Purpose:
  19534  *      Get L3 entry at index
  19535  * Parameters:
  19536  *      unit  - (IN)SOC unit number.
  19537  *      idx   - (IN)Entry index to read.
  19538  *      l3cfg - (OUT) decoded L3 entry
  19539  * Returns:
  19540  *      BCM_E_XXX
  19541  */
  19542 int
  19543 bcm_xgs3_l3_get_by_index(int unit, int idx, _bcm_l3_cfg_t *l3cfg)
  19544 {
  19545     int rv = BCM_E_UNAVAIL;     /* Operation return code. */
  19546 
  19547     /*  Make sure module was initialized. */
  19548     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  19549         return (BCM_E_INIT);
  19550     }
  19551 
  19552     BCM_XGS3_L3_MODULE_LOCK(unit);
  19553     if (l3cfg->l3c_flags & BCM_L3_IPMC) {
  19554         /* Get multicast entry. */
  19555         if (BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_get_by_idx)) {
  19556             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_get_by_idx) (unit, NULL,
  19557                                                                  idx, l3cfg);
  19558         }
  19559     } else {
  19560         /* Get unicast entry. */
  19561         if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_get_by_idx)) {
  19562             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get_by_idx) (unit, NULL, idx,
  19563                                                                l3cfg, NULL);
  19564         }
  19565     }
  19566 
  19567     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  19568     return rv;
  19569 }
  19570 
  19571 /*
  19572  * Function:
  19573  *      bcm_xgs3_l3_conflict_get
  19574  * Purpose:
  19575  *      Given a IP address, return conflicts in the L3 table.
  19576  * Parameters:
  19577  *      unit     - SOC unit number.
  19578  *      ipkey    - IP address to test conflict condition
  19579  *      cf_array - (OUT) arrary of conflicting addresses(at most 8)
  19580  *      cf_max   - max number of conflicts wanted
  19581  *      count    - (OUT) actual # of conflicting addresses
  19582  * Returns:
  19583  *      BCM_E_XXX
  19584  */
  19585 int
  19586 bcm_xgs3_l3_conflict_get(int unit, bcm_l3_key_t *ipkey,
  19587                          bcm_l3_key_t *cf_array, int cf_max, int *cf_count)
  19588 {
  19589     _bcm_l3_cfg_t l3cfg;        /* Lookup entry info.         */
  19590     int l3_index;               /* Adjusted table index.      */
  19591     int bucket_primary;         /* Primary bucket in bank 0.  */
  19592     int bucket_secondary;       /* Secondary bucket in bank 1.*/
  19593     int bucket_iterator;        /* Bucket iterator.           */
  19594     int idx;                    /* Iteration index.           */
  19595     int idx_max;                /* Iteration end index.       */
  19596     int rv = BCM_E_UNAVAIL;     /* Operation return value.    */
  19597 
  19598 
  19599     /*  Make sure module was initialized. */
  19600     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  19601         return (BCM_E_INIT);
  19602     }
  19603 
  19604     /* Input parameters check. */
  19605     if ((NULL == ipkey) || (NULL == cf_count) ||
  19606         (NULL == cf_array) || (cf_max <= 0)) {
  19607         return (BCM_E_PARAM);
  19608     }
  19609 
  19610     /* Make sure hw call to read ip4 entries is initialized. */
  19611     if ((!BCM_XGS3_L3_HWCALL_CHECK(unit, l3_get_by_idx)) ||
  19612         (!BCM_XGS3_L3_HWCALL_CHECK(unit, l3_bucket_get))) {
  19613         return (BCM_E_UNAVAIL);
  19614     }
  19615 
  19616     *cf_count = 0;
  19617 
  19618     /* Translate lookup key to l3cfg format. */
  19619     BCM_IF_ERROR_RETURN(_bcm_xgs3_ip_key_to_l3cfg(unit, ipkey, &l3cfg));
  19620 
  19621     /* Ge. */
  19622 
  19623     BCM_XGS3_L3_MODULE_LOCK(unit);
  19624     rv = (BCM_XGS3_L3_HWCALL_EXEC(unit, l3_bucket_get)(unit, &l3cfg,
  19625                                                       &bucket_primary,
  19626                                                       &bucket_secondary));
  19627     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  19628     BCM_IF_ERROR_RETURN(rv);
  19629 
  19630     /*
  19631      * Loop through all L3_BUCKET_SIZE entries in this bucket
  19632      */
  19633     for (bucket_iterator = 0; bucket_iterator < 2; bucket_iterator++) {
  19634         idx = (bucket_iterator) ? bucket_secondary : bucket_primary;
  19635         idx_max = idx + SOC_L3X_BUCKET_SIZE(unit)/2;
  19636 
  19637         for (;idx < idx_max && (*cf_count < cf_max); idx++) {
  19638             /* Reset entry flags so we alwayes read ipv4 entry. */
  19639             l3cfg.l3c_flags = 0;
  19640 
  19641             BCM_XGS3_L3_MODULE_LOCK(unit);
  19642             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get_by_idx) (unit, NULL, idx,
  19643                                                                &l3cfg, NULL);
  19644             BCM_XGS3_L3_MODULE_UNLOCK(unit);
  19645             if (rv == BCM_E_NOT_FOUND) {
  19646                 continue;
  19647             }
  19648             if (BCM_FAILURE(rv)) {
  19649                 return rv;
  19650             }
  19651 
  19652             /* Reread entry if it is not ipv4 unicast one. */
  19653             if (l3cfg.l3c_flags & (BCM_L3_IP6 | BCM_L3_IPMC)) {
  19654                 l3_index = idx;
  19655 #ifdef BCM_FIREBOLT_SUPPORT
  19656                 BCM_XGS3_FB_IPMC_IP6_IDX_CALC(unit, idx, l3_index, l3cfg.l3c_flags);
  19657 #endif /* BCM_FIREBOLT_SUPPORT */
  19658                 BCM_IF_ERROR_RETURN
  19659                     (bcm_xgs3_l3_get_by_index(unit, l3_index, &l3cfg));
  19660             }
  19661 
  19662             /* Fill conflicting entry in key format. */
  19663             _bcm_xgs3_l3cfg_to_ipkey(unit, cf_array + (*cf_count), &l3cfg);
  19664             if ((++(*cf_count)) >= cf_max) {
  19665                 return (BCM_E_NONE);
  19666             }
  19667         }
  19668     }
  19669     return (BCM_E_NONE);
  19670 }
  19671 
  19672 /*
  19673  * Function:
  19674  *      bcm_xgs3_l3_info
  19675  * Purpose:
  19676  *      Get the status of hardware.
  19677  * Parameters:
  19678  *      unit   - (IN)SOC unit number
  19679  *      l3info - (OUT)Structure to fill with L3 related information.
  19680  * Returns:
  19681  *      BCM_E_XXX.
  19682  */
  19683 int
  19684 bcm_xgs3_l3_info(int unit, bcm_l3_info_t *l3info)
  19685 {
  19686 #ifdef BCM_KATANA_SUPPORT
  19687     int ipv6_128b_used = 0;
  19688     soc_kt_lpm_ipv6_info_t *lpm_ipv6_info = soc_kt_lpm_ipv6_info_get(unit);
  19689 #endif
  19690 
  19691 #ifdef BCM_TRIUMPH_SUPPORT
  19692     soc_mem_t mem;
  19693     BCM_IF_ERROR_RETURN(_bcm_tr_l3_defip_mem_get(unit, 0, 0, &mem));
  19694 #endif /* BCM_TRIUMPH_SUPPORT */
  19695 
  19696     /*  Make sure module was initialized. */
  19697     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  19698         return (BCM_E_INIT);
  19699     }
  19700 
  19701     /* Input parameters check. */
  19702     if (NULL == l3info) {
  19703         return (BCM_E_PARAM);
  19704     }
  19705 
  19706 #ifdef BCM_KATANA_SUPPORT
  19707     if (SOC_IS_KATANA(unit) && LOG_CHECK(BSL_LS_BCM_L3 | BSL_INFO)) {
  19708         _bcm_kt_l3_info_dump(unit);
  19709     }
  19710 #endif
  19711 
  19712     l3info->l3info_max_vrf = SOC_VRF_MAX(unit);
  19713     l3info->l3info_used_vrf = -1;
  19714     l3info->l3info_max_intf = BCM_XGS3_L3_IF_MAX_COUNT(unit);
  19715     l3info->l3info_max_intf_group = SOC_INTF_CLASS_MAX(unit);
  19716     l3info->l3info_max_l3 = BCM_XGS3_L3_TBL_SIZE(unit);
  19717 #ifdef BCM_TRIUMPH3_SUPPORT
  19718     if (SOC_IS_TRIUMPH3(unit) &&
  19719         (soc_feature(unit, soc_feature_esm_support))) {
  19720          l3info->l3info_max_l3 +=
  19721          soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, v4_esm));
  19722     }
  19723 #endif
  19724     l3info->l3info_max_defip = BCM_XGS3_L3_DEFIP_TBL_SIZE(unit);
  19725 #ifdef BCM_TRIUMPH2_SUPPORT
  19726     l3info->l3info_max_ecmp_groups = BCM_XGS3_L3_ECMP_MAX_GROUPS(unit);
  19727 #endif
  19728     l3info->l3info_max_ecmp = BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  19729     l3info->l3info_occupied_intf = BCM_XGS3_L3_IF_COUNT(unit);
  19730     l3info->l3info_max_host = l3info->l3info_max_l3;
  19731     l3info->l3info_max_lpm_block = 0;
  19732     l3info->l3info_used_lpm_block = 0;
  19733 
  19734 #ifdef BCM_TRIUMPH_SUPPORT
  19735     if ((soc_feature(unit, soc_feature_esm_support)) && (L3_DEFIPm != mem)) {
  19736         /* ESM - One route per entry */
  19737         l3info->l3info_max_route = l3info->l3info_max_defip;
  19738     } else
  19739 #endif /* BCM_TRIUMPH_SUPPORT */
  19740     {  /* Two routes per entry */
  19741         l3info->l3info_max_route = l3info->l3info_max_defip << 1;
  19742 #ifdef BCM_TOMAHAWK2_SUPPORT
  19743         if (soc_feature(unit, soc_feature_half_of_l3_defip_ipv4_capacity)) {
  19744             l3info->l3info_max_route >>= 1;
  19745         }
  19746 #endif
  19747         if (soc_feature(unit, soc_feature_defip_2_tcams_with_separate_rpf)) {
  19748             l3info->l3info_max_route = (R2P_V4_MAX << 1);
  19749         }
  19750 
  19751         if (soc_feature(unit, soc_feature_lpm_atomic_write)) {
  19752             int reserved_entries;
  19753 
  19754             BCM_IF_ERROR_RETURN(soc_lpm_reserved_route_get(unit,
  19755                                 &reserved_entries, NULL, NULL));
  19756             l3info->l3info_max_route -= reserved_entries;
  19757         }
  19758 #ifdef BCM_TRIDENT2_SUPPORT
  19759         if (SOC_MEM_IS_VALID(unit, L3_DEFIP_ALPM_IPV4m)) {
  19760             if (soc_mem_index_count(unit, L3_DEFIP_ALPM_IPV4m)) {
  19761                 l3info->l3info_max_route =
  19762                                 soc_mem_index_count(unit, L3_DEFIP_ALPM_IPV4m);
  19763             }
  19764         }
  19765 #ifdef ALPM_ENABLE
  19766         if (soc_property_get(unit, spn_L3_ALPM_ENABLE, 0) &&
  19767             SOC_MEM_IS_VALID(unit, L3_DEFIP_ALPM_LEVEL3m)) {
  19768             if (soc_mem_index_count(unit, L3_DEFIP_ALPM_LEVEL3m)) {
  19769                 l3info->l3info_max_route = ALPM_EPB_MAX * \
  19770                     soc_mem_index_count(unit, L3_DEFIP_ALPM_LEVEL3m);
  19771             }
  19772         }
  19773 #endif
  19774 #endif
  19775     }
  19776 
  19777 #if defined(BCM_HURRICANE2_SUPPORT) || defined(BCM_GREYHOUND_SUPPORT)
  19778     if (SOC_IS_HURRICANE2(unit)||SOC_IS_GREYHOUND(unit) ||
  19779         SOC_IS_HURRICANE3(unit)||SOC_IS_GREYHOUND2(unit)) {
  19780         /* One route per entry */
  19781         l3info->l3info_max_route = l3info->l3info_max_defip;
  19782     }
  19783 #endif /* BCM_HURRICANE2_SUPPORT||BCM_GREYHOUND_SUPPORT */
  19784 
  19785 #ifdef BCM_FIREBOLT_SUPPORT
  19786     if (SOC_IS_FBX(unit)) {
  19787 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \
  19788     defined(BCM_HAWKEYE_SUPPORT)
  19789         if (soc_feature(unit, soc_feature_fp_based_routing)) {
  19790             l3info->l3info_max_route = l3info->l3info_max_defip;
  19791             l3info->l3info_occupied_l3 =
  19792                 BCM_XGS3_L3_IP4_CNT(unit) + BCM_XGS3_L3_IP6_CNT(unit);
  19793             l3info->l3info_occupied_defip =
  19794                 BCM_XGS3_L3_DEFIP_IP4_CNT(unit) + BCM_XGS3_L3_DEFIP_IP6_CNT(unit);
  19795         } else
  19796 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */
  19797         {
  19798             if (SOC_IS_TR_VL(unit)) {
  19799                 l3info->l3info_occupied_l3 = BCM_XGS3_L3_IP4_CNT(unit) + 
  19800                                            2 * BCM_XGS3_L3_IP4_IPMC_CNT(unit) + 
  19801                                            2 * BCM_XGS3_L3_IP6_CNT(unit) +
  19802                                            4 * BCM_XGS3_L3_IP6_IPMC_CNT(unit);
  19803 
  19804                 l3info->l3info_used_host_ip4 = BCM_XGS3_L3_IP4_CNT(unit) + 
  19805                                            2 * BCM_XGS3_L3_IP4_IPMC_CNT(unit);
  19806                 l3info->l3info_used_host_ip6 = 
  19807                                            2 * BCM_XGS3_L3_IP6_CNT(unit) +
  19808                                            4 * BCM_XGS3_L3_IP6_IPMC_CNT(unit);
  19809             } else {
  19810                 l3info->l3info_occupied_l3 = BCM_XGS3_L3_IP4_CNT(unit) + 
  19811                                              BCM_XGS3_L3_IP4_IPMC_CNT(unit) + 
  19812                                            2 * BCM_XGS3_L3_IP6_CNT(unit) +
  19813                                            4 * BCM_XGS3_L3_IP6_IPMC_CNT(unit);
  19814 
  19815                 l3info->l3info_used_host_ip4 = BCM_XGS3_L3_IP4_CNT(unit) + 
  19816                                                BCM_XGS3_L3_IP4_IPMC_CNT(unit);
  19817                 l3info->l3info_used_host_ip6 = 
  19818                                            2 * BCM_XGS3_L3_IP6_CNT(unit) +
  19819                                            4 * BCM_XGS3_L3_IP6_IPMC_CNT(unit);
  19820             }
  19821 
  19822             /* Entries occupied in L3_DEFIPm excluding L3_DEFIP_128m */
  19823 #if defined(BCM_KATANA_SUPPORT)
  19824             if (SOC_IS_KATANA(unit)) {
  19825 
  19826                 if (lpm_ipv6_info->ipv6_128b.depth > 0) {
  19827                     ipv6_128b_used = _bcm_kt_defip_pair128_used_count_get(unit);
  19828                 }
  19829                 l3info->l3info_occupied_defip =
  19830                     BCM_XGS3_L3_DEFIP_IP4_CNT(unit)
  19831                     + ((BCM_XGS3_L3_DEFIP_IP6_CNT(unit) - ipv6_128b_used) * 2);
  19832             } else
  19833 #endif
  19834 #if defined(BCM_TRIDENT2_SUPPORT)
  19835             if (soc_feature(unit, soc_feature_td2_style_l3_defip_cnt)) {
  19836                 int defip_128_used = 0;
  19837                 if (BCM_DEFIP_PAIR128(unit)) {
  19838                     defip_128_used = BCM_DEFIP_PAIR128_USED_COUNT(unit);
  19839                 }
  19840                 l3info->l3info_occupied_defip = BCM_XGS3_L3_DEFIP_IP4_CNT(unit) +
  19841                     (BCM_XGS3_L3_DEFIP_IP6_CNT(unit) - defip_128_used) * 2;
  19842             } else
  19843 #endif
  19844             {
  19845                 l3info->l3info_occupied_defip = BCM_XGS3_L3_DEFIP_IP4_CNT(unit) +
  19846                     (BCM_XGS3_L3_DEFIP_IP6_CNT(unit) * 2);
  19847             }
  19848         }
  19849     }
  19850 #endif /* BCM_FIREBOLT_SUPPORT */
  19851     l3info->l3info_occupied_host = l3info->l3info_occupied_l3;
  19852     l3info->l3info_occupied_route = l3info->l3info_occupied_defip;
  19853     l3info->l3info_max_nexthop = BCM_XGS3_L3_NH_TBL_SIZE(unit);
  19854     l3info->l3info_used_nexthop = BCM_XGS3_L3_NH_CNT(unit);
  19855 
  19856     if(!soc_feature(unit, soc_feature_no_tunnel)) {
  19857         l3info->l3info_max_tunnel_init = BCM_XGS3_L3_TUNNEL_TBL_SIZE(unit);
  19858         l3info->l3info_used_tunnel_init = BCM_XGS3_L3_TBL(unit, tnl_init).idx_maxused;
  19859         if (soc_mem_is_valid(unit, L3_TUNNELm)) {
  19860             l3info->l3info_max_tunnel_term = soc_mem_index_count(unit, L3_TUNNELm);
  19861             l3info->l3info_used_tunnel_term = soc_tunnel_term_used_get(unit);
  19862         }
  19863     } else {
  19864         if (soc_feature(unit, soc_feature_vxlan_lite)) {
  19865             l3info->l3info_max_tunnel_init =
  19866                 BCM_XGS3_L3_TUNNEL_TBL_SIZE(unit);
  19867             l3info->l3info_used_tunnel_init =
  19868                 BCM_XGS3_L3_TBL(unit, tnl_init).idx_maxused;
  19869             l3info->l3info_max_tunnel_term = 0;
  19870             l3info->l3info_used_tunnel_term = 0;
  19871         } else {
  19872         l3info->l3info_max_tunnel_init = 0;
  19873         l3info->l3info_used_tunnel_init = 0;
  19874         l3info->l3info_max_tunnel_term = 0;
  19875         l3info->l3info_used_tunnel_term = 0;
  19876     }
  19877     }
  19878 
  19879     return (BCM_E_NONE);
  19880 }
  19881 
  19882 /*
  19883  * Function:
  19884  *      _bcm_xgs3_lpm_get_nh_info
  19885  * Purpose:
  19886  *      Fill next hop info to lpm entry.
  19887  * Parameters:
  19888  *      unit   - (IN)SOC unit number.
  19889  *      lpm_cfg- (IN)Buffer to fill defip information.
  19890  *      nh_idx - (IN)Next hop index.
  19891  * Returns:
  19892  *      BCM_E_XXX
  19893  */
  19894 STATIC int
  19895 _bcm_xgs3_lpm_get_nh_info(int unit, _bcm_defip_cfg_t *lpm_cfg, int nh_idx)
  19896 {
  19897     bcm_l3_egress_t nh_info;  /* Next hop info buffer.    */
  19898 
  19899 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
  19900     if (soc_feature(unit, soc_feature_ipmc_defip) &&
  19901         (lpm_cfg->defip_flags & BCM_L3_IPMC)) {
  19902        
  19903        return BCM_E_NONE;
  19904     }
  19905 #endif
  19906     /* In egress switching mode - set egress object id only. */
  19907     if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  19908         if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) {
  19909             lpm_cfg->defip_intf = nh_idx + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  19910         } else {
  19911             BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, nh_idx, &nh_info));
  19912             if (nh_info.encap_id > 0 &&
  19913                 nh_info.encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit)) {
  19914                 lpm_cfg->defip_intf = nh_idx + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  19915             } else {
  19916 #ifdef BCM_RIOT_SUPPORT
  19917                 if (BCMI_RIOT_IS_ENABLED(unit) &&
  19918                     (_bcm_vp_is_vfi_type(unit, nh_info.port))) {
  19919                     lpm_cfg->defip_intf =
  19920                         nh_idx + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  19921                 } else
  19922 #endif
  19923                 {
  19924                     lpm_cfg->defip_intf = nh_idx + BCM_XGS3_EGRESS_IDX_MIN(unit);
  19925                 }
  19926             }
  19927         }
  19928         return (BCM_E_NONE);
  19929     }
  19930 
  19931     /* If next hop is trap to cpu - don't read nh table. */
  19932     if (nh_idx == BCM_XGS3_L3_L2CPU_NH_IDX(unit)) {
  19933         /* Set flags to bridge to cpu. */
  19934         lpm_cfg->defip_flags |= BCM_L3_DEFIP_LOCAL;
  19935         /* Set interface index to last one in the table. */
  19936         lpm_cfg->defip_intf = BCM_XGS3_L3_L2CPU_INTF_IDX(unit);
  19937         /* Set module id to a local module. */
  19938         BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &lpm_cfg->defip_modid));
  19939         /* Set port to be a cpu port. */
  19940         lpm_cfg->defip_port_tgid = CMIC_PORT(unit);
  19941         /* No vlan/interface info. */
  19942         lpm_cfg->defip_vid = 0;
  19943         lpm_cfg->defip_tunnel = 0;
  19944         /* Reset mac address. */
  19945         sal_memset(lpm_cfg->defip_mac_addr, 0, sizeof(bcm_mac_t));
  19946         return (BCM_E_NONE);
  19947     }
  19948 
  19949     /* Get next hop entry from hw. */
  19950     BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, nh_idx, &nh_info));
  19951 
  19952     /* Fill next hop info to l3 entry. */
  19953     if (nh_info.flags & BCM_L3_TGID) {       /* Trunk */
  19954         lpm_cfg->defip_flags |= BCM_L3_TGID;
  19955     }
  19956     /* Set module id. */
  19957     lpm_cfg->defip_modid = nh_info.module;
  19958     /* Set trunk/port info. */
  19959     lpm_cfg->defip_port_tgid =
  19960         (nh_info.flags & BCM_L3_TGID) ? nh_info.trunk : nh_info.port;
  19961     /* Set interface index. */
  19962     lpm_cfg->defip_intf = nh_info.intf;
  19963     /* Set physical address. */
  19964     sal_memcpy(lpm_cfg->defip_mac_addr, nh_info.mac_addr, sizeof(bcm_mac_t));
  19965 
  19966     /* Get tunnel id info. */
  19967     BCM_IF_ERROR_RETURN
  19968         (_bcm_xgs3_l3_get_tunnel_id(unit, nh_info.intf,
  19969                                     &lpm_cfg->defip_tunnel));
  19970 #ifdef BCM_FIREBOLT_SUPPORT
  19971     if (SOC_IS_FBX(unit)) {
  19972         lpm_cfg->defip_vid = nh_info.vlan;
  19973     }
  19974 #endif /* BCM_FIREBOLT_SUPPORT */
  19975     return (BCM_E_NONE);
  19976 }
  19977 
  19978 /*
  19979  * Function:
  19980  *      _bcm_xgs3_defip_set_route_info
  19981  * Purpose:
  19982  *      Fill user callbacks route info.
  19983  * Parameters:
  19984  *      unit       - (IN)SOC unit number.
  19985  *      lpm_cfg    - (IN)Defip information.
  19986  *      route_info - (OUT)Buffer to fill route info.
  19987  *      nh_idx     - (IN)Next hop index.
  19988  * Returns:
  19989  *      BCM_E_XXX
  19990  */
  19991 STATIC int
  19992 _bcm_xgs3_defip_set_route_info(int unit, _bcm_defip_cfg_t *lpm_cfg,
  19993                                bcm_l3_route_t *route_info, int nh_idx)
  19994 {
  19995     _bcm_defip_cfg_t lpm_temp;  /* Avoid modifying original lpm entry.*/
  19996     int ipv6;                   /* IPv6 entry indicator.              */
  19997 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
  19998     ipmc_1_entry_t      ipmc_1_entry;
  19999     bcm_ipmc_addr_t     ipmc;
  20000 #endif
  20001 #if defined(BCM_TRIDENT3_SUPPORT)
  20002     int i = 0;
  20003 #endif /* BCM_TRIDENT3_SUPPORT */
  20004 
  20005     /* Input parameters check. */
  20006     if (NULL == lpm_cfg) {
  20007         return (BCM_E_PARAM);
  20008     }
  20009 
  20010     lpm_temp =  *lpm_cfg;
  20011     ipv6 = (lpm_temp.defip_flags & BCM_L3_IP6);
  20012 
  20013     /* Init route entry. */
  20014     bcm_l3_route_t_init(route_info);
  20015 
  20016     /* Set vrf id. */
  20017     route_info->l3a_vrf = lpm_temp.defip_vrf;
  20018 
  20019     if (ipv6) {
  20020         /* Set ipv6 address. */
  20021         sal_memcpy(route_info->l3a_ip6_net, lpm_temp.defip_ip6_addr,
  20022                    sizeof(bcm_ip6_t));
  20023 
  20024         /* Set subnet mask. */
  20025         bcm_ip6_mask_create(route_info->l3a_ip6_mask, lpm_temp.defip_sub_len);
  20026 
  20027         /* Set entry flags to ipv6 */
  20028         route_info->l3a_flags = BCM_L3_IP6;
  20029     } else {
  20030         /* Set ipv4 address. */
  20031         route_info->l3a_subnet = lpm_temp.defip_ip_addr;
  20032 
  20033         /* Set subnet mask. */
  20034         route_info->l3a_ip_mask =
  20035             BCM_IP4_MASKLEN_TO_ADDR(lpm_temp.defip_sub_len);
  20036 
  20037         /* Reset entry flags */
  20038         route_info->l3a_flags = 0;
  20039     }
  20040 
  20041 #ifdef BCM_TRIDENT3_SUPPORT
  20042     if ((soc_feature(unit, soc_feature_flex_flow)) &&
  20043         (lpm_temp.defip_num_of_fields)) {
  20044         for (i = 0;
  20045              i < lpm_temp.defip_num_of_fields;
  20046              i++) {
  20047             route_info->logical_fields[i].id =
  20048                  lpm_temp.defip_logical_fields[i].id;
  20049             route_info->logical_fields[i].value =
  20050                  lpm_temp.defip_logical_fields[i].value;
  20051             route_info->num_of_fields = lpm_temp.defip_num_of_fields;
  20052         }
  20053     }
  20054 #endif /* BCM_TRIDENT3_SUPPORT */
  20055     /* Priority & Class ID */
  20056     if (soc_feature(unit, soc_feature_overlaid_address_class) &&
  20057         !BCM_L3_RPE_SET(lpm_temp.defip_flags)) {
  20058         route_info->l3a_lookup_class = ((lpm_temp.defip_prio & 0xF) << 6);
  20059         route_info->l3a_lookup_class |= (lpm_temp.defip_lookup_class & 0x3F);
  20060     } else {
  20061         route_info->l3a_lookup_class = lpm_temp.defip_lookup_class;
  20062         route_info->l3a_pri = lpm_temp.defip_prio;
  20063     }
  20064 
  20065     /* Fill next hop info Or multicast route Info if needed. */
  20066     if ((nh_idx != BCM_XGS3_L3_INVALID_INDEX) ||
  20067         (lpm_temp.defip_flags & BCM_L3_IPMC)) {
  20068 
  20069         /* Entry flags. */
  20070         route_info->l3a_flags |= lpm_temp.defip_flags;
  20071 
  20072         /* Fill Multicast route info if needed*/
  20073         if (lpm_temp.defip_flags & BCM_L3_IPMC) {
  20074             route_info->l3a_ipmc_flags |= lpm_temp.defip_ipmc_flags;
  20075             route_info->l3a_expected_intf = lpm_temp.defip_expected_intf;
  20076             route_info->l3a_rp = lpm_temp.defip_l3a_rp;
  20077             route_info->l3a_mc_group = lpm_temp.defip_mc_group;
  20078         }
  20079         if (nh_idx != BCM_XGS3_L3_INVALID_INDEX) {
  20080             /* Get next hop info. */
  20081             BCM_IF_ERROR_RETURN(_bcm_xgs3_lpm_get_nh_info(unit, &lpm_temp, nh_idx));
  20082         }
  20083 
  20084         /* Interface index/Egress object id. */
  20085         route_info->l3a_intf = lpm_temp.defip_intf;
  20086 
  20087 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
  20088         /* If it is a Multicast route entry, get the source port
  20089          * information
  20090          */
  20091         if (soc_feature(unit, soc_feature_ipmc_defip) &&
  20092             soc_mem_is_valid(unit, L3_IPMC_1m) &&
  20093             lpm_cfg->defip_flags & BCM_L3_IPMC) {
  20094             sal_memset(&ipmc, 0, sizeof(bcm_ipmc_addr_t));
  20095             BCM_IF_ERROR_RETURN
  20096                 (soc_mem_read(unit, L3_IPMC_1m, MEM_BLOCK_ANY,
  20097                               lpm_temp.defip_mc_group, &ipmc_1_entry));
  20098             BCM_IF_ERROR_RETURN
  20099                 (_tr2_ipmc_glp_get(unit, &ipmc, &ipmc_1_entry));
  20100             if (!(ipmc.flags & BCM_IPMC_SOURCE_PORT_NOCHECK)) {
  20101                 BCM_IF_ERROR_RETURN(
  20102                         _bcm_esw_l3_gport_construct(unit, ipmc.port_tgid,
  20103                             ipmc.mod_id,
  20104                             ipmc.port_tgid,
  20105                             ipmc.ts ? BCM_L3_TGID : 0,
  20106                             &(route_info->l3a_expected_src_gport)));
  20107             } else {
  20108                 route_info->l3a_ipmc_flags |= BCM_IPMC_SOURCE_PORT_NOCHECK;
  20109             }
  20110         }
  20111 #endif
  20112         /* Don't fill additional info in egress switching mode. */
  20113         if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  20114            return (BCM_E_NONE);
  20115         }
  20116 
  20117         /* Trunk */
  20118         if (lpm_temp.defip_flags & BCM_L3_TGID) {
  20119             route_info->l3a_flags |= BCM_L3_TGID;
  20120         }
  20121         /* Module id. */
  20122         route_info->l3a_modid = lpm_temp.defip_modid;
  20123         /* Port/Trunk info. */
  20124         route_info->l3a_port_tgid = lpm_temp.defip_port_tgid;
  20125         /* Vlan id. */
  20126         route_info->l3a_vid = lpm_temp.defip_vid;
  20127         /* Mac address. */
  20128         sal_memcpy(route_info->l3a_nexthop_mac, lpm_temp.defip_mac_addr,
  20129                    sizeof(bcm_mac_t));
  20130     }
  20131 
  20132     return (BCM_E_NONE);
  20133 }
  20134 
  20135 /*
  20136  * Function:
  20137  *      _bcm_xgs3_lpm_call_user_cb
  20138  * Purpose:
  20139  *      Fill user callbacks route info and call user callback.
  20140  * Parameters:
  20141  *      unit       - (IN)SOC unit number.
  20142  *      trv_data   - (IN)User cookie & callback routine.
  20143  *      lpm_cfg    - (IN)Defip information.
  20144  *      nh_idx     - next hop index.
  20145  * Returns:
  20146  *      BCM_E_XXX
  20147  */
  20148 STATIC int
  20149 _bcm_xgs3_lpm_call_user_cb(int unit, _bcm_l3_trvrs_data_t *trv_data,
  20150                            _bcm_defip_cfg_t *lpm_cfg, int nh_idx)
  20151 {
  20152     bcm_l3_route_t route_info;
  20153 
  20154     /* Fill route info. */
  20155     BCM_IF_ERROR_RETURN
  20156         (_bcm_xgs3_defip_set_route_info(unit, lpm_cfg, &route_info, nh_idx));
  20157 
  20158     /* Call user notification routine. */
  20159     if (NULL != trv_data->defip_cb) {
  20160         (*trv_data->defip_cb) (unit, lpm_cfg->defip_index,
  20161                                 &route_info, trv_data->cookie);
  20162     }
  20163     return (BCM_E_NONE);
  20164 }
  20165 
  20166 /*
  20167  * Function:
  20168  *      bcm_xgs3_max_ecmp_set
  20169  * Purpose:
  20170  *      Set the max allowable number of ECMP paths that is less
  20171  *      than the hardware allowed value
  20172  * Parameters:
  20173  *      unit       - (IN) SOC device unit number
  20174  *      max_paths  - (IN) Maximum number of ecmp paths.
  20175  * Returns:
  20176  *      BCM_E_XXX
  20177  */
  20178 int
  20179 bcm_xgs3_max_ecmp_set(int unit, int max_paths)
  20180 {
  20181     int rv = BCM_E_NONE;                     /* Operation return value. */
  20182 
  20183     if (!SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, ecmp)) ||
  20184         !soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, ecmp))) {
  20185         return (BCM_E_UNAVAIL);
  20186     }
  20187 
  20188     if (BCM_XGS3_L3_ECMP_IN_USE(unit)) {
  20189         LOG_ERROR(BSL_LS_BCM_L3,
  20190 		  (BSL_META_U(unit,
  20191 			      "ECMP already in use, max path can't be reset\n")));
  20192         return (BCM_E_BUSY);
  20193     }
  20194 
  20195     /* Max paths sanity. */
  20196     if (max_paths < 2 || max_paths > BCM_XGS3_L3_ECMP_MAX(unit)) {
  20197         return (BCM_E_PARAM);
  20198     }
  20199 
  20200 #ifdef BCM_TOMAHAWK_SUPPORT
  20201     if (soc_feature(unit, soc_feature_hierarchical_ecmp)) {
  20202         int  _max_ecmp_paths = 1024;
  20203         if (!(soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) &&
  20204              (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  20205                  ecmp_mode_hierarchical) && (max_paths > 128)) {
  20206             return (BCM_E_PARAM);
  20207         }
  20208 #ifdef BCM_TOMAHAWK3_SUPPORT
  20209         if (soc_feature(unit, soc_feature_post_ifp_single_stage_ecmp)) {
  20210             _max_ecmp_paths = 4096;
  20211         }
  20212 #endif
  20213         if ((BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == ecmp_mode_single) &&
  20214                                (max_paths > _max_ecmp_paths)) {
  20215             return (BCM_E_PARAM);
  20216         }
  20217     }
  20218     /* In the low latency mode, max value of max paths is 128 */
  20219     if (soc_feature(unit, soc_feature_fast_ecmp)) {
  20220         if (max_paths > 128) {
  20221             return (BCM_E_PARAM);
  20222         }
  20223     }
  20224 #endif /* BCM_TOMAHAWK_SUPPORT */
  20225 
  20226     /* Free original groups array. */
  20227     sal_free(BCM_XGS3_L3_TBL(unit, ecmp_grp).ext_arr);
  20228     BCM_XGS3_L3_TBL(unit, ecmp_grp).ext_arr = NULL;
  20229 
  20230     /* Set maximum number of paths. */
  20231     BCM_XGS3_L3_ECMP_MAX_PATHS(unit) = max_paths;
  20232 
  20233     /* Reinitialize ecmp group table. */
  20234     rv = _bcm_xgs3_l3_ecmp_group_init(unit);
  20235 
  20236     return rv;
  20237 }
  20238 
  20239 /*
  20240  * Function:
  20241  *      bcm_xgs3_max_ecmp_get
  20242  * Purpose:
  20243  *      Get the max allowable number of ECMP paths.
  20244  * Parameters:
  20245  *      unit       - (IN) SOC device unit number
  20246  *      max_paths  - (IN) Maximum number of ecmp paths.
  20247  * Returns:
  20248  *      BCM_E_XXX
  20249  */
  20250 int
  20251 bcm_xgs3_max_ecmp_get(int unit, int *max_paths)
  20252 {
  20253 #if defined(BCM_HAWKEYE_SUPPORT) || defined(BCM_HURRICANE_SUPPORT)
  20254     if ( SOC_IS_HAWKEYE(unit) || SOC_IS_HURRICANE(unit) || 
  20255             SOC_IS_HURRICANE2(unit)) {
  20256         return (BCM_E_UNAVAIL);
  20257     }
  20258 #endif
  20259     if (soc_feature(unit, soc_feature_l3_no_ecmp)) {
  20260         return (BCM_E_UNAVAIL);
  20261     }
  20262 
  20263     if (NULL == max_paths) {
  20264         return (BCM_E_PARAM);
  20265     }
  20266 
  20267     /* Set maximum number of paths. */
  20268     *max_paths = BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  20269 
  20270     return (BCM_E_NONE);
  20271 }
  20272 
  20273 /*
  20274  * Function:
  20275  *      _bcm_xgs3_defip_mpath_add
  20276  * Purpose:
  20277  *      Update multipath route in the hw.
  20278  * Parameters:
  20279  *      unit         - (IN)SOC unit number.
  20280  *      lpm_cfg      - (IN)Route data.
  20281  *      ecmp_group_id  - (IN)New Ecmp group id.
  20282  * Returns:
  20283  *      BCM_E_XXX
  20284  */
  20285 STATIC int
  20286 _bcm_xgs3_defip_mpath_add(int unit, _bcm_defip_cfg_t *lpm_cfg, int ecmp_group_id)
  20287 {
  20288     int ecmp_index;             /* Index in ecmp table.       */
  20289     int rv = BCM_E_UNAVAIL;     /* Operation return status.   */
  20290 
  20291     /* Ecmp table index for the allocated group. */
  20292     ecmp_index = ecmp_group_id;
  20293     if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  20294         ecmp_index = ecmp_group_id * BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  20295     }
  20296 
  20297     /* Set zero based number of paths to lpm entry. */
  20298     rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_id,
  20299                                     &lpm_cfg->defip_ecmp_count);
  20300     if (rv < 0) {
  20301         return rv;
  20302     }
  20303     lpm_cfg->defip_ecmp_count--;
  20304 
  20305     /*  Add route to the hw. */
  20306     if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_add)) {
  20307         BCM_XGS3_L3_MODULE_LOCK(unit);
  20308         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_add) (unit, lpm_cfg, ecmp_index);
  20309         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  20310     }
  20311     /* Decrement group reference count if operation failed.  */
  20312     if (rv < 0) {
  20313         bcm_xgs3_ecmp_group_del(unit, ecmp_group_id, 0);
  20314         return rv;
  20315     }
  20316 
  20317     return (BCM_E_NONE);
  20318 }
  20319 
  20320 /*
  20321  * Function:
  20322  *      _bcm_xgs3_defip_ecmp_write
  20323  * Purpose:
  20324  *      Write route with multipaths to the hw.
  20325  * Parameters:
  20326  *      unit         - (IN)SOC unit number.
  20327  *      lpm_cfg      - (IN)Route data.
  20328  *      ecmp_group   - (IN)Ecmp group.
  20329  *      ecmp_count   - (IN)Count of next hop indexes in ecmp group.
  20330  * Returns:
  20331  *      BCM_E_XXX
  20332  */
  20333 STATIC int
  20334 _bcm_xgs3_defip_ecmp_write(int unit, _bcm_defip_cfg_t *lpm_cfg, uint32 ecmp_flags,
  20335                            int *ecmp_group, int ecmp_count)
  20336 {
  20337     int ecmp_group_id;          /* New ecmp group index.      */
  20338     int ecmp_index;             /* Index in ecmp table.       */
  20339     int rv = BCM_E_UNAVAIL;     /* Operation return status.   */
  20340 
  20341     /* Add ecmp group to the hw. */
  20342     rv = _bcm_xgs3_ecmp_group_add(unit, 0, ecmp_flags, ecmp_count,
  20343                                   0,
  20344                                   ecmp_group,
  20345                                   &ecmp_group_id,
  20346                                   ecmp_count, NULL);
  20347     BCM_IF_ERROR_RETURN(rv);
  20348 
  20349     /* Ecmp table index for the allocated group. */
  20350     ecmp_index = ecmp_group_id;
  20351     if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  20352         ecmp_index = ecmp_group_id * BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  20353     }
  20354 
  20355     /* Set zero based number of paths to lpm entry. */
  20356     rv = _bcm_xgs3_ecmp_max_grp_size_get(unit,
  20357                                     ecmp_group_id,
  20358                                     &lpm_cfg->defip_ecmp_count);
  20359     if (rv < 0) {
  20360         return rv;
  20361     }
  20362     lpm_cfg->defip_ecmp_count--;
  20363 
  20364     /*  Add route to the hw. */
  20365     if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_add)) {
  20366           BCM_XGS3_L3_MODULE_LOCK(unit);
  20367           rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_add) (unit, lpm_cfg, ecmp_index);
  20368           BCM_XGS3_L3_MODULE_UNLOCK(unit);
  20369     }
  20370 
  20371     if (BCM_FAILURE(rv)) {
  20372         bcm_xgs3_ecmp_group_del(unit, ecmp_group_id, 0);
  20373         return rv;
  20374     }
  20375     return (BCM_E_NONE);
  20376 }
  20377 
  20378 /*
  20379  * Function:
  20380  *      _bcm_xgs3_defip_ecmp_add
  20381  * Purpose:
  20382  *      IP route with multipaths to DEFIP table
  20383  * Parameters:
  20384  *      unit           - (IN)SOC unit number.
  20385  *      lpm_cfg        - (IN)Route data.
  20386  *      ecmp_group_idx - (IN)Ecmp group index.
  20387  *      nh_index       - (IN)Next hop index.
  20388  * Returns:
  20389  *      BCM_E_XXX
  20390  */
  20391 STATIC int
  20392 _bcm_xgs3_defip_ecmp_add(int unit, _bcm_defip_cfg_t *lpm_cfg,
  20393                          int ecmp_group_idx, int nh_index)
  20394 {
  20395     int ecmp_max_count = 0;     /* Maximum next hop count in the group.*/
  20396     int ecmp_count = 0;         /* Next hop count in the group.        */
  20397     uint32 ecmp_flags = 0;     /* ECMP group flags */
  20398     int *ecmp_grp;              /* Ecmp group from hw.                 */
  20399     int rv;                     /* Operation return status.            */
  20400 
  20401     /* Allocate ecmp group buffer. */
  20402     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp));
  20403 
  20404     /*If ecmp group exists just update next hops set. */
  20405     if (BCM_XGS3_L3_INVALID_INDEX != ecmp_group_idx) {
  20406 
  20407         /* Extract maximum ecmp group size. */
  20408         rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_idx, &ecmp_max_count);
  20409         if (rv < 0) {
  20410            sal_free(ecmp_grp);
  20411            return rv;
  20412         }
  20413 
  20414 #if defined(BCM_TOMAHAWK3_SUPPORT)
  20415         if ((ecmp_group_idx < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2)) &&
  20416             (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  20417                                          ecmp_mode_hierarchical)) {
  20418             ecmp_flags |= BCM_L3_ECMP_OVERLAY;
  20419         }
  20420 #endif
  20421 
  20422         /* Read ecmp group members from hw. */
  20423         rv = _bcm_xgs3_ecmp_tbl_read(unit, ecmp_group_idx,
  20424                                      ecmp_grp, &ecmp_count);
  20425         if (BCM_FAILURE(rv)) {
  20426             sal_free(ecmp_grp);
  20427             return (rv);
  20428         }
  20429 
  20430 
  20431         /* Enforce max number of multipaths. */
  20432         if (ecmp_count == ecmp_max_count) {
  20433             sal_free(ecmp_grp);
  20434             LOG_ERROR(BSL_LS_BCM_L3,
  20435                       (BSL_META_U(unit,
  20436                                   "Maximum number of ECMP paths reached\n")));
  20437             return (BCM_E_RESOURCE);
  20438         }
  20439         if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, ecmp_group_idx,
  20440                                 BCM_L3_ECMP_PATH_NO_SORTING)) {
  20441             ecmp_flags |= BCM_L3_ECMP_PATH_NO_SORTING;
  20442         }
  20443     } else {            /* New route. */
  20444         ecmp_count = 0;
  20445     }
  20446 
  20447     /* Store new ecmp index in the group. */
  20448     ecmp_grp[ecmp_count] = nh_index;
  20449 
  20450     /* Write group & route to hardware. */
  20451     rv = _bcm_xgs3_defip_ecmp_write(unit, lpm_cfg, ecmp_flags, ecmp_grp, (ecmp_count + 1));
  20452 
  20453     sal_free(ecmp_grp);
  20454     return (rv);
  20455 }
  20456 
  20457 /*
  20458  * Function:
  20459  *      _bcm_xgs3_defip_del
  20460  * Purpose:
  20461  *      Delete IP route with multipaths from DEFIP table
  20462  * Parameters:
  20463  *      unit         - (IN)SOC unit number.
  20464  *      lpm_cfg      - (IN)Route data.
  20465  *      nh_idx       - (IN)Next hop/Ecmp group index.
  20466  * Returns:
  20467  *      BCM_E_XXX
  20468  */
  20469 STATIC int
  20470 _bcm_xgs3_defip_del(int unit, _bcm_defip_cfg_t *lpm_cfg, int nh_idx)
  20471 {
  20472     int rv = BCM_E_UNAVAIL;
  20473 
  20474     /*  Delete route from the hw. */
  20475     if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_del)) {
  20476         BCM_XGS3_L3_MODULE_LOCK(unit);
  20477         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_del) (unit, lpm_cfg);
  20478         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  20479     }
  20480     /* If route deletion successfull decrement next hop reference count. */
  20481     if (rv >= 0) {
  20482         bcm_xgs3_nh_del(unit, 0, nh_idx);
  20483     }
  20484     return rv;
  20485 }
  20486 
  20487 /*
  20488  * Function:
  20489  *      _bcm_xgs3_defip_ecmp_del
  20490  * Purpose:
  20491  *      Delete IP route with multipaths from DEFIP table
  20492  * Parameters:
  20493  *      unit          - (IN)SOC unit number.
  20494  *      lpm_cfg       - (IN)Route data.
  20495  *      ecmp_group_id - (IN)Ecmp group id.
  20496  * Returns:
  20497  *      BCM_E_XXX
  20498  */
  20499 STATIC int
  20500 _bcm_xgs3_defip_ecmp_del(int unit, _bcm_defip_cfg_t *lpm_cfg,
  20501                          int ecmp_group_id)
  20502 {
  20503     bcm_l3_egress_t nh_info;    /* Deleted next hop info.             */
  20504     int cmp_result;             /* Next hop comparison result.        */
  20505     int ecmp_count = 0;         /* Next hop count in the group.       */
  20506     uint32 ecmp_flags = 0;    /* Ecmp group flags */
  20507     int *ecmp_grp;              /* Ecmp group from hw.                */
  20508     uint16 hash;                /* Hash used to find next hop entry.  */
  20509     int idx;                    /* Iteration index.                   */
  20510     int del_nh_index;           /* Matching next hop index.           */
  20511     int rv;                     /* Internal operations status.        */
  20512 
  20513 
  20514     /* Input parameters check. */
  20515     if (NULL == lpm_cfg) {
  20516         return (BCM_E_PARAM);
  20517     }
  20518 
  20519     /* Allocate ecmp group buffer. */
  20520     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp));
  20521 
  20522 #if defined(BCM_TOMAHAWK3_SUPPORT)
  20523     if ((ecmp_group_id < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2)) &&
  20524         (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  20525                                      ecmp_mode_hierarchical)) {
  20526          ecmp_flags |= BCM_L3_ECMP_OVERLAY;
  20527     }
  20528 #endif
  20529 
  20530     if (!BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  20531         /* Read ecmp group members from the hw. */
  20532         rv = _bcm_xgs3_ecmp_tbl_read(unit, ecmp_group_id,
  20533                                      ecmp_grp, &ecmp_count);
  20534         if (BCM_FAILURE(rv)) {
  20535             sal_free(ecmp_grp);
  20536             return (rv);
  20537         }
  20538     }
  20539 
  20540     /*
  20541      * If caller didn't specify multipath or group contains a single entry.
  20542      * just delete a whole ecmp group.
  20543      */
  20544     if ((ecmp_count == 1) || (!(lpm_cfg->defip_flags & BCM_L3_MULTIPATH)) ||
  20545         (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) {
  20546         /*  Delete route from the hw. */
  20547         if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_del)) {
  20548             BCM_XGS3_L3_MODULE_LOCK(unit);
  20549             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_del) (unit, lpm_cfg);
  20550             BCM_XGS3_L3_MODULE_UNLOCK(unit);
  20551         } else {
  20552             sal_free(ecmp_grp);
  20553             return  (BCM_E_UNAVAIL);
  20554         }
  20555 
  20556         /* Decrease reference count for all group member nexthops. */
  20557         if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) {
  20558             _bcm_xgs3_ecmp_group_nh_delete(unit, ecmp_grp, ecmp_count);
  20559         }
  20560     } else {
  20561         /*
  20562          * 1) BCM_L3_MULTIPATH flag is set   &&
  20563          * 2) Next hop information is  present  &&
  20564          * 3)  number of entries > 1.
  20565          * We need to find next hop index marked for deletion.
  20566          */
  20567         /* Prepare next hop info. */
  20568         rv = _bcm_xgs3_nh_entry_init(unit, &nh_info, NULL, lpm_cfg);
  20569         if (BCM_FAILURE(rv)) {
  20570             sal_free(ecmp_grp);
  20571             return (rv);
  20572         }
  20573 
  20574         /* If no interface information present use customer provided vlan id. */
  20575         if(!nh_info.vlan)  {
  20576             nh_info.vlan = lpm_cfg->defip_vid;
  20577         }
  20578 
  20579         /* Convert API next hop entry to HW space format. */
  20580         rv = _bcm_xgs3_nh_map_api_data_to_hw(unit, &nh_info);
  20581         if (BCM_FAILURE(rv)) {
  20582             sal_free(ecmp_grp);
  20583             return (rv);
  20584         }
  20585 
  20586         /* Calculate entry hash. */
  20587         _bcm_xgs3_nh_hash_calc(unit, (void *)&nh_info, &hash);
  20588 
  20589         /* Find next hop entry from ecmp group. */
  20590         for (idx = 0; idx < ecmp_count; idx++) {
  20591 
  20592             /* Compare next hop hash. */
  20593             if (!BCM_XGS3_L3_ENT_HASH_CMP(BCM_XGS3_L3_TBL_PTR(unit, next_hop),
  20594                                           ecmp_grp[idx], hash)) {
  20595                 continue;
  20596             }
  20597 
  20598             /* Compare entire next hop entry. */
  20599             rv = _bcm_xgs3_nh_ent_cmp(unit, (void *)&nh_info,
  20600                                       ecmp_grp[idx], &cmp_result);
  20601             if (BCM_FAILURE(rv)) {
  20602                 sal_free(ecmp_grp);
  20603                 return (rv);
  20604             }
  20605             if (BCM_L3_CMP_EQUAL == cmp_result) {
  20606                 break;
  20607             }                   /* Next hops are identical check. */
  20608         }                       /* Loop over all next hop indexes in the group. */
  20609 
  20610         /* If we didn't find deleted next hop return an error. */
  20611         if (idx >= ecmp_count) {
  20612             sal_free(ecmp_grp);
  20613             return (BCM_E_PARAM);
  20614         }
  20615 
  20616         /* Preserve matching next hop. */
  20617         del_nh_index = ecmp_grp[idx];
  20618 
  20619         /* Decrement ecmp count. */
  20620         ecmp_count--;
  20621 
  20622         /* Copy last next hop index into the deleted index spot. */
  20623         if (idx < ecmp_count) {
  20624             ecmp_grp[idx] = ecmp_grp[ecmp_count];
  20625         }
  20626 
  20627         /* Reset last next hop index in the group. */
  20628         ecmp_grp[ecmp_count] = 0;
  20629 
  20630         /* Write group & route to hardware. */
  20631         if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, ecmp_group_id,
  20632                     BCM_L3_ECMP_PATH_NO_SORTING)) {
  20633             ecmp_flags |= BCM_L3_ECMP_PATH_NO_SORTING;
  20634         }
  20635 
  20636         rv = _bcm_xgs3_defip_ecmp_write(unit, lpm_cfg, ecmp_flags, ecmp_grp, ecmp_count);
  20637 
  20638         if (BCM_FAILURE(rv)) {
  20639             sal_free(ecmp_grp);
  20640             return (rv);
  20641         }
  20642         /* Release next hop index. */
  20643         bcm_xgs3_nh_del(unit, 0, del_nh_index);
  20644     }
  20645     /*
  20646      * Decrement original ecmp group reference count,
  20647      * and possibly delete the group.
  20648      */
  20649     rv = bcm_xgs3_ecmp_group_del(unit, ecmp_group_id, 0);
  20650     sal_free(ecmp_grp);
  20651     return rv;
  20652 }
  20653 
  20654 /*
  20655  * Function:
  20656  *      bcm_xgs3_defip_get
  20657  * Purpose:
  20658  *      Get an entry from DEFIP table.
  20659  * Parameters:
  20660  *      unit    - (IN)SOC unit number.
  20661  *      lpm_cfg - (IN)Buffer to fill defip information.
  20662  * Returns:
  20663  *      BCM_E_XXX
  20664  */
  20665 int
  20666 bcm_xgs3_defip_get(int unit, _bcm_defip_cfg_t *lpm_cfg)
  20667 {
  20668     int nh_ecmp_idx;        /* Next hop/Ecmp group index.          */
  20669     int *ecmp_grp;          /* Ecmp group from hw.                 */
  20670     int nh_idx;             /* Next hop index.                     */
  20671     int rv = BCM_E_UNAVAIL; /* Operation return status.            */
  20672 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
  20673     ipmc_1_entry_t      ipmc_1_entry;
  20674     bcm_ipmc_addr_t     ipmc;
  20675 #endif
  20676 
  20677     /* Input parameters check. */
  20678     if (NULL == lpm_cfg) {
  20679         return (BCM_E_PARAM);
  20680     }
  20681 
  20682     /* Input parameters checks. */
  20683     BCM_XGS3_L3_DEFIP_INVALID_PARAMS_RETURN(unit, lpm_cfg);
  20684 
  20685     /* Get lpm entry. */
  20686     if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_get)) {
  20687         BCM_XGS3_L3_MODULE_LOCK(unit);
  20688         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_get) (unit, lpm_cfg,
  20689                                                      &nh_ecmp_idx);
  20690         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  20691     }
  20692 
  20693     BCM_XGS3_LKUP_IF_ERROR_RETURN(rv, BCM_E_NOT_FOUND);
  20694     /* Translate ecmp index to ecmp group id. */
  20695     if (lpm_cfg->defip_ecmp) {
  20696         if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  20697             nh_ecmp_idx /= BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  20698         }
  20699     }
  20700 
  20701     /* If route is multipath get nh info from the first path. */
  20702     if (lpm_cfg->defip_ecmp && (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)))) {
  20703         /* Allocate ecmp group buffer. */
  20704         BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp));
  20705 
  20706         rv = _bcm_xgs3_ecmp_tbl_read(unit, nh_ecmp_idx,
  20707                                      ecmp_grp, &lpm_cfg->defip_ecmp_count);
  20708         if (BCM_FAILURE(rv)) {
  20709             sal_free(ecmp_grp);
  20710             return (rv);
  20711         }
  20712         nh_idx = ecmp_grp[0];
  20713         sal_free(ecmp_grp);
  20714     } else {
  20715         nh_idx = nh_ecmp_idx;
  20716     }
  20717 
  20718 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
  20719     /* If it is a Multicast route entry, get the source port
  20720      * information
  20721      */
  20722     if (soc_feature(unit, soc_feature_ipmc_defip) &&
  20723         soc_mem_is_valid(unit, L3_IPMC_1m) &&
  20724         lpm_cfg->defip_flags & BCM_L3_IPMC) {
  20725         sal_memset(&ipmc, 0, sizeof(bcm_ipmc_addr_t));
  20726         BCM_IF_ERROR_RETURN
  20727             (soc_mem_read(unit, L3_IPMC_1m, MEM_BLOCK_ANY,
  20728                           lpm_cfg->defip_mc_group, &ipmc_1_entry));
  20729         BCM_IF_ERROR_RETURN
  20730             (_tr2_ipmc_glp_get(unit, &ipmc, &ipmc_1_entry));
  20731         lpm_cfg->defip_source_ts = ipmc.ts;
  20732         lpm_cfg->defip_source_port_tgid = ipmc.port_tgid;
  20733         lpm_cfg->defip_source_modid = ipmc.mod_id;
  20734         lpm_cfg->defip_ipmc_flags |= ipmc.flags;
  20735     }
  20736 #endif
  20737 
  20738     /* Fill next hop info to the prefix. */
  20739     BCM_IF_ERROR_RETURN(_bcm_xgs3_lpm_get_nh_info(unit, lpm_cfg, nh_idx));
  20740 
  20741     return (BCM_E_NONE);
  20742 }
  20743 
  20744 /*
  20745  * Function:
  20746  *      bcm_xgs3_defip_find
  20747  * Purpose:
  20748  *      Find an Longest prefix matched entry from LPM/ALPM table.
  20749  * Parameters:
  20750  *      unit    - (IN)SOC unit number.
  20751  *      lpm_cfg - (IN/OUT)Buffer to fill defip information.
  20752  * Returns:
  20753  *      BCM_E_XXX
  20754  */
  20755 int
  20756 bcm_xgs3_defip_find(int unit, _bcm_defip_cfg_t *lpm_cfg)
  20757 {
  20758 #ifdef ALPM_ENABLE
  20759     int nh_ecmp_idx;        /* Next hop/Ecmp group index.          */
  20760     int *ecmp_grp;          /* Ecmp group from hw.                 */
  20761     int nh_idx;             /* Next hop index.                     */
  20762     int rv = BCM_E_UNAVAIL; /* Operation return status.            */
  20763 
  20764 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
  20765     ipmc_1_entry_t      ipmc_1_entry;
  20766     bcm_ipmc_addr_t     ipmc;
  20767 #endif
  20768 
  20769     /* Input parameters check. */
  20770     if (NULL == lpm_cfg) {
  20771         return (BCM_E_PARAM);
  20772     }
  20773 
  20774     if (!SOC_IS_TRIDENT2X(unit) && !SOC_IS_TOMAHAWKX(unit) && !SOC_IS_TRIDENT3X(unit)) {
  20775         return (BCM_E_UNAVAIL);
  20776     }
  20777 
  20778     if (!(soc_feature(unit, soc_feature_alpm) &&
  20779           soc_property_get(unit, spn_L3_ALPM_ENABLE, 0))) {
  20780         return (BCM_E_CONFIG);
  20781     }
  20782 
  20783     /* Input parameters checks. */
  20784     BCM_XGS3_L3_DEFIP_INVALID_PARAMS_RETURN(unit, lpm_cfg);
  20785 
  20786     /* Get lpm entry. */
  20787     BCM_XGS3_L3_MODULE_LOCK(unit);
  20788     if (SOC_IS_TRIDENT2(unit) || SOC_IS_TRIDENT2PLUS(unit)) {
  20789         rv = _bcm_td2_alpm_find(unit, lpm_cfg, &nh_ecmp_idx);
  20790     }
  20791 #if defined(BCM_TOMAHAWK_SUPPORT)
  20792     else if (soc_feature(unit, soc_feature_alpm2)) {
  20793         rv = bcm_esw_alpm_find(unit, lpm_cfg, &nh_ecmp_idx);
  20794     }
  20795 #endif
  20796 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT)
  20797     else {
  20798         rv = _bcm_th_alpm_find(unit, lpm_cfg, &nh_ecmp_idx);
  20799     }
  20800 #endif
  20801 
  20802     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  20803 
  20804     BCM_XGS3_LKUP_IF_ERROR_RETURN(rv, BCM_E_NOT_FOUND);
  20805     /* Translate ecmp index to ecmp group id. */
  20806     if (lpm_cfg->defip_ecmp) {
  20807         if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  20808             nh_ecmp_idx /= BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  20809         }
  20810     }
  20811 
  20812     /* If route is multipath get nh info from the first path. */
  20813     if (lpm_cfg->defip_ecmp && (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)))) {
  20814         /* Allocate ecmp group buffer. */
  20815         BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp));
  20816 
  20817         rv = _bcm_xgs3_ecmp_tbl_read(unit, nh_ecmp_idx,
  20818                                      ecmp_grp, &lpm_cfg->defip_ecmp_count);
  20819         if (BCM_FAILURE(rv)) {
  20820             sal_free(ecmp_grp);
  20821             return (rv);
  20822         }
  20823         nh_idx = ecmp_grp[0];
  20824         sal_free(ecmp_grp);
  20825     } else {
  20826         nh_idx = nh_ecmp_idx;
  20827     }
  20828 
  20829     /* Fill next hop info to the prefix. */
  20830     BCM_IF_ERROR_RETURN(_bcm_xgs3_lpm_get_nh_info(unit, lpm_cfg, nh_idx));
  20831 
  20832 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
  20833     /* If it is a Multicast route entry, get the source port
  20834      * information
  20835      */
  20836     if (soc_feature(unit, soc_feature_ipmc_defip) &&
  20837         soc_mem_is_valid(unit, L3_IPMC_1m) &&
  20838         lpm_cfg->defip_flags & BCM_L3_IPMC) {
  20839         sal_memset(&ipmc, 0, sizeof(bcm_ipmc_addr_t));
  20840         BCM_IF_ERROR_RETURN
  20841             (soc_mem_read(unit, L3_IPMC_1m, MEM_BLOCK_ANY,
  20842                           lpm_cfg->defip_mc_group, &ipmc_1_entry));
  20843         BCM_IF_ERROR_RETURN
  20844             (_tr2_ipmc_glp_get(unit, &ipmc, &ipmc_1_entry));
  20845         lpm_cfg->defip_source_ts = ipmc.ts;
  20846         lpm_cfg->defip_source_port_tgid = ipmc.port_tgid;
  20847         lpm_cfg->defip_source_modid = ipmc.mod_id;
  20848         lpm_cfg->defip_ipmc_flags |= ipmc.flags;
  20849     }
  20850 #endif
  20851 
  20852     return (BCM_E_NONE);
  20853 #else
  20854     return (BCM_E_UNAVAIL);
  20855 #endif
  20856 
  20857 }
  20858 
  20859 
  20860 /*
  20861  * Function:
  20862  *      bcm_xgs3_defip_path_validate
  20863  * Purpose:
  20864  *      Service routine used to validate route path for non-egress mode.
  20865  * Parameters:
  20866  *      unit        - (IN) Bcm device number.
  20867  *      new_route    - (IN) Added route information.
  20868  *      old_route   - (IN) Previously existing route.
  20869  * Returns:
  20870  *      BCM_E_NONE - Route path is valid.
  20871  *      BCM_E_XXX  - Otherwise.
  20872  */
  20873 int
  20874 bcm_xgs3_defip_path_validate(int unit, _bcm_defip_cfg_t *new_route,
  20875                              _bcm_defip_cfg_t *old_route)
  20876 {
  20877     /* Validate trunk id. */
  20878     BCM_XGS3_L3_IF_INVALID_TGID_RETURN(unit, new_route->defip_flags,
  20879                                        new_route->defip_port_tgid);
  20880 
  20881     if (new_route->defip_flags & BCM_L3_MULTIPATH) {
  20882         /* Make sure device supports ecmp forwarding. */
  20883         if (0 == BCM_XGS3_L3_ECMP_MAX_PATHS(unit)) {
  20884             return (BCM_E_UNAVAIL);
  20885         }
  20886 
  20887         /* Trap to cpu is not allowed as member of ecmp group. */
  20888         if (new_route->defip_flags & BCM_L3_DEFIP_LOCAL) {
  20889             return (BCM_E_PARAM);
  20890         }
  20891     }
  20892 
  20893     /* If it is not addition of new path to a multipath route. */
  20894     /* BCM_L3_REPLACE flag must be set.                        */
  20895     if (NULL != old_route) {
  20896         if ((!(old_route->defip_flags & BCM_L3_MULTIPATH)) ||
  20897             (!(new_route->defip_flags & BCM_L3_MULTIPATH))) {
  20898             if (!(new_route->defip_flags & BCM_L3_REPLACE)) {
  20899                 return (BCM_E_EXISTS);
  20900             }
  20901         }
  20902     }
  20903     return (BCM_E_NONE);
  20904 }
  20905 
  20906 /*
  20907  * Function:
  20908  *      bcm_xgs3_defip_add
  20909  * Purpose:
  20910  *      Add IP route to DEFIP table
  20911  * Parameters:
  20912  *      unit    - (IN)SOC unit number.
  20913  *      lpm_cfg - (IN)Added route information.
  20914  * Returns:
  20915  *      BCM_E_XXX
  20916  */
  20917 int
  20918 bcm_xgs3_defip_add(int unit, _bcm_defip_cfg_t *lpm_cfg)
  20919 {
  20920     _bcm_defip_cfg_t entry;                      /* Lookup buffer.            */
  20921     _bcm_defip_cfg_t *old_route;                 /* Lookup result pointer.    */
  20922     int nh_idx;                                  /* Next hop index.           */
  20923     int mpath;                                   /* New route is multipath.   */
  20924     int nh_remove;                               /* Flag to remove mpath nhops*/
  20925     int rv = BCM_E_UNAVAIL;                      /* Operation return status.  */
  20926     int lkup_result = BCM_E_UNAVAIL;             /* Lookup result.            */
  20927     int nh_ecmp_idx = BCM_XGS3_L3_INVALID_INDEX; /* Next hop/Ecmp group index.*/
  20928     int old_ecmp_grp = BCM_XGS3_L3_INVALID_INDEX;/* Original route ecmp group.*/
  20929 #ifdef BCM_TRIDENT2_SUPPORT
  20930     soc_mem_t    mem_v4 = L3_DEFIP_ALPM_IPV4m;
  20931 #endif
  20932 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
  20933     bcm_ipmc_addr_t ipmc;
  20934     int need_write;
  20935     int new_entry;
  20936 #endif
  20937 
  20938     /* Route lookup key Subnet sanity check. */
  20939     BCM_XGS3_L3_DEFIP_INVALID_PARAMS_RETURN(unit, lpm_cfg);
  20940 
  20941 #ifdef BCM_TRIDENT2_SUPPORT
  20942     if (SOC_MEM_IS_VALID(unit, L3_DEFIP_ALPM_IPV4m)) {
  20943        mem_v4 = L3_DEFIP_ALPM_IPV4m;
  20944     } 
  20945 #endif
  20946 
  20947 
  20948 
  20949     /* Set lookup key. */
  20950     entry = *lpm_cfg;
  20951     mpath = lpm_cfg->defip_flags & BCM_L3_MULTIPATH;
  20952     if (!mpath &&
  20953         BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, lpm_cfg->defip_intf)) {
  20954         return BCM_E_PARAM;
  20955     }
  20956     if (mpath && BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  20957         if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, lpm_cfg->defip_intf)) {
  20958             return BCM_E_PARAM;
  20959         }
  20960     }
  20961 
  20962     /* Check if route exists. */
  20963     if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_get)) {
  20964         BCM_XGS3_L3_MODULE_LOCK(unit);
  20965         lkup_result = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_get) (unit, &entry,
  20966                                                               &nh_ecmp_idx);
  20967         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  20968     }
  20969     lpm_cfg->defip_alpm_cookie = entry.defip_alpm_cookie;
  20970 #ifdef ALPM_ENABLE
  20971     if (soc_feature(unit, soc_feature_alpm2)) {
  20972         lpm_cfg->l1_pvt_node = entry.l1_pvt_node;
  20973         lpm_cfg->pvt_node = entry.pvt_node;
  20974         lpm_cfg->bkt_node = entry.bkt_node;
  20975     }
  20976 #endif
  20977 
  20978     if (BCM_SUCCESS(lkup_result)) {
  20979         /* Save route entry index in hw to indicate  */
  20980         /* existing entry replacement.               */
  20981         lpm_cfg->defip_flex_ctr_base_id = entry.defip_flex_ctr_base_id;
  20982         lpm_cfg->defip_flex_ctr_mode    = entry.defip_flex_ctr_mode;
  20983         lpm_cfg->defip_flex_ctr_pool    = entry.defip_flex_ctr_pool;
  20984         lpm_cfg->defip_index = entry.defip_index;
  20985         lpm_cfg->defip_flags_high = entry.defip_flags_high;
  20986         old_route = &entry;
  20987         /* eXTRACT ecmp group group only if original route was multipath.*/
  20988         if (old_route->defip_flags & BCM_L3_MULTIPATH) {
  20989             /* Trunslate next hop index to ecmp group id. */
  20990             if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  20991                 nh_ecmp_idx /= BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  20992             }
  20993             old_ecmp_grp = nh_ecmp_idx;
  20994         }
  20995 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
  20996         new_entry = FALSE;
  20997 #endif
  20998     } else if (lkup_result == BCM_E_NOT_FOUND){
  20999         /* In case of host replacement - make sure host was present. */
  21000         if ((lpm_cfg->defip_flags & BCM_L3_REPLACE) &&
  21001             (lpm_cfg->defip_flags & BCM_L3_HOST_AS_ROUTE)) {
  21002             return (lkup_result);
  21003         }
  21004 
  21005         /* New route. */
  21006         lpm_cfg->defip_index = BCM_XGS3_L3_INVALID_INDEX;
  21007 #ifdef BCM_TRIDENT2_SUPPORT
  21008         /* defip_index has a cookie which we don't want to lose. BCM_E_NOT_FOUND
  21009          * info for ALPM is available in the cookie
  21010          */
  21011         if (SOC_MEM_IS_VALID(unit, mem_v4) &&
  21012             soc_mem_index_count(unit, mem_v4)) {
  21013                 /* in alpm mode */
  21014                 lpm_cfg->defip_index = entry.defip_index;
  21015         }
  21016 #endif /* BCM_TRIDENT2_SUPPORT */
  21017         old_route = NULL;
  21018 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
  21019         new_entry = TRUE;
  21020 #endif
  21021     } else {
  21022         return lkup_result;
  21023     }
  21024 
  21025 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
  21026     if (soc_feature(unit, soc_feature_ipmc_defip) &&
  21027             (lpm_cfg->defip_flags & BCM_L3_IPMC)) {
  21028         sal_memset(&ipmc, 0, sizeof(bcm_ipmc_addr_t));
  21029         ipmc.flags = lpm_cfg->defip_ipmc_flags;
  21030         ipmc.ts  = lpm_cfg->defip_source_ts;
  21031         ipmc.port_tgid = lpm_cfg->defip_source_port_tgid;
  21032         ipmc.mod_id = lpm_cfg->defip_source_modid;
  21033         ipmc.v = 1;
  21034         if (new_entry) {
  21035             BCM_IF_ERROR_RETURN(_bcm_tr_ipmc_src_port_consistency_check(unit,
  21036                         lpm_cfg->defip_mc_group, &ipmc, 0, &need_write));
  21037             /* Increment the reference count of the given ipmc_index. */
  21038             IPMC_DEFIP_USED_SET(unit, lpm_cfg->defip_mc_group);
  21039         } else {
  21040             if (entry.defip_mc_group != lpm_cfg->defip_mc_group) {
  21041                 BCM_IF_ERROR_RETURN(_bcm_tr_ipmc_src_port_consistency_check(unit,
  21042                             lpm_cfg->defip_mc_group, &ipmc, 0, &need_write));
  21043                 IPMC_DEFIP_USED_SET(unit, lpm_cfg->defip_mc_group);
  21044                 IPMC_DEFIP_USED_CLR(unit, entry.defip_mc_group);
  21045             } else {
  21046                 BCM_IF_ERROR_RETURN(_bcm_tr_ipmc_src_port_consistency_check(unit,
  21047                             lpm_cfg->defip_mc_group, &ipmc, 1, &need_write));
  21048             }
  21049         }
  21050 
  21051         if (need_write) {
  21052             /* Write L3_IPMC table entry. */
  21053             rv = bcm_tr_ipmc_write(unit, lpm_cfg->defip_mc_group, &ipmc);
  21054             if (BCM_FAILURE(rv)) {
  21055                 IPMC_DEFIP_USED_CLR(unit, entry.defip_mc_group);
  21056                 return (rv);
  21057             }
  21058         }
  21059     }
  21060 #endif
  21061 
  21062     if (BCM_GPORT_IS_BLACK_HOLE(lpm_cfg->defip_port_tgid)) {
  21063          nh_idx = 0;
  21064 #if defined(BCM_TRIDENT2PLUS_SUPPORT)         
  21065     } else if (soc_feature(unit, soc_feature_ipmc_defip) &&
  21066                 (lpm_cfg->defip_flags & BCM_L3_IPMC)) {
  21067         nh_idx = BCM_XGS3_L3_INVALID_INDEX;
  21068 #endif    
  21069     } else {
  21070          /* Validate forwarding path. */
  21071          if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) {
  21072               /* No path sanity checks for egress mode,         */
  21073               /* Path sanity done during egress object addition.*/
  21074               BCM_IF_ERROR_RETURN
  21075                    (bcm_xgs3_defip_path_validate(unit, lpm_cfg, old_route));
  21076          } else if (BCM_SUCCESS(lkup_result)){
  21077               if (!(lpm_cfg->defip_flags & BCM_L3_REPLACE)) {
  21078                    return (BCM_E_EXISTS);
  21079               }
  21080          }
  21081          /* Get next hop index. */
  21082          BCM_IF_ERROR_RETURN(_bcm_xgs3_nh_init_add(unit, NULL, lpm_cfg, &nh_idx));
  21083          if (soc_feature(unit, soc_feature_l3_extended_host_entry)) {
  21084             if (nh_idx == BCM_XGS3_L3_INVALID_INDEX) {
  21085                 return SOC_E_PARAM;
  21086             }
  21087          }
  21088     }
  21089 
  21090     /*
  21091      * If adding new paths to ECMP route, add new paths
  21092      * and update ecmp count in LPM table.
  21093      */
  21094     if (mpath) {
  21095         /* For egress switching mode just set the route entry. */
  21096         if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  21097            /* Validate NH idx */
  21098            if (BCM_XGS3_L3_INVALID_INDEX == nh_idx) {
  21099                return BCM_E_PARAM;
  21100            }
  21101 #ifdef BCM_TRIDENT2_SUPPORT
  21102            /* If an old ECMP group is replaced by a new one, and if
  21103             * they have members in common, the resilient hash flow set
  21104             * entries containing the shared members are copied from the old
  21105             * ECMP group to the new ECMP group, in order to minimize
  21106             * flow-to-member reassignments.
  21107             */
  21108            if ((SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT3X(unit)) &&
  21109                soc_feature(unit, soc_feature_ecmp_resilient_hash)) {
  21110                if (BCM_SUCCESS(lkup_result) &&
  21111                    (old_route->defip_flags & BCM_L3_MULTIPATH)) {
  21112                    BCM_IF_ERROR_RETURN(bcm_td2_l3_egress_ecmp_rh_shared_copy(unit,
  21113                                old_ecmp_grp, nh_idx));
  21114                }
  21115            }
  21116 #ifdef BCM_TOMAHAWK_SUPPORT
  21117            if ((SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit))&&
  21118                soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) {
  21119                if (BCM_SUCCESS(lkup_result) &&
  21120                    (old_route->defip_flags & BCM_L3_MULTIPATH)) {
  21121                    BCM_IF_ERROR_RETURN(bcm_opt_l3_egress_ecmp_rh_shared_copy(unit,
  21122                                old_ecmp_grp, nh_idx));
  21123                }
  21124            }
  21125 #endif /* BCM_TOMAHAWK_SUPPORT */
  21126 
  21127 #endif /* BCM_TRIDENT2_SUPPORT */
  21128            /* In egress mode increment path reference & update the route.*/
  21129            rv = _bcm_xgs3_defip_mpath_add(unit, lpm_cfg, nh_idx);
  21130         } else {
  21131            if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  21132                /* For non egress switching mode create ecmp group and route.*/
  21133                rv = _bcm_xgs3_defip_ecmp_add(unit, lpm_cfg, old_ecmp_grp, nh_idx);
  21134            } else {
  21135                return BCM_E_UNAVAIL;
  21136            }
  21137         }
  21138     } else {
  21139         /*  Add route to the hw. */
  21140         if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_add)) {
  21141             BCM_XGS3_L3_MODULE_LOCK(unit);
  21142             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_add) (unit, lpm_cfg, nh_idx);
  21143             BCM_XGS3_L3_MODULE_UNLOCK(unit);
  21144         }
  21145     }
  21146 
  21147     /* In case of route update decrement original path/group reference count. */
  21148     if ((BCM_SUCCESS(lkup_result)) && (BCM_SUCCESS(rv))) {
  21149         if(old_route->defip_flags & BCM_L3_MULTIPATH) {
  21150             /* Destroy ecmp group. Keep member next hops if new route is */
  21151             /* multipath as well, otherwise remove them.                 */
  21152             /* Never touch next hops attched to an egress object.        */
  21153             nh_remove = (!(mpath || BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)));
  21154             BCM_IF_ERROR_RETURN
  21155                 (_bcm_xgs3_ecmp_group_remove(unit, nh_ecmp_idx, nh_remove));
  21156         } else {
  21157             BCM_IF_ERROR_RETURN(bcm_xgs3_nh_del(unit, 0, nh_ecmp_idx));
  21158         }
  21159     }
  21160 
  21161     /* Regardless of status don't touch egress object multipath routes. */
  21162     if (mpath && BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  21163         return (rv);
  21164     }
  21165 
  21166     /* If route addition failed decrement next hop reference count. */
  21167     if (BCM_FAILURE(rv)) {
  21168         /* Free next hop entry. */
  21169         bcm_xgs3_nh_del(unit, 0, nh_idx);
  21170         /* Rollback for IPMC ref count */
  21171 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
  21172         if (soc_feature(unit, soc_feature_ipmc_defip) &&
  21173             (lpm_cfg->defip_flags & BCM_L3_IPMC)) {
  21174             if (new_entry) {
  21175                 IPMC_DEFIP_USED_CLR(unit, lpm_cfg->defip_mc_group);
  21176             } else if (entry.defip_mc_group != lpm_cfg->defip_mc_group) {
  21177                 IPMC_DEFIP_USED_SET(unit, entry.defip_mc_group);
  21178                 IPMC_DEFIP_USED_CLR(unit, lpm_cfg->defip_mc_group);
  21179             }
  21180         }
  21181 #endif /* BCM_TRIDENT2PLUS_SUPPORT */
  21182     }
  21183     return (rv);
  21184 }
  21185 
  21186 /*
  21187  * Function:
  21188  *      bcm_xgs3_defip_del
  21189  * Purpose:
  21190  *      Delete IP route from DEFIP table
  21191  * Parameters:
  21192  *      unit    - (IN)SOC unit number.
  21193  *      lpm_cfg - (IN)Deleted route information.
  21194  * Returns:
  21195  *      BCM_E_XXX
  21196  */
  21197 int
  21198 bcm_xgs3_defip_del(int unit, _bcm_defip_cfg_t *lpm_cfg)
  21199 {
  21200     _bcm_defip_cfg_t entry;     /* Lookup buffer.            */
  21201     int rv;                     /* Operation return status.  */
  21202     int nh_ecmp_idx = BCM_XGS3_L3_INVALID_INDEX;        /* Next hop/Ecmp group index. */
  21203     int lkup_result = BCM_E_UNAVAIL;    /* Lookup result.            */
  21204 
  21205     /* Input parameters checks. */
  21206     BCM_XGS3_L3_DEFIP_INVALID_PARAMS_RETURN(unit, lpm_cfg);
  21207 
  21208     /* Port trunk verification. */
  21209     if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) {
  21210         BCM_XGS3_L3_IF_INVALID_TGID_RETURN(unit, lpm_cfg->defip_flags,
  21211                                            lpm_cfg->defip_port_tgid);
  21212     }
  21213 
  21214     /* Set lookup key. */
  21215     entry = *lpm_cfg;
  21216 
  21217 #ifdef ALPM_ENABLE
  21218 #if defined(BCM_TOMAHAWK_SUPPORT)
  21219         if (soc_feature(unit, soc_feature_alpm2) &&
  21220             ALPMC(unit) && !ALPM_HIT_SKIP(unit)) {
  21221             entry.defip_flags |= BCM_L3_HIT_CLEAR;
  21222         }
  21223 #endif /* BCM_TOMAHAWK_SUPPORT */
  21224 #endif /* ALPM_ENABLE */
  21225 
  21226     /* Check if route exists. */
  21227     if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_get)) {
  21228         BCM_XGS3_L3_MODULE_LOCK(unit);
  21229         lkup_result = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_get) (unit, &entry,
  21230                                                               &nh_ecmp_idx);
  21231         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  21232     }
  21233     if (lkup_result < 0) {
  21234         return lkup_result;
  21235     }
  21236 
  21237     lpm_cfg->defip_flags_high = entry.defip_flags_high;
  21238     lpm_cfg->defip_index = entry.defip_index;
  21239     lpm_cfg->defip_alpm_cookie = entry.defip_alpm_cookie;
  21240 #ifdef ALPM_ENABLE
  21241     if (soc_feature(unit, soc_feature_alpm2)) {
  21242         lpm_cfg->l1_pvt_node = entry.l1_pvt_node;
  21243         lpm_cfg->pvt_node = entry.pvt_node;
  21244         lpm_cfg->bkt_node = entry.bkt_node;
  21245     }
  21246 #endif
  21247     if (entry.defip_flags & BCM_L3_IPMC &&
  21248             soc_feature(unit, soc_feature_ipmc_defip)) {
  21249         lpm_cfg->defip_flags |= BCM_L3_IPMC;
  21250     }
  21251     /* Remove path from hw. */
  21252     if (entry.defip_flags & BCM_L3_MULTIPATH) {
  21253         /* Trunslate next hop index to ecmp group id. */
  21254         if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  21255             nh_ecmp_idx /= BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  21256         }
  21257         rv = _bcm_xgs3_defip_ecmp_del(unit, lpm_cfg, nh_ecmp_idx);
  21258     } else {
  21259         rv = _bcm_xgs3_defip_del(unit, lpm_cfg, nh_ecmp_idx);
  21260     }
  21261 
  21262     if ((rv >= 0) && soc_feature(unit, soc_feature_ipmc_defip) &&
  21263             (entry.defip_flags & BCM_L3_IPMC)) {
  21264         if (entry.defip_mc_group) {
  21265             IPMC_DEFIP_USED_CLR(unit, entry.defip_mc_group);
  21266         }
  21267     }
  21268 
  21269     return rv;
  21270 }
  21271 
  21272 /*
  21273  * Function:
  21274  *      _bcm_xgs3_defip_intf_del_test_cb
  21275  * Purpose:
  21276  *      Test entries in DEFIP table by intf match.
  21277  * Parameters:
  21278  *      unit      - (IN)SOC unit number.
  21279  *      pattern   - (IN)Match pattern (interface id & negate).
  21280  *      data1     - (IN)Route info.
  21281  *      data2     - (IN)Next hop info.
  21282  *      cmp_result- (OUT)Comparison result.
  21283  * Returns:
  21284  *      BCM_E_XXX
  21285  */
  21286 STATIC int
  21287 _bcm_xgs3_defip_intf_del_test_cb(int unit, void *pattern,
  21288                                  void *data1, void *data2, int *cmp_result)
  21289 {
  21290     _bcm_l3_trvrs_data_t *trv_data;     /* Travers data.              */
  21291     _bcm_if_del_pattern_t *if_info;     /* Interface id/negate info.  */
  21292     _bcm_defip_cfg_t *lpm_cfg;          /* Route information.         */
  21293     int if_cmp_result = -1;             /* Interface compare result.  */
  21294     int nh_ecmp_idx;                    /* Next hop/ecmp group index. */
  21295     int ecmp_count = 0;                 /* Ecmp group size.           */
  21296     int *ecmp_grp;                      /* Ecmp group from hw.        */
  21297     int idx;                            /* Iteration index.           */
  21298     int rv;                             /* Operation return status.   */
  21299 
  21300     /* Cast input parameters. */
  21301     trv_data = (_bcm_l3_trvrs_data_t *) pattern;
  21302     if_info = (_bcm_if_del_pattern_t *) trv_data->pattern;
  21303     lpm_cfg = (_bcm_defip_cfg_t *) data1;
  21304     nh_ecmp_idx = *(int *)data2;
  21305 
  21306 
  21307     if (lpm_cfg->defip_ecmp) {
  21308         /* Translate next hop index to ecmp group id. */
  21309         if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  21310             nh_ecmp_idx /= BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  21311         }
  21312 
  21313         /* Allocate ecmp group buffer. */
  21314         BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp));
  21315 
  21316         /* If route is multipath get next hops from ecmp group. */
  21317          rv = _bcm_xgs3_ecmp_tbl_read(unit, nh_ecmp_idx,
  21318                                      ecmp_grp, &ecmp_count);
  21319          if (BCM_FAILURE(rv)) {
  21320              sal_free(ecmp_grp);
  21321              return (rv);
  21322          }
  21323 
  21324         /* Loop over all ecmp group members and check outgoing interface. */
  21325         for (idx = 0; idx < ecmp_count; idx++) {
  21326             rv = _bcm_xgs3_l3_nh_intf_cmp(unit, if_info->l3_intf,
  21327                                           ecmp_grp[idx], &if_cmp_result);
  21328             if (BCM_FAILURE(rv)) {
  21329                 sal_free(ecmp_grp);
  21330                 return (rv);
  21331             }
  21332             if (BCM_L3_CMP_EQUAL == *cmp_result) {
  21333                 break;
  21334             }
  21335         }                       /* Loop over ecmp group next hops. */
  21336         sal_free(ecmp_grp);
  21337     } else {
  21338         /* Check next hop outgoing interface. */
  21339         BCM_IF_ERROR_RETURN
  21340             (_bcm_xgs3_l3_nh_intf_cmp(unit, if_info->l3_intf,
  21341                                       nh_ecmp_idx, &if_cmp_result));
  21342     }
  21343 
  21344     /* Calculate final result based on negate and interface index comparison. */
  21345     if (BCM_XGS3_L3_IS_EQUAL(if_cmp_result, if_info->negate)) {
  21346         *cmp_result = BCM_L3_CMP_EQUAL;
  21347     } else {
  21348         *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  21349     }
  21350     return (BCM_E_NONE);
  21351 }
  21352 
  21353 
  21354 /*
  21355  * Function:
  21356  *      _bcm_xgs3_defip_intf_del_op_cb
  21357  * Purpose:
  21358  *      Delete entries in DEFIP table by intf match.
  21359  * Parameters:
  21360  *      unit      - (IN)SOC unit number.
  21361  *      pattern   - (IN)Match pattern (interface id & negate).
  21362  *      data1     - (IN)Route info.
  21363  *      data2     - (IN)Next hop info.
  21364  *      cmp_result- (OUT)Comparison result.
  21365  * Returns:
  21366  *      BCM_E_XXX
  21367  */
  21368 STATIC int
  21369 _bcm_xgs3_defip_intf_del_op_cb(int unit, void *pattern,
  21370                                void *data1, void *data2, int *cmp_result)
  21371 {
  21372     _bcm_l3_trvrs_data_t *trv_data;     /* Travers data.              */
  21373     _bcm_if_del_pattern_t *if_info;     /* Interface id/negate info.  */
  21374     _bcm_defip_cfg_t *lpm_cfg;          /* Route information.         */
  21375     int if_cmp_result;                  /* Interface compare result.  */
  21376     int nh_ecmp_idx;                    /* Next hop/ecmp group index. */
  21377     uint32 ecmp_flags = 0;                  /* Ecmp group flags */
  21378     int ecmp_count = 0;                 /* Ecmp group next hops count.*/
  21379     int *ecmp_grp;                      /* Ecmp group from hw.        */
  21380     int idx;                            /* Iteration index.           */
  21381     int rv;                             /* Operation return status.   */
  21382     int new_ecmp_count = 0;             /* New ecmp group nh count.   */
  21383 
  21384     /* Cast input parameters. */
  21385     trv_data = (_bcm_l3_trvrs_data_t *) pattern;
  21386     if_info = (_bcm_if_del_pattern_t *) trv_data->pattern;
  21387     lpm_cfg = (_bcm_defip_cfg_t *) data1;
  21388     nh_ecmp_idx = *(int *)data2;
  21389 
  21390     /* avoid route delete failure during callback in update match. */
  21391     lpm_cfg->defip_index = BCM_XGS3_L3_INVALID_INDEX;
  21392 
  21393     if (lpm_cfg->defip_ecmp) {  /* Multipath. */
  21394         /* Translate next hop index to ecmp group id. */
  21395         if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  21396             nh_ecmp_idx /= BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  21397         }
  21398 
  21399         /* Allocate ecmp group buffer. */
  21400         BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_grp));
  21401 
  21402         /* If route is multipath get next hops from ecmp group. */
  21403         rv = _bcm_xgs3_ecmp_tbl_read(unit, nh_ecmp_idx,
  21404                                      ecmp_grp, &ecmp_count);
  21405         if (BCM_FAILURE(rv)) {
  21406             sal_free(ecmp_grp);
  21407             return (rv);
  21408         }
  21409 
  21410         /* Loop over all ecmp group members and check outgoing interface. */
  21411         for (idx = 0; idx < ecmp_count; idx++) {
  21412             rv = _bcm_xgs3_l3_nh_intf_cmp(unit, if_info->l3_intf,
  21413                                           ecmp_grp[idx], &if_cmp_result);
  21414             if (BCM_FAILURE(rv)) {
  21415                 sal_free(ecmp_grp);
  21416                 return (rv);
  21417             }
  21418 
  21419             /* Update ecmp group based on comparison result. */
  21420             if (BCM_XGS3_L3_IS_EQUAL(if_cmp_result, if_info->negate)) {
  21421                 /* Overrite the entry with last group member. */
  21422                 ecmp_grp[idx] = ecmp_grp[ecmp_count - 1];
  21423                 BCM_XGS3_L3_DEC_IF_POSITIVE(ecmp_count);
  21424                 BCM_XGS3_L3_DEC_IF_POSITIVE(idx);
  21425             } else {
  21426                 new_ecmp_count++;
  21427             }
  21428         }
  21429 
  21430         /* If no paths left or at least one interface matches in
  21431            l3 egress switching mode, delete the route. */
  21432         if ((!new_ecmp_count) ||
  21433             ((new_ecmp_count != ecmp_count) &&
  21434              (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)))){
  21435             /* Unset multipath flag to indicate complete route deletion. */
  21436             lpm_cfg->defip_flags &= ~BCM_L3_MULTIPATH;
  21437             sal_free(ecmp_grp);
  21438             return _bcm_xgs3_defip_ecmp_del(unit, lpm_cfg, nh_ecmp_idx);
  21439         } else if (new_ecmp_count != ecmp_count) {
  21440             if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, nh_ecmp_idx,
  21441                               BCM_L3_ECMP_PATH_NO_SORTING)) {
  21442                 ecmp_flags |= BCM_L3_ECMP_PATH_NO_SORTING;
  21443             }
  21444             /* Next hops array changed rewrite ecmp group. */
  21445 #if defined(BCM_TOMAHAWK3_SUPPORT)
  21446             if ((*ecmp_grp < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2)) &&
  21447                 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode ==
  21448                                              ecmp_mode_hierarchical) &&
  21449                 (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl))) {
  21450                 ecmp_flags |= BCM_L3_ECMP_OVERLAY;
  21451             }
  21452 #endif
  21453 
  21454             rv = _bcm_xgs3_defip_ecmp_write(unit, lpm_cfg, ecmp_flags, ecmp_grp,
  21455                                             new_ecmp_count);
  21456             sal_free(ecmp_grp);
  21457             BCM_IF_ERROR_RETURN(rv);
  21458 
  21459             /* Free original ecmp group. */
  21460             BCM_IF_ERROR_RETURN(bcm_xgs3_ecmp_group_del(unit, nh_ecmp_idx, 0));
  21461         } else {
  21462             sal_free(ecmp_grp);
  21463             /* Else nothing changed don't touch the entry. */
  21464         }
  21465     } else {                    /* Single path. */
  21466         /* Check next hop outgoing interface. */
  21467         BCM_IF_ERROR_RETURN
  21468             (_bcm_xgs3_l3_nh_intf_cmp(unit, if_info->l3_intf,
  21469                                       nh_ecmp_idx, &if_cmp_result));
  21470         /* Based on comparison & negate decide to delete an entry or not. */
  21471         if (BCM_XGS3_L3_IS_EQUAL(if_cmp_result, if_info->negate)) {
  21472             BCM_IF_ERROR_RETURN
  21473                 (_bcm_xgs3_defip_del(unit, lpm_cfg, nh_ecmp_idx));
  21474         }
  21475         if (soc_feature(unit, soc_feature_ipmc_defip) &&
  21476                 (lpm_cfg->defip_flags & BCM_L3_IPMC)) {
  21477 
  21478             if (lpm_cfg->defip_mc_group) {
  21479                 IPMC_DEFIP_USED_CLR(unit, lpm_cfg->defip_mc_group);
  21480             }
  21481         }
  21482     }
  21483     return (BCM_E_NONE);
  21484 }
  21485 
  21486 /*
  21487  * Function:
  21488  *      bcm_xgs3_ip4_defip_del_intf
  21489  * Purpose:
  21490  *      Delete entries in DEFIP table by intf match.
  21491  * Parameters:
  21492  *      unit - SOC unit number.
  21493  *      defip - Pointer to memory for DEFIP table related information.
  21494  *      negate - 0 means interface match; 1 means not match
  21495  * Returns:
  21496  *      BCM_E_XXX
  21497  */
  21498 int
  21499 bcm_xgs3_defip_del_intf(int unit, _bcm_defip_cfg_t *lpm_cfg, int negate)
  21500 {
  21501     _bcm_l3_trvrs_data_t trv_data;     /* Travers initiator function input. */
  21502     _bcm_if_del_pattern_t pattern;      /* Interface & negate combination
  21503                                            to be used for comparision.      */
  21504     int rv = BCM_E_UNAVAIL;             /* Operation return value.          */
  21505 
  21506     bcm_l3_egress_t egr;                /* Egress object.                */
  21507     int nh_index;                       /* Next hop index.               */
  21508     bcm_if_t intf;                      /* Deleted interface id.         */
  21509 
  21510     /*  Make sure module was initialized. */
  21511     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  21512         return (BCM_E_INIT);
  21513     }
  21514 
  21515     /* Input parameters check */
  21516     if (NULL == lpm_cfg) {
  21517         return (BCM_E_PARAM);
  21518     }
  21519 
  21520     intf = lpm_cfg->defip_intf;
  21521 
  21522     /* Check l3 switching mode. */
  21523     if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  21524         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf) ||
  21525             BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) {
  21526             if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) {
  21527                 nh_index = intf - BCM_XGS3_EGRESS_IDX_MIN(unit);
  21528             } else {
  21529                 nh_index = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  21530             }
  21531             /* Get egress object information. */
  21532             BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, nh_index, &egr));
  21533             /* Use egress object interface for iteration */
  21534             intf = egr.intf;
  21535         }
  21536     }
  21537 
  21538     /* If table is empty -> there is nothing to delete. */
  21539     BCM_XGS3_L3_IF_DEFIP_CNT_ZERO_RETURN
  21540         (unit, (lpm_cfg->defip_flags & BCM_L3_IP6));
  21541 
  21542     /* Zero traverse info. */
  21543     sal_memset(&trv_data, 0, sizeof(_bcm_l3_trvrs_data_t));
  21544 
  21545     /* Set interface match pattern (interface index + negate) */
  21546     pattern.l3_intf = intf;
  21547     pattern.negate = negate;
  21548 
  21549     /* Fill traverse data struct. */
  21550     trv_data.flags = lpm_cfg->defip_flags | BCM_XGS3_L3_OP_DEL;
  21551     trv_data.pattern = (void *)&pattern;
  21552     trv_data.cmp_cb = _bcm_xgs3_defip_intf_del_test_cb;
  21553     trv_data.op_cb = _bcm_xgs3_defip_intf_del_op_cb;
  21554 
  21555     /*  Delete routes matching the pattern from hw. */
  21556     if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_update_match)) {
  21557         BCM_XGS3_L3_MODULE_LOCK(unit);
  21558         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_update_match) (unit, &trv_data);
  21559         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  21560     }
  21561     trv_data.flags &= ~BCM_XGS3_L3_OP_DEL;
  21562     return rv;
  21563 }
  21564 
  21565 /*
  21566  * Function:
  21567  *      _bcm_xgs3_defip_del_all_op_cb
  21568  * Purpose:
  21569  *      Delete all entries in DEFIP table.
  21570  * Parameters:
  21571  *      unit      - (IN)SOC unit number.
  21572  *      pattern   - (IN)Match pattern.
  21573  *      data1     - (IN)Route info.
  21574  *      data2     - (IN)Next hop info.
  21575  *      cmp_result- (OUT)Comparison result.
  21576  * Returns:
  21577  *      BCM_E_XXX
  21578  */
  21579 STATIC int
  21580 _bcm_xgs3_defip_del_all_op_cb(int unit, void *pattern,
  21581                               void *data1, void *data2, int *cmp_result)
  21582 {
  21583     _bcm_defip_cfg_t *lpm_cfg;  /* Route information.         */
  21584     int nh_ecmp_idx;            /* Next hop/ecmp group index. */
  21585     int rv;                     /* Operation return status.   */
  21586 
  21587     /* Cast input parameters. */
  21588     lpm_cfg = (_bcm_defip_cfg_t *) data1;
  21589     nh_ecmp_idx = *(int *)data2;
  21590 
  21591 #ifdef ALPM_ENABLE
  21592     /* If ALPM is enabled and it's TD2, keep defip_index */
  21593     if (!(SOC_IS_TRIDENT2(unit) &&
  21594           soc_property_get(unit, spn_L3_ALPM_ENABLE, 0) &&
  21595           soc_feature(unit, soc_feature_alpm)))
  21596 #endif
  21597     {
  21598         /* otherwise set it invalid to trigger lookup */
  21599         lpm_cfg->defip_index = BCM_XGS3_L3_INVALID_INDEX;
  21600     }
  21601 
  21602     /* clear hit bit */
  21603 #ifdef ALPM_ENABLE
  21604 #if defined(BCM_TOMAHAWK_SUPPORT)
  21605     if (soc_feature(unit, soc_feature_alpm2) && ALPMC(unit) && !ALPM_HIT_SKIP(unit)) {
  21606         int alpm_global_routes = 0;
  21607         if (!(lpm_cfg->defip_flags & BCM_L3_IPMC) &&
  21608         _soc_alpm_mode[unit] != 0 &&
  21609         (lpm_cfg->defip_vrf == BCM_L3_VRF_OVERRIDE ||
  21610          (lpm_cfg->defip_vrf == BCM_L3_VRF_GLOBAL &&
  21611          _soc_alpm_mode[unit] == 3))) {
  21612              alpm_global_routes = 1;
  21613         }
  21614         if (!alpm_global_routes) {
  21615             lpm_cfg->defip_flags |= BCM_L3_HIT_CLEAR;
  21616             /* Clear hit bit. */
  21617             if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_get)) {
  21618                 BCM_XGS3_L3_MODULE_LOCK(unit);
  21619                 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_get)(unit, lpm_cfg, NULL);
  21620                 BCM_XGS3_L3_MODULE_UNLOCK(unit);
  21621                 if (rv < 0) {
  21622                     return rv;
  21623                 }
  21624             }
  21625         } /* Don't clear Global Routes in ALPM mode */
  21626     }
  21627 #endif /* BCM_TOMAHAWK_SUPPORT */
  21628 #endif /* ALPM_ENABLE */
  21629 
  21630     if (lpm_cfg->defip_ecmp) {
  21631         /* Translate next hop index to ecmp group id. */
  21632         if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  21633             nh_ecmp_idx /= BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  21634         }
  21635         /*
  21636          * Reset multipath flag so the whole entry and not a specific path
  21637          * will be deleted.
  21638          */
  21639         lpm_cfg->defip_flags &= ~BCM_L3_MULTIPATH;
  21640         rv = _bcm_xgs3_defip_ecmp_del(unit, lpm_cfg, nh_ecmp_idx);
  21641     } else {
  21642         rv = _bcm_xgs3_defip_del(unit, lpm_cfg, nh_ecmp_idx);
  21643     }
  21644     if ((rv >= 0) &&
  21645             soc_feature(unit, soc_feature_ipmc_defip) &&
  21646             (lpm_cfg->defip_flags & BCM_L3_IPMC)) {
  21647 
  21648         if (lpm_cfg->defip_mc_group) {
  21649             IPMC_DEFIP_USED_CLR(unit, lpm_cfg->defip_mc_group);
  21650         }
  21651     }
  21652 
  21653     return rv;
  21654 }
  21655 
  21656 #ifdef ALPM_ENABLE
  21657 #if defined(BCM_TOMAHAWK3_SUPPORT)
  21658 /*
  21659  * Function:
  21660  *      _bcm_xgs3_defip_fast_del_all_op_cb
  21661  * Purpose:
  21662  *      Delete all entries in DEFIP table.
  21663  * Parameters:
  21664  *      unit      - (IN)SOC unit number.
  21665  *      pattern   - (IN)Match pattern.
  21666  *      data1     - (IN)Route info.
  21667  *      data2     - (IN)Next hop info.
  21668  *      cmp_result- (OUT)Comparison result.
  21669  * Returns:
  21670  *      BCM_E_XXX
  21671  */
  21672 STATIC int
  21673 _bcm_xgs3_defip_fast_del_all_op_cb(int unit, void *pattern,
  21674                                    void *data1, void *data2, int *cmp_result)
  21675 {
  21676     _bcm_defip_cfg_t *lpm_cfg;  /* Route information.         */
  21677     int nh_ecmp_idx;            /* Next hop/ecmp group index. */
  21678     int rv;                     /* Operation return status.   */
  21679 
  21680     /* Cast input parameters. */
  21681     lpm_cfg = (_bcm_defip_cfg_t *) data1;
  21682     nh_ecmp_idx = *(int *)data2;
  21683 
  21684     /* flag with fast_delete_all */
  21685     lpm_cfg->fast_delete_all = TRUE;
  21686 
  21687     if (lpm_cfg->defip_ecmp) {
  21688         /* Translate next hop index to ecmp group id. */
  21689         if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  21690             nh_ecmp_idx /= BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  21691         }
  21692         /*
  21693          * Reset multipath flag so the whole entry and not a specific path
  21694          * will be deleted.
  21695          */
  21696         lpm_cfg->defip_flags &= ~BCM_L3_MULTIPATH;
  21697         rv = _bcm_xgs3_defip_ecmp_del(unit, lpm_cfg, nh_ecmp_idx);
  21698     } else {
  21699         rv = _bcm_xgs3_defip_del(unit, lpm_cfg, nh_ecmp_idx);
  21700     }
  21701     if ((rv >= 0) &&
  21702             soc_feature(unit, soc_feature_ipmc_defip) &&
  21703             (lpm_cfg->defip_flags & BCM_L3_IPMC)) {
  21704 
  21705         if (lpm_cfg->defip_mc_group) {
  21706             IPMC_DEFIP_USED_CLR(unit, lpm_cfg->defip_mc_group);
  21707         }
  21708     }
  21709 
  21710     return rv;
  21711 }
  21712 #endif
  21713 #endif
  21714 
  21715 #if defined(BCM_TRIUMPH_SUPPORT)
  21716 /*
  21717  * Function:
  21718  *      bcm_xgs3_defip_verify_internal_mem_usage
  21719  * Purpose:
  21720  *      Verify if entries are present within INT-DEFIP table
  21721  * Parameters:
  21722  *      unit  - (IN)SOC unit number.
  21723  * Returns:
  21724  *      BCM_E_XXX
  21725  */
  21726 
  21727 int
  21728 bcm_xgs3_defip_verify_internal_mem_usage(int unit)
  21729 {
  21730 
  21731   if (soc_feature(unit, soc_feature_esm_support)) {
  21732     if (soc_mem_index_count(unit, L3_DEFIPm)) {
  21733       if (BCM_XGS3_L3_DEFIP_IP4_CNT(unit)) {
  21734         return BCM_E_DISABLED;
  21735       }
  21736 
  21737       if (BCM_XGS3_L3_DEFIP_IP6_CNT(unit)) {
  21738         return BCM_E_DISABLED;
  21739       }
  21740 
  21741     }
  21742     BCM_IF_ERROR_RETURN(_bcm_trx_l3_defip_verify_internal_mem_usage(unit));
  21743   }
  21744   return BCM_E_NONE;
  21745 }
  21746 #endif
  21747 
  21748 /*
  21749  * Function:
  21750  *      bcm_xgs3_defip_del_all
  21751  * Purpose:
  21752  *      Delete all entries in DEFIP table
  21753  * Parameters:
  21754  *      unit  - (IN)SOC unit number.
  21755  * Returns:
  21756  *      BCM_E_XXX
  21757  */
  21758 int
  21759 bcm_xgs3_defip_del_all(int unit)
  21760 {
  21761     _bcm_l3_trvrs_data_t trv_data;  /* Travers initiator parameters. */
  21762     int tmp_rv;                     /* First error occured.          */
  21763     int rv;                         /* Operation return status.      */
  21764 
  21765     tmp_rv = rv = BCM_E_NONE;
  21766 
  21767     /*  Make sure module was initialized. */
  21768     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  21769         return (BCM_E_INIT);
  21770     }
  21771 
  21772 #ifdef ALPM_ENABLE
  21773 #if defined(BCM_TOMAHAWK3_SUPPORT)
  21774     /* Hard delete_all for TH3 ALPM */
  21775     if (SOC_IS_TOMAHAWK3(unit) &&
  21776         soc_feature(unit, soc_feature_alpm2) &&
  21777         soc_property_get(unit, spn_L3_ALPM_ENABLE, 0)) {
  21778 
  21779         _bcm_l3_trvrs_data_t trv_data1;  /* ALPM route fast delete_all travers. */
  21780 
  21781         if ((BCM_XGS3_L3_DEFIP_IP4_CNT(unit) == 0) &&
  21782             (BCM_XGS3_L3_DEFIP_IP6_CNT(unit) == 0)) {
  21783             return rv;
  21784         }
  21785 
  21786         /* Zero traverse info. */
  21787         sal_memset(&trv_data, 0, sizeof(_bcm_l3_trvrs_data_t));
  21788         sal_memset(&trv_data1, 0, sizeof(_bcm_l3_trvrs_data_t));
  21789 
  21790         /* Fill traverse data struct. */
  21791         trv_data.op_cb = _bcm_xgs3_defip_del_all_op_cb;
  21792         trv_data1.op_cb = _bcm_xgs3_defip_fast_del_all_op_cb;
  21793 
  21794         BCM_XGS3_L3_MODULE_LOCK(unit);
  21795 
  21796         /*  Fast delete all (IPv4 & IPv6) by travel data */
  21797         rv = bcm_esw_alpm_cleanup(unit, &trv_data, &trv_data1);
  21798 
  21799         if (BCM_SUCCESS(rv)) {
  21800             BCM_XGS3_L3_DEFIP_IP4_CNT(unit) = 0;
  21801             BCM_XGS3_L3_DEFIP_IP6_CNT(unit) = 0;
  21802         }
  21803         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  21804         return rv;
  21805     }
  21806 #endif
  21807 #endif
  21808 
  21809     /* Make sure required hw call is defined. */
  21810     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_update_match)) {
  21811         return (BCM_E_UNAVAIL);
  21812     }
  21813 
  21814     /* Zero traverse info. */
  21815     sal_memset(&trv_data, 0, sizeof(_bcm_l3_trvrs_data_t));
  21816 
  21817     /* Fill traverse data struct. */
  21818     trv_data.op_cb = _bcm_xgs3_defip_del_all_op_cb;
  21819 
  21820     trv_data.flags = 0;
  21821     if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
  21822        trv_data.flags |= BCM_XGS3_L3_OP_GET_REVERSE;
  21823     }
  21824 
  21825     BCM_XGS3_L3_MODULE_LOCK(unit);
  21826     /*  Delete ipv4 routes matching the pattern from hw. */
  21827     if (BCM_XGS3_L3_DEFIP_IP4_CNT(unit)) {
  21828         tmp_rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_update_match) (unit,
  21829                                                                   &trv_data);
  21830     }
  21831 
  21832     /*  Delete ipv6 routes matching the pattern from hw. */
  21833     if (BCM_XGS3_L3_DEFIP_IP6_CNT(unit)) {
  21834         trv_data.flags |= BCM_L3_IP6;
  21835         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_update_match) (unit,
  21836                                                               &trv_data);
  21837     }
  21838     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  21839     return (tmp_rv < 0) ? tmp_rv : rv;
  21840 }
  21841 
  21842 /*
  21843  * Function:
  21844  *      _bcm_xgs3_defip_age_test_cb
  21845  * Purpose:
  21846  *      Test hit bit in DEFIP entries.
  21847  * Parameters:
  21848  *      unit      - (IN)SOC unit number.
  21849  *      pattern   - (IN)Match pattern.
  21850  *      data1     - (IN)Route info.
  21851  *      data2     - (IN)Next hop info.
  21852  *      cmp_result- (OUT)Comparison result.
  21853  * Returns:
  21854  *      BCM_E_XXX
  21855  */
  21856 STATIC int
  21857 _bcm_xgs3_defip_age_test_cb(int unit, void *pattern, void *data1,
  21858                             void *data2, int *cmp_result)
  21859 {
  21860     _bcm_defip_cfg_t *lpm_cfg;          /* Route information.        */
  21861 
  21862     /* Cast input parameters. */
  21863     lpm_cfg = (_bcm_defip_cfg_t *) data1;
  21864 
  21865     if (lpm_cfg->defip_flags & BCM_L3_HIT) {
  21866         *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  21867     } else {
  21868         *cmp_result = BCM_L3_CMP_EQUAL;
  21869     }
  21870     return (BCM_E_NONE);
  21871 }
  21872 
  21873 
  21874 /*
  21875  * Function:
  21876  *      _bcm_xgs3_defip_age_delete_cb
  21877  * Purpose:
  21878  *      Delete unused entries in DEFIP table
  21879  *      and notify the user.
  21880  * Parameters:
  21881  *      unit      - (IN)SOC unit number.
  21882  *      pattern   - (IN)Match pattern.
  21883  *      data1     - (IN)Route info.
  21884  *      data2     - (IN)Next hop info.
  21885  *      cmp_result- (OUT)Comparison result.
  21886  * Returns:
  21887  *      BCM_E_XXX
  21888  */
  21889 STATIC int
  21890 _bcm_xgs3_defip_age_delete_cb(int unit, void *pattern, void *data1,
  21891                        void *data2, int *cmp_result)
  21892 {
  21893     _bcm_defip_cfg_t *lpm_cfg;          /* Route information.        */
  21894     _bcm_l3_trvrs_data_t *trv_data;    /* Travers data.             */
  21895     int nh_ecmp_idx;                    /* Next hop/Ecmp group index.*/
  21896     int rv = BCM_E_NONE;                /* Operation return status.  */
  21897 
  21898     int alpm_global_routes = 0;
  21899 
  21900     /* Cast input parameters. */
  21901     trv_data = (_bcm_l3_trvrs_data_t *) pattern;
  21902     lpm_cfg = (_bcm_defip_cfg_t *) data1;
  21903     nh_ecmp_idx = *(int *)data2;
  21904 
  21905 #if defined(BCM_TRIDENT2_SUPPORT)
  21906     if (!(lpm_cfg->defip_flags & BCM_L3_IPMC) &&
  21907         _soc_alpm_mode[unit] != 0 &&
  21908         (lpm_cfg->defip_vrf == BCM_L3_VRF_OVERRIDE ||
  21909          lpm_cfg->defip_vrf == BCM_L3_VRF_GLOBAL)) {
  21910          alpm_global_routes = 1;
  21911     }
  21912 #endif
  21913 
  21914     if (!(lpm_cfg->defip_flags & BCM_L3_HIT)) {
  21915         /* avoid route delete failure during callback in update match. */
  21916         lpm_cfg->defip_index = BCM_XGS3_L3_INVALID_INDEX;
  21917         /* Remove path from hw. */
  21918         if (!alpm_global_routes) {
  21919             if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) {
  21920                 /* Unset multipath flag -> so all route path's can be deleted. */
  21921                 lpm_cfg->defip_flags &= ~BCM_L3_MULTIPATH;
  21922                 rv = _bcm_xgs3_defip_ecmp_del(unit, lpm_cfg, nh_ecmp_idx);
  21923             } else {
  21924                 rv = _bcm_xgs3_defip_del(unit, lpm_cfg, nh_ecmp_idx);
  21925             }
  21926         } /* Don't delete Global Routes in ALPM mode */
  21927 
  21928         if ((rv >= 0) &&
  21929                 soc_feature(unit, soc_feature_ipmc_defip) &&
  21930                 (lpm_cfg->defip_flags & BCM_L3_IPMC)) {
  21931 
  21932             if (lpm_cfg->defip_mc_group) {
  21933                 IPMC_DEFIP_USED_CLR(unit, lpm_cfg->defip_mc_group);
  21934             }
  21935         }
  21936         /* Notify caller regarding unused entry. */
  21937         _bcm_xgs3_lpm_call_user_cb(unit, trv_data, lpm_cfg,
  21938                                    BCM_XGS3_L3_INVALID_INDEX);
  21939     }
  21940     return (rv);
  21941 }
  21942 
  21943 
  21944 /*
  21945  * Function:
  21946  *      _bcm_xgs3_defip_age_clear_hit_cb
  21947  * Purpose:
  21948  *      Age entries in DEFIP table and notify the user.
  21949  * Parameters:
  21950  *      unit      - (IN)SOC unit number.
  21951  *      pattern   - (IN)Match pattern.
  21952  *      data1     - (IN)Route info.
  21953  *      data2     - (IN)Next hop info.
  21954  *      cmp_result- (OUT)Comparison result.
  21955  * Returns:
  21956  *      BCM_E_XXX
  21957  */
  21958 STATIC int
  21959 _bcm_xgs3_defip_age_clear_hit_cb(int unit, void *pattern, void *data1,
  21960                                  void *data2, int *cmp_result)
  21961 {
  21962     _bcm_defip_cfg_t *lpm_cfg;          /* Route information.        */
  21963     int rv = BCM_E_NONE;                /* Operation return status.  */
  21964     int alpm_global_routes = 0;
  21965 
  21966     /* Comparison is always false - since no action required. */
  21967     *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  21968 
  21969     /* Cast input parameters. */
  21970     lpm_cfg =  (_bcm_defip_cfg_t *) data1;
  21971 
  21972 #if defined(BCM_TRIDENT2_SUPPORT)
  21973     if (!(lpm_cfg->defip_flags & BCM_L3_IPMC) &&
  21974         _soc_alpm_mode[unit] != 0 &&
  21975         (lpm_cfg->defip_vrf == BCM_L3_VRF_OVERRIDE ||
  21976          (lpm_cfg->defip_vrf == BCM_L3_VRF_GLOBAL &&
  21977          _soc_alpm_mode[unit] == 3))) {
  21978          alpm_global_routes = 1;
  21979     }
  21980 #endif
  21981 
  21982     if (lpm_cfg->defip_flags & BCM_L3_HIT) {
  21983         if (!alpm_global_routes) {
  21984             lpm_cfg->defip_flags |= BCM_L3_HIT_CLEAR;
  21985 
  21986             /* Clear hit bit. */
  21987             if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_get)) {
  21988                 BCM_XGS3_L3_MODULE_LOCK(unit);
  21989                 rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_get)(unit, lpm_cfg, NULL);
  21990                 BCM_XGS3_L3_MODULE_UNLOCK(unit);
  21991                 if (rv < 0) {
  21992                     return rv;
  21993                 }
  21994             }
  21995         } /* Don't clear Global Routes in ALPM mode */
  21996     }
  21997     return (BCM_E_NONE);
  21998 }
  21999 
  22000 /*
  22001  * Function:
  22002  *    bcm_xgs3_defip_age
  22003  * Purpose:
  22004  *    Age out the DEFIP table
  22005  * Parameters:
  22006  *      unit      - (IN)SOC unit number.
  22007  *      flags     - (IN)IPv4/IPv6.
  22008  *      age_out   - (IN)age_out Notification callback.
  22009  *      user_data - (IN)User provided cookie for callback.
  22010  * Returns:
  22011  *      BCM_E_XXX
  22012  */
  22013 int
  22014 _bcm_xgs3_defip_age(int unit, int flags, bcm_l3_route_traverse_cb age_out,
  22015                     void *user_data)
  22016 {
  22017     _bcm_l3_trvrs_data_t trv_data;     /* Travers initiator parameters. */
  22018     int rv = BCM_E_UNAVAIL;             /* Operation return status.      */
  22019 
  22020     /* If table is empty -> there is nothing to delete. */
  22021     BCM_XGS3_L3_IF_DEFIP_CNT_ZERO_RETURN(unit, flags & BCM_L3_IP6);
  22022 
  22023     /* Zero traverse info. */
  22024     sal_memset(&trv_data, 0, sizeof(_bcm_l3_trvrs_data_t));
  22025 
  22026     /* Fill traverse data struct. */
  22027     trv_data.flags = flags;
  22028     /* We need to set both operational & test callback since firebolt
  22029        never executes test routine. */
  22030     trv_data.cmp_cb = _bcm_xgs3_defip_age_test_cb;
  22031     trv_data.op_cb = _bcm_xgs3_defip_age_delete_cb;
  22032     trv_data.defip_cb = age_out;
  22033     trv_data.cookie   = user_data;
  22034 
  22035     /*  Age routes matching the pattern from hw. */
  22036     if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_update_match)) {
  22037         BCM_XGS3_L3_MODULE_LOCK(unit);
  22038         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_update_match) (unit, &trv_data);
  22039         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  22040     }
  22041     /*  Clear hit bit for the rest of the routes. */
  22042     trv_data.cmp_cb = _bcm_xgs3_defip_age_clear_hit_cb;
  22043     trv_data.op_cb = _bcm_xgs3_defip_age_clear_hit_cb;
  22044     if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_update_match)) {
  22045         BCM_XGS3_L3_MODULE_LOCK(unit);
  22046         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_update_match) (unit, &trv_data);
  22047         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  22048     }
  22049     return rv;
  22050 }
  22051 
  22052 /*
  22053  * Function:
  22054  *    bcm_xgs3_defip_age
  22055  * Purpose:
  22056  *    Age out DEFIP table
  22057  * Parameters:
  22058  *      unit     - (IN)SOC unit number.
  22059  *      age_out  - (IN)age_out Notification callback.
  22060  *      user_data - (IN)User provided cookie for callback.
  22061  * Returns:
  22062  *      BCM_E_XXX
  22063  */
  22064 int
  22065 bcm_xgs3_defip_age(int unit, bcm_l3_route_traverse_cb age_out, void *user_data)
  22066 {
  22067     int rv;                  /* Operation return status. */
  22068     int tmp_rv;              /* First error occured.     */
  22069 
  22070     /*  Make sure module was initialized. */
  22071     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  22072         return (BCM_E_INIT);
  22073     }
  22074 
  22075     /* Age all ipv4 entries. */
  22076     tmp_rv = _bcm_xgs3_defip_age(unit, 0, age_out, user_data);
  22077 
  22078     /* Age all ipv6 entries. */
  22079     rv = _bcm_xgs3_defip_age(unit, BCM_L3_IP6, age_out, user_data);
  22080 
  22081     return (tmp_rv < 0) ? tmp_rv : rv;
  22082 }
  22083 
  22084 #ifdef BCM_WARM_BOOT_SUPPORT
  22085 
  22086 /*
  22087  * Function:
  22088  *      _bcm_xgs3_l3_ecmp_group_hash_calc
  22089  * Purpose:
  22090  *      Calculate ecmp group next hops hash(signature).
  22091  * Parameters:
  22092  *      unit                        -  (IN)SOC unit number.
  22093  *      ecmp_group_index  - (IN)Ecmp group index
  22094  *      ecmp_group   - (IN)Ecmp group.
  22095  *      ecmp_count   - (IN)Ecmp group next hops count.
  22096  *      hash     -  (OUT) Hash(signature) calculated value.
  22097  * Returns:
  22098  *      BCM_X_XXX
  22099  */
  22100 STATIC int
  22101 _bcm_xgs3_l3_ecmp_group_hash_calc(int unit, int ecmp_group_index,
  22102                                   int *ecmp_group, int ecmp_count, uint16 *hash)
  22103 {
  22104     int  rv = BCM_E_NONE;
  22105     int *dlb_ecmp_group = NULL;
  22106     _bcm_l3_ecmp_group_buffer_t ecmp_buffer;
  22107 
  22108 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  22109     if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
  22110         bcm_l3_egress_ecmp_t ecmp;
  22111         int location_offset = 0;
  22112         int primary_count = 0;
  22113         int i = 0, j = 0;
  22114         int ecmp_max_paths = 0;
  22115         SHR_BITDCL *group_bitmap_ptr = NULL;
  22116 
  22117         bcm_l3_egress_ecmp_t_init(&ecmp);
  22118         ecmp.ecmp_intf = ecmp_group_index  + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  22119         rv = bcm_th2_l3_egress_ecmp_dlb_get(unit, &ecmp);
  22120         if (BCM_FAILURE(rv)) {
  22121             return rv;
  22122         }
  22123 
  22124         if (BCM_TH2_ECMP_IS_DLB_OR_DGM(unit, ecmp.dynamic_mode)) {
  22125             rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_index,
  22126                                                  &ecmp_max_paths);
  22127             if (BCM_FAILURE(rv)) {
  22128                 return rv;
  22129             }
  22130 
  22131             group_bitmap_ptr =
  22132                 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_index);
  22133 
  22134             if (ecmp.dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) {
  22135                 SHR_BITCOUNT_RANGE(group_bitmap_ptr, primary_count,
  22136                                    0, ecmp_max_paths / 2);
  22137                 /* Only alternate members exist */
  22138                 if (0 == primary_count) {
  22139                     location_offset = ecmp_max_paths / 2;
  22140                 }
  22141             }
  22142             /* Allocate DLB ecmp group buffer. */
  22143             rv = _bcm_xgs3_l3_ecmp_group_alloc(unit, &dlb_ecmp_group);
  22144             if (BCM_FAILURE(rv)) {
  22145                 return rv;
  22146             }
  22147 
  22148             /* Exclude filler members from expanded DLB group */
  22149             for (i = 0; i < ecmp_count; i++) {
  22150                 if (SHR_BITGET(group_bitmap_ptr, i + location_offset)) {
  22151                     dlb_ecmp_group[j++] = ecmp_group[i];
  22152                 }
  22153             }
  22154             ecmp_buffer.dlb_group_buffer = dlb_ecmp_group;
  22155         } else {
  22156             ecmp_buffer.dlb_group_buffer = NULL;
  22157         }
  22158     }else
  22159 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT */
  22160     {
  22161         ecmp_buffer.dlb_group_buffer = NULL;
  22162     }
  22163 
  22164     ecmp_buffer.group_buffer = ecmp_group;
  22165 
  22166     /* Compute signature and reference count for ECMP group */
  22167     _bcm_xgs3_ecmp_grp_hash_calc(unit, (void *)&ecmp_buffer, hash);
  22168 
  22169     if (dlb_ecmp_group) {
  22170         sal_free(dlb_ecmp_group);
  22171     }
  22172 
  22173     return rv;
  22174 }
  22175 
  22176 /*
  22177  * Function:
  22178  *      _bcm_xgs3_defip_state_recover
  22179  * Purpose:
  22180  *      Recover route table references & usage counters
  22181  *      after warm reboot.
  22182  * Parameters:
  22183  *      unit        - (IN)SOC unit number.
  22184  *      lpm_cfg     - (IN)Route info.
  22185  *      nh_ecmp_idx - (IN)Next hop /Ecmp group index.
  22186  * Returns:
  22187  *      BCM_E_XXX
  22188  */
  22189 STATIC int
  22190 _bcm_xgs3_defip_state_recover(int unit, _bcm_defip_cfg_t *lpm_cfg, int
  22191                               nh_ecmp_idx)
  22192 
  22193 {
  22194     int *ecmp_group;                        /* Ecmp group from hw.      */
  22195     int ecmp_count;                         /* Ecmp group size.         */
  22196     _bcm_l3_tbl_t *nh_tbl_ptr;              /* Next hop table ptr.      */
  22197     _bcm_l3_tbl_t *ecmp_tbl_ptr;            /* ECMP table ptr.          */
  22198     int rv;                                 /* Operation return status. */
  22199 
  22200     /* Get table pointers */
  22201     nh_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop);
  22202     ecmp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  22203 
  22204 #ifdef BCM_TOMAHAWK3_SUPPORT
  22205     if ((BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == ecmp_mode_hierarchical)
  22206          && (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl)) &&
  22207             (nh_ecmp_idx < (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2))) {
  22208         ecmp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp);
  22209     }
  22210 #endif
  22211 
  22212     /* Allocate ecmp group buffer. */
  22213     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_group));
  22214 
  22215     /* Update defip book-keeping info */
  22216     if ((lpm_cfg->defip_flags & BCM_L3_IP6) == BCM_L3_IP6) {
  22217         BCM_XGS3_L3_DEFIP_IP6_CNT(unit)++;
  22218     } else {
  22219         BCM_XGS3_L3_DEFIP_IP4_CNT(unit)++;
  22220     }
  22221 
  22222     if (lpm_cfg->defip_ecmp) {
  22223          /* Translate ecmp index to ecmp group id. */
  22224          if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  22225               nh_ecmp_idx /= BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  22226          }
  22227 
  22228         /* Increment ecmp group reference count. */
  22229         BCM_XGS3_L3_ENT_REF_CNT_INC(ecmp_tbl_ptr, nh_ecmp_idx, 
  22230                                     BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  22231                                     _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE);
  22232 
  22233         /* If route is multipath get next hops from ecmp group. */
  22234         rv = _bcm_xgs3_ecmp_tbl_read(unit, nh_ecmp_idx,
  22235                                      ecmp_group, &ecmp_count);
  22236         if (BCM_FAILURE(rv)) {
  22237             sal_free(ecmp_group);
  22238             return (rv);
  22239         }
  22240 
  22241         /* Set ecmp in use flag if needed. */
  22242         if (!BCM_XGS3_L3_ECMP_IN_USE(unit)) {
  22243             BCM_XGS3_L3_ECMP_IN_USE(unit) = TRUE;
  22244         }
  22245 
  22246         rv = _bcm_xgs3_l3_ecmp_group_hash_calc(
  22247                  unit, nh_ecmp_idx, ecmp_group, ecmp_count,
  22248                              &BCM_XGS3_L3_ENT_HASH(ecmp_tbl_ptr, nh_ecmp_idx));
  22249         if (BCM_FAILURE(rv)) {
  22250             sal_free(ecmp_group);
  22251             return (rv);
  22252         }
  22253     } else {  /* Unipath route. */
  22254         /* Set reference count to nh_hop table entry */
  22255         BCM_XGS3_L3_ENT_REF_CNT_INC(nh_tbl_ptr, nh_ecmp_idx,
  22256                                     _BCM_SINGLE_WIDE);
  22257     }
  22258     sal_free(ecmp_group);
  22259     return (BCM_E_NONE);
  22260 }
  22261 
  22262 /*
  22263  * Function:
  22264  *      _bcm_xgs3_l3_ecmp_reinit
  22265  * Purpose:
  22266  *      Recover basic ECMP groups table info
  22267  * Parameters:
  22268  *      unit  - SOC unit number
  22269  * Returns:
  22270  *      BCM_E_XXX
  22271  */
  22272 STATIC int
  22273 _bcm_xgs3_l3_ecmp_reinit(int unit, int ecmp_max_paths, int *ecmp_refcnt)
  22274 {
  22275     int index_min;                /* First entry index.            */
  22276     int index_max;                /* Last  entry index.            */
  22277     int idx;
  22278     uint32 entry[SOC_MAX_MEM_WORDS];        /* Buffer.                       */
  22279     _bcm_l3_tbl_t *nh_tbl_ptr;              /* Next hop table ptr.      */
  22280     _bcm_l3_tbl_t *ecmp_tbl_ptr;            /* ECMP table ptr.          */
  22281     int *ecmp_group;
  22282     int rv=0, ecmp_count=0;
  22283     int nh_idx=0, grp_idx=0, grp_max_idx=0, grp_min_idx=0;
  22284     int ecmp_grp_idx = 0;
  22285     int ecmp_grp_record_width = _BCM_SINGLE_WIDE;
  22286     uint16 entry_hash = 0;
  22287     char *l3_tbl_ptr  = NULL;            /* Table dma pointer.             */
  22288     _bcm_l3_cfg_t l3_cfg;	                /* Extracted L3 entry            */
  22289 
  22290     sal_memset(entry , 0, SOC_MAX_MEM_WORDS * sizeof(uint32));
  22291 
  22292 #if defined(BCM_HAWKEYE_SUPPORT)
  22293     if (SOC_IS_HAWKEYE(unit)) {
  22294         BCM_XGS3_L3_ECMP_TBL_SIZE(unit) = 0;
  22295         BCM_XGS3_L3_ECMP_MAX_PATHS(unit) = 0;
  22296         return BCM_E_NONE;
  22297     }
  22298 #endif
  22299     if (SOC_IS_HURRICANE(unit) || SOC_IS_HURRICANE2(unit)) {
  22300         BCM_XGS3_L3_ECMP_TBL_SIZE(unit) = 0;
  22301         BCM_XGS3_L3_ECMP_MAX_PATHS(unit) = 0;
  22302         return BCM_E_NONE;
  22303     }
  22304 
  22305     if (soc_feature(unit, soc_feature_l3_no_ecmp)) {
  22306         BCM_XGS3_L3_ECMP_TBL_SIZE(unit) = 0;
  22307         BCM_XGS3_L3_ECMP_MAX_PATHS(unit) = 0;
  22308         return BCM_E_NONE;
  22309     }
  22310     /* Get table pointers */
  22311     nh_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop);
  22312     ecmp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  22313 
  22314     /* Get ECMP table start & end index. */
  22315     ecmp_tbl_ptr->idx_min = index_min =
  22316 	   soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, ecmp));
  22317     ecmp_tbl_ptr->idx_max = index_max =
  22318 	   soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, ecmp));
  22319     BCM_XGS3_L3_ECMP_TBL_SIZE(unit) = index_max - index_min + 1;
  22320     ecmp_tbl_ptr->idx_maxused = ecmp_tbl_ptr->idx_min;
  22321 
  22322 #ifdef BCM_TRIUMPH2_SUPPORT
  22323     BCM_XGS3_L3_MAX_ECMP_MODE(unit) = (SOC_IS_TRIUMPH3(unit)) ? TRUE :
  22324                            soc_property_get(unit, spn_L3_MAX_ECMP_MODE, 0);
  22325 #endif /* BCM_TRIUMPH2_SUPPORT */
  22326 
  22327     /* Restore ECMP max paths info (from level 2 recovery) */
  22328     /* For level-1 warmboot, leave the value at its default */
  22329     if (ecmp_max_paths != 0) {
  22330         BCM_XGS3_L3_ECMP_MAX_PATHS(unit) = ecmp_max_paths;
  22331     }
  22332 
  22333     /* Initialize the number of ECMP groups */
  22334     ecmp_tbl_ptr->idx_max = BCM_XGS3_L3_ECMP_TBL_SIZE(unit) /
  22335 	    	       BCM_XGS3_L3_ECMP_MAX_PATHS(unit) - 1;
  22336 
  22337     grp_max_idx = ecmp_tbl_ptr->idx_max;
  22338 
  22339     if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  22340         if (!BCM_XGS3_L3_MAX_ECMP_MODE(unit)) {
  22341             /* Here, the max possible groups (and max group index) is limited by
  22342              * the size of L3_ECMP_COUNTm table. To support dynamic
  22343              * per-ecmp-group size, two entries are added to the L3_ECMP_COUNTm
  22344              * table per group:
  22345              *
  22346              * L3_ECMP_COUNTm Table:
  22347              *        Group # Entry idx   COUNTf
  22348              *          0 ------> 0     Current ecmp path count for group 0.
  22349              *                    1     Max size for group 0.
  22350              *          2 ------> 2     Current ecmp path count for group 2.
  22351              *                    3     Max size for group 2.
  22352              *         ...so on...
  22353              *  (Tbl size - 2)-->(Tbl size-2)  Current path count for this group.
  22354              *                   (Tbl size-1)  Max size for this group.
  22355  */
  22356             grp_max_idx = soc_mem_index_count(unit, L3_ECMP_COUNTm) - 2;
  22357             ecmp_tbl_ptr->idx_max = grp_max_idx + 1;
  22358         } else {
  22359             grp_max_idx = soc_mem_index_count(unit, L3_ECMP_COUNTm) - 1;
  22360             ecmp_tbl_ptr->idx_max = grp_max_idx;
  22361         }
  22362     }
  22363 
  22364 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
  22365     /* if there is split in table then set split range */
  22366     bcmi_xgs3_l3_ecmp_tbl_split_range_init(unit, ecmp_tbl_ptr);
  22367 #endif
  22368 
  22369     /*
  22370      * Determine the group entry-width.
  22371      * This logic should be in sync with that in _bcm_xgs3_ecmp_group_add
  22372      */
  22373 #ifdef BCM_TRX_SUPPORT
  22374     if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  22375         if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  22376             if (soc_feature(unit, soc_feature_l3_ecmp_1k_groups)) {
  22377                 ecmp_grp_record_width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  22378                     _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  22379 #ifdef BCM_TRIUMPH3_SUPPORT
  22380                 if (SOC_IS_TRIUMPH3(unit)) {
  22381                     ecmp_grp_record_width = _BCM_SINGLE_WIDE;
  22382                 }
  22383 #endif
  22384             } else if (SOC_IS_TRIDENT(unit)) {
  22385                 ecmp_grp_record_width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  22386                     _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  22387             } else if (SOC_IS_SCORPION(unit)) {
  22388                 ecmp_grp_record_width = ecmp_max_paths;
  22389             } else {
  22390                 ecmp_grp_record_width = ecmp_max_paths;
  22391                 if (SOC_IS_TRIUMPH2(unit) ||
  22392                         SOC_IS_APOLLO(unit) ||
  22393                         SOC_IS_VALKYRIE2(unit) ||
  22394                         SOC_IS_KATANAX(unit) ||
  22395                         SOC_IS_GREYHOUND(unit) ||
  22396                         SOC_IS_HURRICANE3(unit) ||
  22397                         SOC_IS_GREYHOUND2(unit)) {
  22398                     ecmp_grp_record_width = BCM_XGS3_L3_MAX_ECMP_MODE(unit) ?
  22399                         _BCM_SINGLE_WIDE : _BCM_DOUBLE_WIDE;
  22400                 }
  22401             }
  22402         }
  22403     }
  22404 #endif  /* BCM_TRX_SUPPORT */
  22405 
  22406 #ifdef BCM_TRIUMPH3_SUPPORT
  22407     
  22408     if (soc_feature(unit, soc_feature_ecmp_dlb)) {
  22409 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  22410         if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
  22411             BCM_IF_ERROR_RETURN(bcm_th2_ecmp_dlb_hw_recover(unit));
  22412         } else
  22413 #endif /* BCM_TOMAHAWK2_SUPPORT */
  22414         {
  22415             BCM_IF_ERROR_RETURN(bcm_tr3_ecmp_dlb_hw_recover(unit));
  22416         }
  22417     }
  22418 #endif /* BCM_TRIUMPH3_SUPPORT */
  22419 
  22420     /* Allocate ecmp group buffer */
  22421     BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_group));
  22422 
  22423     grp_min_idx = ecmp_tbl_ptr->idx_min;
  22424 
  22425 #ifdef BCM_TOMAHAWK3_SUPPORT
  22426     if ((BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == ecmp_mode_hierarchical)
  22427          && (soc_feature(unit, soc_feature_l3_ecmp_hier_tbl))) {
  22428         _bcm_l3_tbl_t *hecmp_tbl_ptr;  /* HECMP table ptr. */
  22429 
  22430         hecmp_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, hecmp_grp);
  22431         grp_min_idx = (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / 2);
  22432         for (grp_idx = hecmp_tbl_ptr->idx_min; grp_idx <= hecmp_tbl_ptr->idx_max;) {
  22433              int ecmp_idx = 0;
  22434              int max_ecmp_cnt;
  22435              /* Increment ECMP group reference count. */
  22436              BCM_XGS3_L3_ENT_REF_CNT_INC(hecmp_tbl_ptr, grp_idx,
  22437                      ecmp_grp_record_width);
  22438 
  22439              /* Get next hops from ECMP group */
  22440              sal_memset(ecmp_group, 0, sizeof(int) * BCM_XGS3_L3_ECMP_MAX(unit));
  22441              rv = _bcm_xgs3_ecmp_tbl_read(unit, grp_idx, ecmp_group, &ecmp_count);
  22442              if (BCM_FAILURE(rv)) {
  22443                  sal_free(ecmp_group);
  22444                  return (rv);
  22445              }
  22446 
  22447              if ((ecmp_refcnt[grp_idx] < 1)) {
  22448                 BCM_XGS3_L3_ENT_REF_CNT_DEC(hecmp_tbl_ptr, grp_idx,
  22449                         ecmp_grp_record_width);
  22450 
  22451                 /*
  22452                  * There maybe entries starting at any index when added
  22453                  * with specific ID. Look for the immediate next index.
  22454                  */
  22455                 grp_idx+=1;
  22456                 continue;
  22457              }
  22458 
  22459              /* Set ecmp in use flag if needed. */
  22460              if (!BCM_XGS3_L3_ECMP_IN_USE(unit)) {
  22461                   BCM_XGS3_L3_ECMP_IN_USE(unit) = TRUE;
  22462              }
  22463 
  22464              /* Compute signature and reference count for ECMP group */
  22465              rv = _bcm_xgs3_l3_ecmp_group_hash_calc(unit, grp_idx, ecmp_group,
  22466                                                      ecmp_count, &entry_hash);
  22467              if (BCM_FAILURE(rv)) {
  22468                  sal_free(ecmp_group);
  22469                  return (rv);
  22470              }
  22471 
  22472              BCM_XGS3_L3_ENT_HASH_UPDATE(hecmp_tbl_ptr, grp_idx,
  22473                      ecmp_grp_record_width, entry_hash);
  22474 
  22475              /* Loop over all ecmp group members and increment nh reference count.*/
  22476              for (nh_idx = 0; nh_idx < ecmp_count; nh_idx++) {
  22477                   /* Skip over members that are not NH indices */
  22478                   if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit,
  22479                                              ecmp_group[nh_idx])) {
  22480                       continue;
  22481                   }
  22482                   BCM_XGS3_L3_ENT_REF_CNT_INC(nh_tbl_ptr, ecmp_group[nh_idx],
  22483                                               _BCM_SINGLE_WIDE);
  22484              }
  22485              /* Update max table index used */
  22486              if (hecmp_tbl_ptr->idx_maxused < grp_idx) {
  22487                  hecmp_tbl_ptr->idx_maxused = grp_idx;
  22488              }
  22489 
  22490              BCM_IF_ERROR_RETURN(
  22491                  _bcm_xgs3_l3_ecmp_grp_info_get(unit, grp_idx,
  22492                                                 NULL, &ecmp_idx));
  22493 
  22494              max_ecmp_cnt = 0;
  22495              rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, grp_idx, &max_ecmp_cnt);
  22496              if (BCM_FAILURE(rv)) {
  22497                  return rv;
  22498              }
  22499 
  22500              BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ecmp),
  22501                                              ecmp_idx, max_ecmp_cnt);
  22502 
  22503              BCM_XGS3_L3_ECMP_GRP_CNT(unit)++;
  22504 
  22505              /*
  22506               * Record was found. Next index will be after this
  22507               * record's width.
  22508               */
  22509              grp_idx+=ecmp_grp_record_width;
  22510         }
  22511     }
  22512 #endif
  22513 
  22514     for (grp_idx = grp_min_idx; grp_idx <= grp_max_idx;) {
  22515 #ifdef BCM_TRIDENT2_SUPPORT
  22516        /* In Trident2, VP LAGs share the same table as ECMP group table.
  22517         * The first N entries are reserved for VP LAGs, where N is the
  22518         * value of the config property max_vp_lags.
  22519         */
  22520         if (soc_feature(unit, soc_feature_vp_lag)) {
  22521             int max_vp_lags;
  22522 
  22523             max_vp_lags = soc_property_get(unit, spn_MAX_VP_LAGS,
  22524                     soc_mem_index_count(unit, EGR_VPLAG_GROUPm));
  22525 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
  22526             /*
  22527              * TD2P has split indexes for overlay and underlay.
  22528              * vp lags are in second range for underlay domain.
  22529              * therefore skip indexes which are reserved for vp lag.
  22530              */
  22531             if ((ecmp_tbl_ptr->split_idx > 0)) {
  22532 
  22533                 if ((grp_idx >= ecmp_tbl_ptr->split_idx) && 
  22534                     (grp_idx <= ecmp_tbl_ptr->split_idx + max_vp_lags - 1)) {
  22535                     grp_idx = ecmp_tbl_ptr->split_idx + max_vp_lags;
  22536                     continue;
  22537                 }
  22538             } else 
  22539 #endif
  22540             {
  22541                 if (grp_idx < max_vp_lags) {
  22542                     grp_idx = max_vp_lags;
  22543                     continue;
  22544                 }
  22545 
  22546             } 
  22547         }
  22548 #endif /* BCM_TRIDENT2_SUPPORT */
  22549 
  22550 
  22551          /* Increment ECMP group reference count. */
  22552          BCM_XGS3_L3_ENT_REF_CNT_INC(ecmp_tbl_ptr, grp_idx,
  22553                  ecmp_grp_record_width);
  22554 
  22555          /* Get next hops from ECMP group */
  22556          sal_memset(ecmp_group, 0, sizeof(int) * BCM_XGS3_L3_ECMP_MAX(unit));
  22557          rv = _bcm_xgs3_ecmp_tbl_read(unit, grp_idx, ecmp_group, &ecmp_count);
  22558          if (BCM_FAILURE(rv)) {
  22559              sal_free(ecmp_group);
  22560              return (rv);
  22561          }
  22562 
  22563          if ((ecmp_refcnt[grp_idx] < 1)) {
  22564             BCM_XGS3_L3_ENT_REF_CNT_DEC(ecmp_tbl_ptr, grp_idx,
  22565                     ecmp_grp_record_width);
  22566 
  22567             /*
  22568              * There maybe entries starting at any index when added
  22569              * with specific ID. Look for the immediate next index.
  22570              */
  22571             grp_idx+=1;
  22572             continue;
  22573          }
  22574 
  22575          /* Set ecmp in use flag if needed. */
  22576          if (!BCM_XGS3_L3_ECMP_IN_USE(unit)) {
  22577               BCM_XGS3_L3_ECMP_IN_USE(unit) = TRUE;
  22578          }
  22579 
  22580          /* Compute signature and reference count for ECMP group */
  22581          rv = _bcm_xgs3_l3_ecmp_group_hash_calc(unit, grp_idx, ecmp_group,
  22582                                                  ecmp_count, &entry_hash);
  22583          if (BCM_FAILURE(rv)) {
  22584              sal_free(ecmp_group);
  22585              return (rv);
  22586          }
  22587 
  22588          BCM_XGS3_L3_ENT_HASH_UPDATE(ecmp_tbl_ptr, grp_idx,
  22589                  ecmp_grp_record_width, entry_hash);
  22590 
  22591          /* Loop over all ecmp group members and increment nh reference count.*/
  22592          for (nh_idx = 0; nh_idx < ecmp_count; nh_idx++) {
  22593               /* Skip over members that are not NH indices */
  22594               if (soc_feature(unit, soc_feature_hierarchical_ecmp) ||
  22595                   soc_feature(unit, soc_feature_multi_level_ecmp)) {
  22596                   if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit,
  22597                                              ecmp_group[nh_idx])) {
  22598                       continue;
  22599                   }
  22600               }
  22601               BCM_XGS3_L3_ENT_REF_CNT_INC(nh_tbl_ptr, ecmp_group[nh_idx], 
  22602                                           _BCM_SINGLE_WIDE);
  22603          }
  22604          /* Update max table index used */
  22605 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
  22606          if ((BCMI_L3_ECMP_IS_MULTI_LEVEL(unit) && 
  22607              (ecmp_tbl_ptr->split_idx > grp_idx))) {
  22608              if (grp_idx > ecmp_tbl_ptr->split_maxused) {
  22609                  ecmp_tbl_ptr->split_maxused = grp_idx;
  22610              }
  22611          } else 
  22612 #endif
  22613          {
  22614              if (ecmp_tbl_ptr->idx_maxused < grp_idx) {
  22615                  ecmp_tbl_ptr->idx_maxused = grp_idx;
  22616              }
  22617          }
  22618          if (SOC_IS_TD_TT(unit)) {
  22619              int ecmp_idx = 0;
  22620              int max_ecmp_cnt;
  22621              
  22622              if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) {
  22623                  BCM_IF_ERROR_RETURN(
  22624                      _bcm_xgs3_l3_ecmp_grp_info_get(unit, grp_idx,
  22625                                                     NULL, &ecmp_idx));
  22626                  
  22627                  max_ecmp_cnt = 0;
  22628                  rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, grp_idx, &max_ecmp_cnt);
  22629                  if (BCM_FAILURE(rv)) {
  22630                      return rv;
  22631                  }
  22632                
  22633                  BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ecmp),
  22634                                              ecmp_idx, max_ecmp_cnt);
  22635              }
  22636          }
  22637 
  22638          BCM_XGS3_L3_ECMP_GRP_CNT(unit)++;
  22639 
  22640          /*
  22641           * Record was found. Next index will be after this
  22642           * record's width.
  22643           */
  22644          grp_idx+=ecmp_grp_record_width;
  22645     }
  22646 
  22647     sal_free(ecmp_group);
  22648 
  22649     if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, v4))) {
  22650         index_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, v4));
  22651         index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, v4));
  22652         rv = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, v4),
  22653                                       BCM_XGS3_L3_ENT_SZ(unit, v4),
  22654                                       "l3_tbl", &l3_tbl_ptr, NULL);
  22655         if (BCM_FAILURE(rv)) {
  22656             l3_tbl_ptr = NULL;
  22657         }
  22658         /* Loop over all valid IPV4 unicast entries to get ECMP group use count. */
  22659         for (idx = index_min; idx <= index_max; idx++) {
  22660             sal_memset(&l3_cfg, 0, sizeof(_bcm_l3_cfg_t));
  22661             BCM_XGS3_L3_MODULE_LOCK(unit);
  22662             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get_by_idx)(
  22663                           unit, l3_tbl_ptr, idx,
  22664                           &l3_cfg, &ecmp_grp_idx);
  22665             BCM_XGS3_L3_MODULE_UNLOCK(unit);
  22666             if (rv == BCM_E_NOT_FOUND) {
  22667                 continue;
  22668             } else if (BCM_FAILURE(rv)) {
  22669                 goto cleanup;
  22670             }
  22671             if ((l3_cfg.l3c_flags & BCM_L3_IP6) == BCM_L3_IP6) {
  22672                 continue;
  22673             }
  22674             if ((l3_cfg.l3c_flags & BCM_L3_IPMC) == BCM_L3_IPMC) {
  22675                 continue;
  22676             }
  22677 
  22678             if(l3_cfg.l3c_flags & BCM_L3_MULTIPATH){
  22679                 /* Increment ecmp group reference count. */
  22680                 BCM_XGS3_L3_ENT_REF_CNT_INC
  22681                     (BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), ecmp_grp_idx, ecmp_grp_record_width);
  22682             }
  22683         }
  22684         if (l3_tbl_ptr) {
  22685             soc_cm_sfree(unit, l3_tbl_ptr);
  22686             l3_tbl_ptr = NULL;
  22687         }
  22688     }
  22689 
  22690     if (SOC_MEM_IS_VALID(unit, BCM_XGS3_L3_MEM(unit, v6))) {
  22691         index_min = soc_mem_index_min(unit, BCM_XGS3_L3_MEM(unit, v6));
  22692         index_max = soc_mem_index_max(unit, BCM_XGS3_L3_MEM(unit, v6));
  22693         rv = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, v6),
  22694                                       BCM_XGS3_L3_ENT_SZ(unit, v6),
  22695                                       "l3_tbl", &l3_tbl_ptr, NULL);
  22696         if (BCM_FAILURE(rv)) {
  22697             l3_tbl_ptr = NULL;
  22698         }
  22699         /*
  22700          * Loop over all valid IPV6 unicast entries to get ECMP group use count.
  22701          */
  22702         for (idx = index_min; idx <= index_max; idx++) {
  22703             l3_cfg.l3c_flags = BCM_L3_IP6;
  22704             BCM_XGS3_L3_MODULE_LOCK(unit);
  22705             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_get_by_idx)(
  22706                 unit, l3_tbl_ptr, idx, &l3_cfg, &ecmp_grp_idx);
  22707             BCM_XGS3_L3_MODULE_UNLOCK(unit);
  22708             if (rv == BCM_E_NOT_FOUND) {
  22709                 continue;
  22710             } else if (BCM_FAILURE(rv)) {
  22711                 goto cleanup;
  22712             }
  22713             if ((l3_cfg.l3c_flags & BCM_L3_IP6) != BCM_L3_IP6) {
  22714                 continue;
  22715             }
  22716             if ((l3_cfg.l3c_flags & BCM_L3_IPMC) == BCM_L3_IPMC) {
  22717                 continue;
  22718             }
  22719             
  22720             if(l3_cfg.l3c_flags & BCM_L3_MULTIPATH){
  22721                 /* Increment ecmp group reference count. */
  22722                 BCM_XGS3_L3_ENT_REF_CNT_INC
  22723                     (BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), ecmp_grp_idx, ecmp_grp_record_width);
  22724             }
  22725         }
  22726         if (l3_tbl_ptr) {
  22727             soc_cm_sfree(unit, l3_tbl_ptr);
  22728             l3_tbl_ptr = NULL;
  22729         }
  22730     }
  22731 
  22732 #ifdef BCM_TRIDENT2_SUPPORT
  22733     if (SOC_IS_TRIDENT2X(unit) &&
  22734         soc_feature(unit, soc_feature_ecmp_resilient_hash)) {
  22735         BCM_IF_ERROR_RETURN(bcm_td2_ecmp_rh_hw_recover(unit));
  22736     }
  22737 #endif /* BCM_TRIDENT2_SUPPORT */
  22738 
  22739     rv = BCM_E_NONE;
  22740 cleanup:
  22741     if (l3_tbl_ptr) {
  22742         soc_cm_sfree(unit, l3_tbl_ptr);
  22743     }
  22744 
  22745     return rv;
  22746 }
  22747 #endif /* BCM_WARM_BOOT_SUPPORT */
  22748 
  22749 /*
  22750  * Function:
  22751  *      _bcm_xgs3_defip_traverse_cb
  22752  * Purpose:
  22753  *      Walk entries in DEFIP table.
  22754  * Parameters:
  22755  *      unit      - (IN)SOC unit number.
  22756  *      pattern   - (IN)Match pattern.
  22757  *      data1     - (IN)Route info.
  22758  *      data2     - (IN)Next hop info.
  22759  *      cmp_result- (OUT)Comparison result (Always negative).
  22760  * Returns:
  22761  *      BCM_E_XXX
  22762  */
  22763 STATIC int
  22764 _bcm_xgs3_defip_traverse_cb(int unit, void *pattern,
  22765                             void *data1, void *data2, int *cmp_result)
  22766 {
  22767     _bcm_l3_trvrs_data_t *trv_data;         /* Traverse data.               */
  22768     _bcm_trvs_range_t *range_info;          /* Travers start/end/count info.*/
  22769     _bcm_defip_cfg_t *lpm_cfg;              /* Route information.           */
  22770     int nh_ecmp_idx;                        /* Next hop/ecmp group index.   */
  22771     int ecmp_count = 0;                     /* Ecmp group size.             */
  22772     int *ecmp_group;                        /* Ecmp group from hw.          */
  22773     int idx;                                /* Iteration index.             */
  22774     int rv;                                 /* Operation return status.     */
  22775 
  22776     /* Cast input parameters. */
  22777     trv_data = (_bcm_l3_trvrs_data_t *) pattern;
  22778     range_info = (_bcm_trvs_range_t *) trv_data->pattern;
  22779     lpm_cfg = (_bcm_defip_cfg_t *) data1;
  22780     nh_ecmp_idx = *(int *)data2;
  22781 
  22782     /* We never need to call operational callback. */
  22783     *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  22784 
  22785 #ifdef BCM_WARM_BOOT_SUPPORT
  22786     if (SOC_WARM_BOOT(unit)) {
  22787         rv = _bcm_xgs3_defip_state_recover(unit, lpm_cfg, nh_ecmp_idx);
  22788         if (BCM_FAILURE(rv)) {
  22789             return (rv);
  22790         }
  22791 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
  22792         if (soc_feature(unit, soc_feature_ipmc_defip)) {
  22793             rv = bcm_td2p_defip_mc_route_check(unit, lpm_cfg);
  22794         }
  22795 #endif
  22796         return rv;
  22797     }
  22798 #endif /* BCM_WARM_BOOT_SUPPORT */
  22799 
  22800 
  22801     if ((lpm_cfg->defip_ecmp) &&
  22802         (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)))) {
  22803         /* Allocate ecmp group buffer. */
  22804         BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_group));
  22805 
  22806         /* If route is multipath get next hops from ecmp group. */
  22807         rv = _bcm_xgs3_ecmp_tbl_read(unit, nh_ecmp_idx,
  22808                                      ecmp_group, &ecmp_count);
  22809         if (BCM_FAILURE(rv)) {
  22810             sal_free(ecmp_group);
  22811             return (rv);
  22812         }
  22813 
  22814         /* Set number of ecmp paths. */
  22815         lpm_cfg->defip_ecmp_count = ecmp_count;
  22816 
  22817         /* Loop over all ecmp group members and check outgoing interface. */
  22818         for (idx = 0; idx < ecmp_count; idx++) {
  22819             /* Check number of routes reported. */
  22820             if (range_info->start > range_info->current_count) {
  22821                 range_info->current_count++;
  22822                 continue;
  22823             }
  22824             if (range_info->end < range_info->current_count) {
  22825                 sal_free(ecmp_group);
  22826                 return (BCM_E_FULL);
  22827             }
  22828             range_info->current_count++;
  22829 
  22830             /* Notify caller regarding entry path. */
  22831             _bcm_xgs3_lpm_call_user_cb(unit, trv_data,
  22832                                        lpm_cfg, ecmp_group[idx]);
  22833 
  22834         } /* Loop over ecmp group next hops. */
  22835         sal_free(ecmp_group);
  22836     } else {
  22837         if (range_info->start > range_info->current_count) {
  22838             range_info->current_count++;
  22839             return (BCM_E_NONE);
  22840         }
  22841 
  22842         if (range_info->end < range_info->current_count) {
  22843             return (BCM_E_FULL);
  22844         }
  22845         range_info->current_count++;
  22846 
  22847         /* Notify caller regarding unused entry. */
  22848         _bcm_xgs3_lpm_call_user_cb(unit, trv_data, lpm_cfg, nh_ecmp_idx);
  22849     }
  22850     return (BCM_E_NONE);
  22851 }
  22852 
  22853 /*
  22854  * Function:
  22855  *      bcm_xgs3_defip_traverse
  22856  * Purpose:
  22857  *      Traverse entries in the DEF_IP table
  22858  * Parameters:
  22859  *      unit      - (IN)SOC unit number.
  22860  *      flags     - (IN)IPv4/IPv6.
  22861  *      start     - (IN)Start index of interest.
  22862  *      end       - (IN)End index of interest.
  22863  *      trav_fn   - (IN)Callback function for every entry.
  22864  *      user_data - (IN)User callback data.
  22865  * Returns:
  22866  *      BCM_E_XXX
  22867  */
  22868 int
  22869 bcm_xgs3_defip_traverse(int unit, int flags, uint32 start, uint32 end,
  22870                         bcm_l3_route_traverse_cb trav_fn, void *user_data)
  22871 {
  22872     _bcm_l3_trvrs_data_t trv_data;     /* Traverse information.        */
  22873     _bcm_trvs_range_t range_info;       /* Start/End/Count information. */
  22874     int rv = BCM_E_UNAVAIL;             /* Operation return status.     */
  22875 
  22876     /* Input indexes sanity */
  22877     if (start > end) {
  22878         return BCM_E_NOT_FOUND;
  22879     }
  22880 
  22881     if (!SOC_WARM_BOOT(unit)) {
  22882 	/* If table is empty -> there is nothing to delete. */
  22883 	BCM_XGS3_L3_IF_DEFIP_CNT_ZERO_RETURN(unit, flags & BCM_L3_IP6);
  22884     }
  22885 
  22886     /* Zero traverse info. */
  22887     sal_memset(&trv_data, 0, sizeof(_bcm_l3_trvrs_data_t));
  22888     sal_memset(&range_info, 0, sizeof(_bcm_trvs_range_t));
  22889 
  22890     range_info.start = start;
  22891     range_info.end = end;
  22892     /* Fill traverse data struct. */
  22893     trv_data.flags = flags;
  22894     trv_data.pattern = &range_info;
  22895     /* We need to set both operational & test callback since firebolt
  22896        never executes test routine. */
  22897     trv_data.cmp_cb = _bcm_xgs3_defip_traverse_cb;
  22898     trv_data.op_cb = _bcm_xgs3_defip_traverse_cb;
  22899     trv_data.defip_cb = trav_fn;
  22900     trv_data.cookie = user_data;
  22901 
  22902     /*  Update/show routes matching the pattern from hw. */
  22903     if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_update_match)) {
  22904         BCM_XGS3_L3_MODULE_LOCK(unit);
  22905         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_update_match) (unit, &trv_data);
  22906         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  22907     }
  22908     /* Handle case we got to the last requested index (end) callback
  22909        will return table full, no error in this case.
  22910      */
  22911     rv = (rv == BCM_E_FULL) ? BCM_E_NONE : rv;
  22912     return rv;
  22913 }
  22914 
  22915 /*
  22916  * Function:
  22917  *      bcm_xgs3_defip_ip4_traverse
  22918  * Purpose:
  22919  *      Traverse IPv4 entries in the DEF_IP table
  22920  * Parameters:
  22921  *      unit      - (IN)SOC unit number.
  22922  *      start     - (IN)Start index of interest.
  22923  *      end       - (IN)End index of interest.
  22924  *      trav_fn   - (IN)Callback function for every entry.
  22925  *      user_data - (IN)User callback data.
  22926  * Returns:
  22927  *      BCM_E_XXX
  22928  */
  22929 int
  22930 bcm_xgs3_defip_ip4_traverse(int unit, uint32 start, uint32 end,
  22931                             bcm_l3_route_traverse_cb trav_fn, void *user_data)
  22932 {
  22933     return bcm_xgs3_defip_traverse(unit, 0, start, end, trav_fn, user_data);
  22934 }
  22935 
  22936 /*
  22937  * Function:
  22938  *      bcm_xgs3_defip_ip6_traverse
  22939  * Purpose:
  22940  *      Traverse IPv6 entries in the DEF_IP table
  22941  * Parameters:
  22942  *      unit      - (IN)SOC unit number.
  22943  *      start     - (IN)Start index of interest.
  22944  *      end       - (IN)End index of interest.
  22945  *      trav_fn   - (IN)Callback function for every entry.
  22946  *      user_data - (IN)User callback data.
  22947  * Returns:
  22948  *      BCM_E_XXX
  22949  */
  22950 int
  22951 bcm_xgs3_defip_ip6_traverse(int unit, uint32 start, uint32 end,
  22952                             bcm_l3_route_traverse_cb trav_fn, void *user_data)
  22953 {
  22954     return bcm_xgs3_defip_traverse(unit, BCM_L3_IP6,
  22955                                    start, end, trav_fn, user_data);
  22956 }
  22957 
  22958 /*
  22959  * Function:
  22960  *      bcm_xgs3_defip_ecmp_get_all
  22961  * Purpose:
  22962  *      Get all paths for a route, useful for ECMP route
  22963  * Parameters:
  22964  *      unit       - (IN) SOC device unit number
  22965  *      the_route  - (IN) route's net/mask
  22966  *      path_array - (OUT) Array of all ECMP paths
  22967  *      max_path   - (IN) Max number of ECMP paths
  22968  *      path_count - (OUT) Actual number of ECMP paths
  22969  * Returns:
  22970  *      BCM_E_XXX
  22971  */
  22972 int
  22973 bcm_xgs3_defip_ecmp_get_all(int unit, _bcm_defip_cfg_t *lpm_cfg,
  22974                             bcm_l3_route_t *path_array, int max_path,
  22975                             int *path_count)
  22976 {
  22977     int *ecmp_group;                     /* Next hop index.            */
  22978     int nh_ecmp_idx;                     /* Next hop/Ecmp group index. */
  22979     int ecmp_count = 0;                  /* Ecmp group size.           */
  22980     int idx;                             /* Iteration index.           */
  22981     int rv = BCM_E_UNAVAIL;              /* Operation return status.   */
  22982 
  22983     /* Input parameters checks. */
  22984     BCM_XGS3_L3_DEFIP_INVALID_PARAMS_RETURN(unit, lpm_cfg);
  22985 
  22986 
  22987     /* Get lpm entry. */
  22988     if (BCM_XGS3_L3_HWCALL_CHECK(unit, lpm_get)) {
  22989         BCM_XGS3_L3_MODULE_LOCK(unit);
  22990         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, lpm_get) (unit, lpm_cfg,
  22991                                                      &nh_ecmp_idx);
  22992         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  22993     }
  22994     BCM_IF_ERROR_RETURN(rv);
  22995 
  22996     if (lpm_cfg->defip_ecmp) {
  22997         /* Trunslate next hop index to ecmp group id. */
  22998         if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  22999             nh_ecmp_idx /= BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  23000         }
  23001         /* Allocate ecmp group buffer. */
  23002         BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_ecmp_group_alloc(unit, &ecmp_group));
  23003 
  23004         /* Get ecmp group next hop indexes. */
  23005         rv = _bcm_xgs3_ecmp_tbl_read(unit, nh_ecmp_idx,
  23006                                      ecmp_group, &ecmp_count);
  23007         if (BCM_FAILURE(rv)) {
  23008             sal_free(ecmp_group);
  23009             return (rv);
  23010         }
  23011 
  23012         /* Set route information. */
  23013         for (idx = 0; ((idx < ecmp_count) && (idx < max_path)); idx++) {
  23014             rv = _bcm_xgs3_defip_set_route_info(unit, lpm_cfg, path_array + idx,
  23015                                                 ecmp_group[idx]);
  23016             if (BCM_FAILURE(rv)) {
  23017                 sal_free(ecmp_group);
  23018                 return (rv);
  23019             }
  23020         }
  23021         sal_free(ecmp_group);
  23022         /* Fill number of ecmp paths. */
  23023         *path_count = idx;
  23024     } else {
  23025         BCM_IF_ERROR_RETURN
  23026             (_bcm_xgs3_defip_set_route_info(unit, lpm_cfg, path_array,
  23027                                             nh_ecmp_idx));
  23028         *path_count =  1;
  23029     }
  23030     return (BCM_E_NONE);
  23031 }
  23032 /*
  23033  * Function:
  23034  *      bcm_xgs3_l3_ip6_prefix_map_get
  23035  * Purpose:
  23036  *      Get a list of IPv6 96 bit prefixes which are mapped to ipv4 lookup
  23037  *      space.
  23038  * Parameters:
  23039  *      unit       - (IN) bcm device.
  23040  *      map_size   - (IN) Size of allocated entries in ip6_array.
  23041  *      ip6_array  - (OUT) Array of mapped prefixes.
  23042  *      ip6_count  - (OUT) Number of entries of ip6_array actually filled in.
  23043  *                      This will be a value less than or equal to the value.
  23044  *                      passed in as map_size unless map_size is 0.  If
  23045  *                      map_size is 0 then ip6_array is ignored and
  23046  *                      ip6_count is filled in with the number of entries
  23047  *                      that would have been filled into ip6_array if
  23048  *                      map_size was arbitrarily large.
  23049  * Returns:
  23050  *      BCM_E_XXX
  23051  */
  23052 int
  23053 bcm_xgs3_l3_ip6_prefix_map_get(int unit, int map_size,
  23054                               bcm_ip6_t *ip6_array, int *ip6_count)
  23055 {
  23056 #if defined(BCM_TRX_SUPPORT) || defined(BCM_FIREBOLT2_SUPPORT)
  23057     soc_mem_t mem;         /* IPv4 in IPv6 table memory.    */
  23058     int  tbl_sz;           /* IPv4 in IPv6 table size.      */
  23059     char *tbl_ptr;         /* Dma table pointer.            */
  23060     uint32 *buf_p;         /* Table entry pointer.          */
  23061     int  idx;              /* Table iterator.               */
  23062     int  valid_entry_count;/* Table valid entry count.      */
  23063 
  23064     mem = BCM_XGS3_L3_MEM(unit, v6_prefix_map);
  23065 
  23066     /* Check feature support. */
  23067     if (INVALIDm == mem) {
  23068         return (BCM_E_UNAVAIL);
  23069     }
  23070 
  23071     /* Input parameters sanity check. */
  23072     if ((NULL == ip6_count) || ((NULL == ip6_array) && (0 != map_size))) {
  23073         return (BCM_E_PARAM);
  23074     }
  23075 
  23076     /* Table DMA the ipv4 in ipv6 table to software copy */
  23077     BCM_IF_ERROR_RETURN
  23078         (bcm_xgs3_l3_tbl_dma(unit, mem, BCM_XGS3_L3_ENT_SZ(unit, v6_prefix_map),
  23079                              "v6_prefix_tbl", &tbl_ptr, &tbl_sz));
  23080 
  23081     /* Reset destination buffer. */
  23082     valid_entry_count = 0;
  23083     if (NULL != ip6_array) {
  23084         sal_memset (ip6_array, 0, map_size * sizeof(bcm_ip6_t));
  23085     }
  23086 
  23087     for (idx = 0; idx < tbl_sz; idx++) {
  23088         buf_p = soc_mem_table_idx_to_pointer(unit, mem, uint32 *, tbl_ptr, idx);
  23089         /* Skip if entry is invalid. */
  23090         if (!soc_mem_field32_get(unit, mem, buf_p, ENABLEf)) {
  23091             continue;
  23092         }
  23093 
  23094         if (NULL != ip6_array) {
  23095             soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6_PREFIXf,
  23096                                  ip6_array[valid_entry_count],
  23097                                  SOC_MEM_IP6_UPPER_96BIT);
  23098             /* Update number of read entries . */
  23099             if (++valid_entry_count >= map_size) {
  23100                 break;
  23101             }
  23102         } else {
  23103            valid_entry_count++;
  23104         }
  23105     }
  23106 
  23107     /* Assign number of valid entries read. */
  23108     *ip6_count = valid_entry_count;
  23109     /* Free resources. */
  23110     soc_cm_sfree(unit,tbl_ptr);
  23111 
  23112     return (BCM_E_NONE);
  23113 #endif /* BCM_TRX_SUPPORT || BCM_FIREBOLT2_SUPPORT */
  23114     return (BCM_E_UNAVAIL);
  23115 }
  23116 
  23117 /*
  23118  * Function:
  23119  *      bcm_xgs3_l3_ip6_prefix_map_add
  23120  * Purpose:
  23121  *      Create an IPv6 prefix map into IPv4 entry. In case Ipv6 traffic
  23122  *      destination or source IP address matches upper 96 bits of
  23123  *      translation entry. traffic will be routed/switched  based on
  23124  *      lower 32 bits of destination/source IP address treated as IPv4 address.
  23125  * Parameters:
  23126  *      unit     - (IN)  bcm device.
  23127  *      ip6_addr - (IN)  New IPv6 translation address.
  23128  * Returns:
  23129  *      BCM_E_XXX
  23130  */
  23131 int
  23132 bcm_xgs3_l3_ip6_prefix_map_add(int unit, bcm_ip6_t ip6_addr)
  23133 {
  23134 #if defined(BCM_TRX_SUPPORT) || defined(BCM_FIREBOLT2_SUPPORT)
  23135     soc_mem_t mem;         /* IPv4 in IPv6 table memory.    */
  23136     int  tbl_sz;           /* IPv4 in IPv6 table size.      */
  23137     char *tbl_ptr;         /* Dma table pointer.            */
  23138     uint32 *buf_p;         /* Table entry pointer.          */
  23139     bcm_ip6_t addr;        /* IPv6 prefix map.              */
  23140     int  rv;               /* Operation status.             */
  23141     int  idx;              /* Table iterator.               */
  23142 
  23143     mem = BCM_XGS3_L3_MEM(unit, v6_prefix_map);
  23144 
  23145     /* Check feature support. */
  23146     if (INVALIDm == mem) {
  23147         return (BCM_E_UNAVAIL);
  23148     }
  23149 
  23150     /* Reset lower 32 bit of ip6 address. */
  23151     sal_memset(((char *)ip6_addr) + 12,0, 4);
  23152 
  23153     /* Table DMA the ipv4 in ipv6 table to software copy */
  23154     rv = bcm_xgs3_l3_tbl_dma(unit, mem, BCM_XGS3_L3_ENT_SZ(unit, v6_prefix_map),
  23155                              "v6_prefix_tbl", &tbl_ptr, &tbl_sz);
  23156     BCM_IF_ERROR_RETURN(rv);
  23157 
  23158     rv = BCM_E_RESOURCE;  /* Assuming there is no room for new entry. */
  23159     for (idx = 0; idx < tbl_sz; idx++) {
  23160         buf_p = soc_mem_table_idx_to_pointer (unit, mem, uint32 *, tbl_ptr, idx);
  23161 
  23162         /* Skip if entry is disabled. */
  23163         if (!soc_mem_field32_get(unit, mem, buf_p, ENABLEf)) {
  23164             if (BCM_E_RESOURCE == rv) {
  23165                 soc_mem_field32_set(unit, mem, buf_p, ENABLEf, 1);
  23166 
  23167                 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6_PREFIXf,
  23168                                      ip6_addr, SOC_MEM_IP6_UPPER_96BIT);
  23169                 rv = BCM_E_NONE;
  23170             }
  23171             continue;
  23172         }
  23173 
  23174         /* Extract entry prefix. */
  23175         soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6_PREFIXf, addr,
  23176                              SOC_MEM_IP6_UPPER_96BIT);
  23177 
  23178         /* Compare 12 most significant bytes of address. */
  23179         if (0 == sal_memcmp(addr, ip6_addr, 12)) {
  23180            rv = BCM_E_EXISTS;
  23181            break;
  23182         }
  23183     }
  23184 
  23185     /* Write the modified  buffer back. */
  23186     if (BCM_SUCCESS(rv)) {
  23187         rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ALL,
  23188                                  soc_mem_index_min(unit, mem),
  23189                                  soc_mem_index_max(unit, mem), tbl_ptr);
  23190     }
  23191 
  23192     /* Free resources. */
  23193     soc_cm_sfree(unit,tbl_ptr);
  23194     return (rv);
  23195 #endif /* BCM_TRX_SUPPORT || BCM_FIREBOLT2_SUPPORT */
  23196     return (BCM_E_UNAVAIL);
  23197 }
  23198 
  23199 /*
  23200  * Function:
  23201  *      bcm_xgs3_l3_ip6_prefix_map_delete
  23202  * Purpose:
  23203  *      Destroy an IPv6 prefix map entry.
  23204  * Parameters:
  23205  *      unit     - (IN)  bcm device.
  23206  *      ip6_addr - (IN)  IPv6 translation address.
  23207  * Returns:
  23208  *      BCM_E_XXX
  23209  */
  23210 int
  23211 bcm_xgs3_l3_ip6_prefix_map_delete(int unit, bcm_ip6_t ip6_addr)
  23212 {
  23213 #if defined(BCM_TRX_SUPPORT) || defined(BCM_FIREBOLT2_SUPPORT)
  23214     soc_mem_t mem;         /* IPv4 in IPv6 table memory.    */
  23215     int  tbl_sz;           /* IPv4 in IPv6 table size.      */
  23216     char *tbl_ptr;         /* Dma table pointer.            */
  23217     uint32 *buf_p;         /* Table entry pointer.          */
  23218     bcm_ip6_t addr;        /* IPv6 prefix map.              */
  23219     int  rv;                /* Operation status.             */
  23220     int  idx;              /* Table iterator.               */
  23221 
  23222     mem = BCM_XGS3_L3_MEM(unit, v6_prefix_map);
  23223 
  23224     /* Check feature support. */
  23225     if (INVALIDm == mem) {
  23226         return (BCM_E_UNAVAIL);
  23227     }
  23228 
  23229     /* Table DMA the ipv4 in ipv6 table to software copy */
  23230     rv = bcm_xgs3_l3_tbl_dma(unit, mem, BCM_XGS3_L3_ENT_SZ(unit, v6_prefix_map),
  23231                              "v6_prefix_tbl", &tbl_ptr, &tbl_sz);
  23232     BCM_IF_ERROR_RETURN(rv);
  23233 
  23234     rv = BCM_E_NOT_FOUND;
  23235     for (idx = 0; idx < tbl_sz; idx++) {
  23236         buf_p = soc_mem_table_idx_to_pointer (unit, mem, uint32 *, tbl_ptr, idx);
  23237 
  23238         /* Skip if entry is disabled. */
  23239         if (!soc_mem_field32_get(unit, mem, buf_p, ENABLEf)) {
  23240             continue;
  23241         }
  23242 
  23243         /* Extract entry prefix. */
  23244         soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6_PREFIXf, addr,
  23245                              SOC_MEM_IP6_UPPER_96BIT);
  23246 
  23247         /* Compare 12 most significant bytes of address. */
  23248         if (0 == sal_memcmp(addr, ip6_addr, 12)) {
  23249            soc_mem_field32_set(unit, mem, buf_p, ENABLEf, 0);
  23250            rv = BCM_E_NONE;
  23251            break;
  23252         }
  23253     }
  23254 
  23255     if (BCM_SUCCESS(rv)) {
  23256         /* Write the buffer back. */
  23257         rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ALL,
  23258                                  soc_mem_index_min(unit, mem),
  23259                                  soc_mem_index_max(unit, mem), tbl_ptr);
  23260     }
  23261     /* Free resources. */
  23262     soc_cm_sfree(unit,tbl_ptr);
  23263 
  23264     return (rv);
  23265 #endif /* BCM_TRX_SUPPORT || BCM_FIREBOLT2_SUPPORT */
  23266     return (BCM_E_UNAVAIL);
  23267 }
  23268 
  23269 /*
  23270  * Function:
  23271  *      bcm_xgs3_l3_ip6_prefix_map_delete_all
  23272  * Purpose:
  23273  *      Flush all IPv6 prefix maps.
  23274  * Parameters:
  23275  *      unit     - (IN)  bcm device.
  23276  * Returns:
  23277  *      BCM_E_XXX
  23278  */
  23279 int
  23280 bcm_xgs3_l3_ip6_prefix_map_delete_all(int unit)
  23281 {
  23282 #if defined(BCM_TRX_SUPPORT) || defined(BCM_FIREBOLT2_SUPPORT)
  23283     /* Check feature support. */
  23284     if (INVALIDm == BCM_XGS3_L3_MEM(unit, v6_prefix_map)) {
  23285         return (BCM_E_UNAVAIL);
  23286     }
  23287 
  23288     /* Clear IPv6 prefix map table. */
  23289     BCM_IF_ERROR_RETURN
  23290         (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, v6_prefix_map)));
  23291 
  23292     return (BCM_E_NONE);
  23293 #endif /* BCM_TRX_SUPPORT || BCM_FIREBOLT2_SUPPORT */
  23294     return (BCM_E_UNAVAIL);
  23295 }
  23296 
  23297 /*
  23298  * Function:
  23299  *      _bcm_xgs3_l3_ingress_interface_add
  23300  * Purpose:
  23301  *      Add l3 ingress interface.
  23302  * Parameters:
  23303  *      unit  - (IN) Bcm device number.
  23304  *      iif   - (IN/OUT) Ingress interface descriptor.
  23305  * Returns:
  23306  *      BCM_E_XXX
  23307  */
  23308 int
  23309 _bcm_xgs3_l3_ingress_interface_add(int unit, _bcm_l3_ingress_intf_t *iif)
  23310 {
  23311     int idx;                                      /* Allocation index        */
  23312     int loop_max;                                 /* Max number of tries.    */
  23313     int rv;
  23314 
  23315     /* Input parameters check. */
  23316     if (NULL == iif) {
  23317         return (BCM_E_PARAM);
  23318     }
  23319     /* Vrf id range check. */
  23320     if ((iif->vrf > SOC_VRF_MAX(unit)) ||
  23321         (iif->vrf <  BCM_L3_VRF_DEFAULT)) {
  23322         if ((!soc_mem_field_valid(unit, L3_IIFm, VRF_VALIDf)) ||
  23323             ((soc_mem_field_valid(unit, L3_IIFm, VRF_VALIDf) &&
  23324             (iif->vrf != BCM_L3_VRF_INVALID)))) {
  23325         return (BCM_E_PARAM);
  23326     }
  23327     }
  23328 
  23329     /* Qualification class range check. */
  23330     if ((iif->if_class > SOC_INTF_CLASS_MAX(unit)) || (iif->if_class < 0)) {
  23331         return (BCM_E_PARAM);
  23332     }
  23333 
  23334     if ((0 == BCM_XGS3_L3_HWCALL_CHECK(unit, ing_intf_add))) {
  23335         return (BCM_E_UNAVAIL);
  23336     }
  23337 
  23338     /* Allocate interface class id. */
  23339     if ((iif->flags & BCM_L3_INGRESS_WITH_ID) || (iif->flags & BCM_L3_INGRESS_REPLACE)){
  23340         if ((iif->intf_id >= (BCM_XGS3_L3_ING_IF_TBL_SIZE(unit))) ||
  23341             (iif->intf_id < 0)) {
  23342             return (BCM_E_PARAM);
  23343         }
  23344         /* Does entry exist? */
  23345         if (iif->flags & BCM_L3_INGRESS_WITH_ID) {
  23346             if (!(iif->flags & BCM_L3_INGRESS_REPLACE) &&
  23347                 (0 != SHR_BITGET(BCM_XGS3_L3_ING_IF_INUSE(unit),
  23348                                  iif->intf_id))) {
  23349                 return (BCM_E_EXISTS);
  23350             }
  23351             SHR_BITSET(BCM_XGS3_L3_ING_IF_INUSE(unit), iif->intf_id);
  23352         }
  23353     } else {
  23354         L3_ING_IF_MIN(unit, idx);
  23355         loop_max = BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) - idx;
  23356         while (loop_max) {
  23357             if (0 == SHR_BITGET(BCM_XGS3_L3_ING_IF_INUSE(unit), idx)) {
  23358                 SHR_BITSET(BCM_XGS3_L3_ING_IF_INUSE(unit), idx);
  23359                 iif->intf_id = idx;
  23360                 break;
  23361             }
  23362             idx++;
  23363             loop_max--;
  23364         }
  23365         if (0 == loop_max) {
  23366             return (BCM_E_FULL);
  23367         }
  23368     }
  23369 
  23370     BCM_XGS3_L3_MODULE_LOCK(unit);
  23371     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ing_intf_add) (unit, iif, NULL, NULL);
  23372     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  23373     return rv;
  23374 }
  23375 
  23376 /*
  23377  * Function:
  23378  *      _bcm_xgs3_l3_ingress_interface_delete
  23379  * Purpose:
  23380  *      Delete l3 ingress interface.
  23381  * Parameters:
  23382  *      unit  - (IN) Bcm device number.
  23383  *      if_id - (IN) Ingress interface id.
  23384  * Returns:
  23385  *      BCM_E_XXX
  23386  */
  23387 int
  23388 _bcm_xgs3_l3_ingress_interface_delete(int unit, int intf_id)
  23389 {
  23390     int rv;
  23391     /* Input parameters check. */
  23392     if ((intf_id >= (BCM_XGS3_L3_ING_IF_TBL_SIZE(unit))) || (intf_id < 0)) {
  23393         return (BCM_E_PARAM);
  23394     }
  23395 
  23396     if (BCM_XGS3_L3_HWCALL_CHECK(unit, ing_intf_del)) {
  23397         SHR_BITCLR(BCM_XGS3_L3_ING_IF_INUSE(unit), intf_id);
  23398         BCM_XGS3_L3_MODULE_LOCK(unit);
  23399         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ing_intf_del) (unit, intf_id);
  23400         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  23401         return rv;
  23402     }
  23403     return (BCM_E_UNAVAIL);
  23404 }
  23405 
  23406 /*
  23407  * Function:
  23408  *      _bcm_xgs3_l3_ingress_interface_get
  23409  * Purpose:
  23410  *      Get l3 ingress interface.
  23411  * Parameters:
  23412  *      unit  - (IN) Bcm device number.
  23413  *      iif   - (IN/OUT) Ingress interface descriptor.
  23414  * Returns:
  23415  *      BCM_E_XXX
  23416  */
  23417 int
  23418 _bcm_xgs3_l3_ingress_interface_get(int unit, _bcm_l3_ingress_intf_t *iif)
  23419 {
  23420     int rv;
  23421     /* Input parameters check. */
  23422     if (NULL == iif) {
  23423         return (BCM_E_PARAM);
  23424     }
  23425 
  23426     if ((iif->intf_id >= (BCM_XGS3_L3_ING_IF_TBL_SIZE(unit))) ||
  23427         (iif->intf_id < 0)) {
  23428         return (BCM_E_PARAM);
  23429     }
  23430 
  23431     if (BCM_XGS3_L3_HWCALL_CHECK(unit, ing_intf_get)) {
  23432         BCM_XGS3_L3_MODULE_LOCK(unit);
  23433         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ing_intf_get) (unit, NULL, iif);
  23434         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  23435         return rv;
  23436     }
  23437     return (BCM_E_UNAVAIL);
  23438 }
  23439 
  23440 /*
  23441  * Function:
  23442  *      _bcm_xgs3_tunnel_type_support_check
  23443  * Purpose:
  23444  *      Check if tunnel type is supported on a device.
  23445  * Parameters:
  23446  *      unit        - (IN) Bcm device number.
  23447  *      tnl_type    - (IN) Tunnel type to check.
  23448  *      tunnel_term - (OUT) Type supported as tunnel terminator.
  23449  *      tunnel_init - (OUT) Type supported as tunnel initiator.
  23450  * Returns:
  23451  *      BCM_E_XXX
  23452  */
  23453 int
  23454 _bcm_xgs3_tunnel_type_support_check(int unit, bcm_tunnel_type_t tnl_type,
  23455                                     int *tunnel_term, int *tunnel_init)
  23456 {
  23457     int term;      /* Tunnel Terminator supported. */
  23458     int init;      /* Tunnel Initiator supported.  */
  23459 
  23460     switch (tnl_type) {
  23461       case bcmTunnelTypeNone:
  23462       case bcmTunnelTypeIp4In4:
  23463       case bcmTunnelTypeIp6In4:
  23464       case bcmTunnelType6In4Uncheck:
  23465       case bcmTunnelTypeIsatap:
  23466       case bcmTunnelTypePimSmDr1:
  23467       case bcmTunnelTypePimSmDr2:
  23468           term = init = TRUE;
  23469           break;
  23470       case bcmTunnelTypeIpAnyIn4:
  23471           init = TRUE;
  23472           if (soc_feature(unit, soc_feature_tunnel_term_hash_table) ||
  23473                (soc_feature(unit, soc_feature_tunnel_protocol_match)
  23474                 && !(soc_property_get(unit,
  23475                                     spn_BCM_TUNNEL_TERM_COMPATIBLE_MODE, 0)))) {
  23476               term = FALSE;
  23477           } else {
  23478               term = TRUE;
  23479           }
  23480           break;
  23481       case bcmTunnelTypeIp4In6:
  23482       case bcmTunnelTypeIp6In6:
  23483           if (!soc_feature(unit, soc_feature_tunnel_any_in_6)) {
  23484               term = init = FALSE;
  23485           } else {
  23486               term = init = TRUE;
  23487           }
  23488           break;
  23489       case bcmTunnelTypeIpAnyIn6:
  23490           if (!soc_feature(unit, soc_feature_tunnel_any_in_6)) {
  23491               term = init = FALSE;
  23492           } else {
  23493               init = TRUE;
  23494               if (soc_feature(unit, soc_feature_tunnel_term_hash_table) ||
  23495                   (soc_feature(unit, soc_feature_tunnel_protocol_match)
  23496                    && !(soc_property_get(unit,
  23497                                     spn_BCM_TUNNEL_TERM_COMPATIBLE_MODE, 0)))) {
  23498                   term = FALSE;
  23499               } else {
  23500                   term = TRUE;
  23501               }
  23502           }
  23503           break;
  23504       case bcmTunnelType6In4:
  23505           if (!soc_feature(unit, soc_feature_tunnel_6to4_secure)) {
  23506               term = init = FALSE;
  23507           }  else {
  23508               term = init = TRUE;
  23509           }
  23510           break;
  23511       case bcmTunnelTypePim6SmDr1:
  23512       case bcmTunnelTypePim6SmDr2:
  23513           if (!soc_feature(unit, soc_feature_tunnel_any_in_6)) {
  23514               term = init = FALSE;
  23515           } else {
  23516               init = TRUE;
  23517               term = FALSE;
  23518           }
  23519           break;
  23520       case bcmTunnelTypeGre4In4:
  23521       case bcmTunnelTypeGre6In4:
  23522       case bcmTunnelTypeGreAnyIn4:
  23523           if (!soc_feature(unit, soc_feature_tunnel_gre)) {
  23524               term = init = FALSE;
  23525           } else {
  23526               term = init = TRUE;
  23527           }
  23528           break;
  23529       case bcmTunnelTypeGre4In6:
  23530       case bcmTunnelTypeGre6In6:
  23531       case bcmTunnelTypeGreAnyIn6:
  23532           if ((!soc_feature(unit, soc_feature_tunnel_gre)) ||
  23533               (!soc_feature(unit, soc_feature_tunnel_any_in_6))) {
  23534               term = init = FALSE;
  23535           } else {
  23536               term = init = TRUE;
  23537           }
  23538           break;
  23539       case bcmTunnelTypeUdp:
  23540       case bcmTunnelTypeMpls:
  23541           term = init = TRUE;
  23542           break;
  23543       case bcmTunnelTypeWlanWtpToAc:
  23544       case bcmTunnelTypeWlanWtpToAc6:
  23545       case bcmTunnelTypeWlanAcToAc:
  23546       case bcmTunnelTypeWlanAcToAc6:
  23547           if (soc_feature(unit, soc_feature_wlan)) {
  23548               term = init = TRUE;
  23549           } else {
  23550               term = init = FALSE;
  23551           }
  23552           break;
  23553       case bcmTunnelTypeAutoMulticast:
  23554       case bcmTunnelTypeAutoMulticast6:
  23555           if (soc_feature(unit, soc_feature_auto_multicast)) {
  23556               term = init = TRUE;
  23557           } else {
  23558               term = init = FALSE;
  23559           }
  23560           break;
  23561 #ifdef BCM_MONTEREY_SUPPORT
  23562       case bcmTunnelTypeRoeIn4:
  23563       case bcmTunnelTypeRoeIn6:
  23564           if (soc_feature(unit, soc_feature_roe) ||
  23565               soc_feature(unit, soc_feature_roe_custom)) {
  23566               init = TRUE;
  23567               term = FALSE;
  23568           } else {
  23569               term = init = FALSE;
  23570           }
  23571           break;
  23572 #endif
  23573       default:
  23574           term = init = FALSE;
  23575     }
  23576 
  23577     if (NULL != tunnel_term) {
  23578         *tunnel_term = term;
  23579     }
  23580     if (NULL != tunnel_init) {
  23581         *tunnel_init = init;
  23582     }
  23583     return (BCM_E_NONE);
  23584 }
  23585 
  23586 /*
  23587  * Function:
  23588  *      _bcm_xgs3_l3_set_tnl_term_type
  23589  * Purpose:
  23590  *      Set tunnel terminator HW type & sub type.
  23591  * Parameters:
  23592  *      unit          - (IN)SOC unit number
  23593  *      tnl_info      - (IN)tnl_info Tunnel parameters.
  23594  *      tnl_type      - (OUT)Tunnel type.
  23595  *      tnl_sub_type  - (OUT)Tunnel sub_type
  23596  * Returns:
  23597  *      BCM_E_XXX
  23598  */
  23599 int
  23600 _bcm_xgs3_l3_set_tnl_term_type(int unit, bcm_tunnel_terminator_t *tnl_info,
  23601                                _bcm_tnl_term_type_t *tnl_type)
  23602 {
  23603     /* Input parameters check. */
  23604     if ((NULL == tnl_info) || (NULL == tnl_type)) {
  23605         return (BCM_E_PARAM);
  23606     }
  23607 
  23608     /* Reset destination buffer first. */
  23609     sal_memset(tnl_type, 0, sizeof(_bcm_tnl_term_type_t));
  23610 
  23611     /* Set tunnel outer header IP version. */
  23612     tnl_type->tnl_outer_hdr_ipv6 =_BCM_TUNNEL_OUTER_HEADER_IPV6(tnl_info->type);
  23613 
  23614     switch (tnl_info->type) {
  23615       case bcmTunnelType6In4Uncheck:
  23616           tnl_type->tnl_auto = 1;           /* automatic tunnel. */
  23617           tnl_type->tnl_sub_type = 0;
  23618           tnl_type->tnl_protocol = 0x29;    /* 6over4 OR 6to4 */
  23619           break;
  23620       case bcmTunnelTypeIsatap:
  23621           tnl_type->tnl_auto = 1;           /* automatic tunnel. */
  23622           tnl_type->tnl_sub_type = 0x1;
  23623           tnl_type->tnl_protocol = 0x29;    /* 6over4 OR 6to4 */
  23624           break;
  23625       case bcmTunnelType6In4:
  23626           tnl_type->tnl_auto = 1;           /* automatic tunnel. */
  23627           if (soc_feature(unit, soc_feature_tunnel_6to4_secure)) {
  23628               tnl_type->tnl_sub_type = 0x2;
  23629           } else {
  23630               tnl_type->tnl_sub_type = 0;
  23631           }
  23632           tnl_type->tnl_protocol = 0x29;   /* 6over4 OR 6to4 */
  23633           break;
  23634       case bcmTunnelTypeIp4In4:
  23635       case bcmTunnelTypeIp4In6:
  23636           tnl_type->tnl_auto = 0;          /* configured tunnel */
  23637           tnl_type->tnl_sub_type = 0x2;    /* IPv4 payload only.*/
  23638           tnl_type->tnl_protocol = 0x04;   /* IP in IP */
  23639           break;
  23640       case bcmTunnelTypeIp6In4:
  23641       case bcmTunnelTypeIp6In6:
  23642           tnl_type->tnl_auto = 0;          /* configured tunnel    */
  23643           tnl_type->tnl_sub_type = 0x1;    /* IPv6 payload only.   */
  23644           tnl_type->tnl_protocol = 0x29;   /* IPv6 */
  23645           break;
  23646       case bcmTunnelTypeIpAnyIn4:
  23647       case bcmTunnelTypeIpAnyIn6:
  23648           tnl_type->tnl_auto = 0;          /* configured tunnel    */
  23649           tnl_type->tnl_sub_type = 0x3;    /* IPv4 & IPv6 payload. */
  23650           tnl_type->tnl_protocol = 0x04;   /* IP in IP */
  23651           break;
  23652       case bcmTunnelTypeGre4In4:
  23653       case bcmTunnelTypeGre4In6:
  23654           tnl_type->tnl_auto = 0;            /* configured tunnel */
  23655           tnl_type->tnl_sub_type = 0x2;      /* IPv4 payload only.*/
  23656           tnl_type->tnl_gre = 0x1;           /* GRE tunnel.       */
  23657           tnl_type->tnl_gre_v4_payload = 0x1;/* IPv4 payload only.*/
  23658           tnl_type->tnl_protocol = 0x2F;     /* Protocol GRE      */
  23659           break;
  23660       case bcmTunnelTypeGre6In4:
  23661       case bcmTunnelTypeGre6In6:
  23662           tnl_type->tnl_auto = 0;            /* configured tunnel */
  23663           tnl_type->tnl_sub_type = 0x1;      /* IPv6 payload only.*/
  23664           tnl_type->tnl_gre = 0x1;           /* GRE tunnel.       */
  23665           tnl_type->tnl_gre_v6_payload = 0x1;/* IPv4 payload only.*/
  23666           tnl_type->tnl_protocol = 0x2F;     /* Protocol GRE      */
  23667           break;
  23668       case bcmTunnelTypeGreAnyIn4:
  23669       case bcmTunnelTypeGreAnyIn6:
  23670           tnl_type->tnl_auto = 0;            /* configured tunnel    */
  23671           tnl_type->tnl_sub_type = 0x3;      /* IPv4 & IPv6 payload. */
  23672           tnl_type->tnl_gre = 0x1;           /* GRE tunnel.          */
  23673           tnl_type->tnl_gre_v4_payload = 0x1;/* IPv4 payload only.   */
  23674           tnl_type->tnl_gre_v6_payload = 0x1;/* IPv4 payload only.   */
  23675           tnl_type->tnl_protocol = 0x2F;     /* Protocol GRE      */
  23676           break;
  23677       case bcmTunnelTypePimSmDr1:
  23678       case bcmTunnelTypePimSmDr2:
  23679       case bcmTunnelTypePim6SmDr1:
  23680       case bcmTunnelTypePim6SmDr2:
  23681           tnl_type->tnl_auto = 0;            /* configured tunnel    */
  23682           tnl_type->tnl_sub_type = 0x3;      /* IPv4 & IPv6 payload. */
  23683           tnl_type->tnl_pim_sm = 0x1;        /* PIM SM tunnel.       */
  23684           tnl_type->tnl_protocol = 0x67;     /* Protocol PIM         */
  23685           break;
  23686       case bcmTunnelTypeUdp:
  23687           tnl_type->tnl_auto = 0;            /* configured tunnel    */
  23688           tnl_type->tnl_sub_type = 0x3;      /* IPv4 & IPv6 payload. */
  23689           tnl_type->tnl_udp = 0x1;           /* UDP tunnel.          */
  23690           tnl_type->tnl_protocol = 0x11;     /* Protocol UDP         */
  23691           break;
  23692       case bcmTunnelTypeWlanWtpToAc:
  23693           tnl_type->tnl_auto = 0;            /* configured tunnel    */
  23694           tnl_type->tnl_sub_type = 0x3;      /* IPv4 & IPv6 payload. */
  23695           tnl_type->tnl_udp_type = 0x1;      /* UDP tunnel.          */
  23696           tnl_type->tnl_protocol = 0x11;     /* Protocol UDP         */
  23697           break;
  23698       case bcmTunnelTypeWlanAcToAc:
  23699           tnl_type->tnl_auto = 0;            /* configured tunnel    */
  23700           tnl_type->tnl_sub_type = 0x3;      /* IPv4 & IPv6 payload. */
  23701           tnl_type->tnl_udp_type = 0x0;      /* UDP tunnel.          */
  23702           tnl_type->tnl_protocol = 0x11;     /* Protocol UDP         */
  23703           break;
  23704       case bcmTunnelTypeWlanWtpToAc6:
  23705           tnl_type->tnl_auto = 0;            /* configured tunnel    */
  23706           tnl_type->tnl_sub_type = 0x3;      /* IPv4 & IPv6 payload. */
  23707           tnl_type->tnl_udp_type = 0x1;      /* UDP tunnel.          */
  23708           tnl_type->tnl_protocol = 0x88;     /* Protocol UDP lite    */
  23709           break;
  23710       case bcmTunnelTypeWlanAcToAc6:
  23711           tnl_type->tnl_auto = 0;            /* configured tunnel    */
  23712           tnl_type->tnl_sub_type = 0x3;      /* IPv4 & IPv6 payload. */
  23713           tnl_type->tnl_udp_type = 0x0;      /* UDP tunnel.          */
  23714           tnl_type->tnl_protocol = 0x88;     /* Protocol UDP lite    */
  23715           break;
  23716       case bcmTunnelTypeAutoMulticast:
  23717       case bcmTunnelTypeAutoMulticast6:
  23718           tnl_type->tnl_auto = 0;			 /* Configured tunnel	 */
  23719           tnl_type->tnl_sub_type = 0x2;
  23720           tnl_type->tnl_udp_type = 0x2; 	 /* AMT tunnel. 		 */
  23721           tnl_type->tnl_protocol = 0x11;       /* Protocol UDP         */
  23722           break;
  23723       default:
  23724           return (BCM_E_PARAM);
  23725     }
  23726     return (BCM_E_NONE);
  23727 }
  23728 
  23729 /*
  23730  * Function:
  23731  *      bcm_xgs3_l3_get_tnl_term_type
  23732  * Purpose:
  23733  *      Get tunnel terminator API type
  23734  * Parameters:
  23735  *      unit          - (IN)SOC unit number
  23736  *      tnl_info      - (IN/OUT)tnl_info Tunnel parameters.
  23737  *      tnl_type      - (IN)Tunnel type.
  23738  * Returns:
  23739  *      BCM_E_XXX
  23740  */
  23741 int
  23742 _bcm_xgs3_l3_get_tnl_term_type(int unit, bcm_tunnel_terminator_t *tnl_info,
  23743                                _bcm_tnl_term_type_t *tnl_type)
  23744 
  23745 {
  23746     int v6;                 /* Outer header is ipv6. */
  23747 
  23748     /* Input parameters check. */
  23749     if ((NULL == tnl_type) || (NULL == tnl_info)) {
  23750         return (BCM_E_PARAM);
  23751     }
  23752 
  23753     if (tnl_type->tnl_auto) {             /* Automatic tunnel */
  23754         switch (tnl_type->tnl_sub_type) {
  23755           case 0x0:
  23756               tnl_info->type = bcmTunnelType6In4Uncheck;
  23757               break;
  23758           case 0x1:
  23759               tnl_info->type = bcmTunnelTypeIsatap;
  23760               break;
  23761           case 0x2:
  23762               tnl_info->type = bcmTunnelType6In4;
  23763               break;
  23764           default:
  23765               return (BCM_E_PARAM);
  23766         }
  23767         return (BCM_E_NONE);
  23768     }
  23769 
  23770     /* Configured tunnel */
  23771 
  23772     /* Read outer header IP version. */
  23773     v6 = tnl_type->tnl_outer_hdr_ipv6;
  23774 
  23775     if (tnl_type->tnl_gre) {
  23776 
  23777         if ((tnl_type->tnl_gre_v4_payload) &&
  23778             (tnl_type->tnl_gre_v6_payload)) {
  23779             tnl_info->type = (v6) ? bcmTunnelTypeGreAnyIn6 :
  23780                 bcmTunnelTypeGreAnyIn4;
  23781         } else {
  23782             if (tnl_type->tnl_gre_v6_payload) {
  23783                 tnl_info->type = (v6) ? bcmTunnelTypeGre6In6 :
  23784                     bcmTunnelTypeGre6In4;
  23785             } else {
  23786                 tnl_info->type = (v6) ? bcmTunnelTypeGre4In6 :
  23787                     bcmTunnelTypeGre4In4;
  23788             }
  23789         }
  23790     } else if (tnl_type->tnl_udp) {
  23791         tnl_info->type = bcmTunnelTypeUdp;
  23792     } else if (tnl_type->tnl_pim_sm) {
  23793         tnl_info->type = (v6) ? bcmTunnelTypePim6SmDr1 : bcmTunnelTypePimSmDr1;
  23794     } else if (tnl_type->tnl_protocol == 0x11) {
  23795         if (tnl_type->tnl_udp_type == 1) {
  23796             tnl_info->type = bcmTunnelTypeWlanWtpToAc;
  23797         } else if (tnl_type->tnl_udp_type == 2) {
  23798             tnl_info->type = (v6) ? bcmTunnelTypeAutoMulticast6 : bcmTunnelTypeAutoMulticast;
  23799         } else {
  23800 #ifdef BCM_TRIDENT3_SUPPORT
  23801             if (SOC_IS_TRIDENT3X(unit)) {
  23802                 tnl_info->type = (v6) ? bcmTunnelTypeAutoMulticast6 : bcmTunnelTypeAutoMulticast;
  23803             } else
  23804 #endif
  23805             tnl_info->type = bcmTunnelTypeWlanAcToAc;
  23806         }
  23807     } else if (tnl_type->tnl_protocol == 0x88) {
  23808         if (tnl_type->tnl_udp_type == 1) {
  23809             tnl_info->type = bcmTunnelTypeWlanWtpToAc6;
  23810         } else {
  23811             tnl_info->type = bcmTunnelTypeWlanAcToAc6;
  23812         }
  23813     } else {
  23814         switch (tnl_type->tnl_sub_type) {
  23815           case 0x3:
  23816               tnl_info->type = (v6) ? bcmTunnelTypeIpAnyIn6 :
  23817                  bcmTunnelTypeIpAnyIn4;
  23818               break;
  23819           case 0x2:
  23820               tnl_info->type = (v6) ? bcmTunnelTypeIp4In6 :
  23821                   bcmTunnelTypeIp4In4;
  23822               break;
  23823           case 0x1:
  23824               tnl_info->type = (v6) ? bcmTunnelTypeIp6In6 :
  23825                   bcmTunnelTypeIp6In4;
  23826               break;
  23827           default:
  23828               return (BCM_E_PARAM);
  23829         }
  23830     }
  23831     return (BCM_E_NONE);
  23832 }
  23833 
  23834 /*
  23835  * Function:
  23836  *      bcm_xgs3_tunnel_terminator_validate
  23837  * Purpose:
  23838  *     Tunnel terminator structure sanity check routine.
  23839  * Parameters:
  23840  *      unit     - (IN) SOC unit number.
  23841  *      tnl_info - (IN) Tunnel terminator parameters.
  23842  * Returns:
  23843  *      BCM_E_NONE  - If data in the structure is valid.
  23844  *      BCM_E_PARAMS - otherwise.
  23845  */
  23846 STATIC int
  23847 _bcm_xgs3_tunnel_terminator_validate(int unit,
  23848                                      bcm_tunnel_terminator_t *tnl_info)
  23849 {
  23850     int support;         /* Tunnel type support by device. */
  23851     int masklen;         /* IPv6 sip/dip mask length.      */
  23852     bcm_ip6_t zero_addr; /* IPv6 sip address.              */
  23853     int rv;              /* Operation return status.       */
  23854 
  23855     /* Input parameters check. */
  23856     if (NULL == tnl_info) {
  23857         return (SOC_E_PARAM);
  23858     }
  23859 
  23860     /* Vrf range sanity. */
  23861     if ((tnl_info->vrf > SOC_VRF_MAX(unit)) ||
  23862         (tnl_info->vrf <  BCM_L3_VRF_DEFAULT)) {
  23863         return (BCM_E_PARAM);
  23864     }
  23865 
  23866     /* fwd_vlan range sanity. */
  23867     if (tnl_info->fwd_vlan != 0) {
  23868         if (!BCM_VLAN_VALID(tnl_info->fwd_vlan)) {
  23869             return BCM_E_PARAM;
  23870         }
  23871     }
  23872 
  23873     if (!soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
  23874         if (_BCM_TUNNEL_OUTER_HEADER_IPV6(tnl_info->type)) {
  23875             sal_memset(zero_addr, 0, sizeof(bcm_ip6_t));
  23876 
  23877             /* Destination ip mask must be a full mask. */
  23878             masklen = bcm_ip6_mask_length(tnl_info->dip6_mask);
  23879             if (masklen != BCM_XGS3_L3_IPV6_PREFIX_LEN) {
  23880                 return (BCM_E_PARAM);
  23881             }
  23882 
  23883             /* Apply source ip subnet mask. */
  23884             rv = bcm_xgs3_l3_mask6_apply(tnl_info->sip6_mask, tnl_info->sip6);
  23885             BCM_IF_ERROR_RETURN(rv);
  23886         } else {
  23887             /* Destination ip mask must be a full mask. */
  23888             if (tnl_info->dip_mask != BCM_XGS3_L3_IP4_FULL_MASK)  {
  23889                 return (BCM_E_PARAM);
  23890             }
  23891 
  23892             /* Apply source ip subnet mask. */
  23893             tnl_info->sip &= tnl_info->sip_mask;
  23894         }
  23895     }
  23896 
  23897     rv = _bcm_xgs3_tunnel_type_support_check(unit, tnl_info->type,
  23898                                              &support, NULL);
  23899     BCM_IF_ERROR_RETURN(rv);
  23900 
  23901     if (FALSE == support) {
  23902         return (BCM_E_UNAVAIL);
  23903     }
  23904 
  23905     return (BCM_E_NONE);
  23906 }
  23907 
  23908 /*
  23909  * Function:
  23910  *      _bcm_xgs3_l3_tnl_term_entry_init
  23911  * Purpose:
  23912  *      Initialize soc tunnel terminator entry key portion.
  23913  * Parameters:
  23914  *      unit     - (IN)  BCM device number.
  23915  *      tnl_info - (IN)  BCM buffer with tunnel info.
  23916  *      entry    - (OUT) SOC buffer with key filled in.
  23917  * Returns:
  23918  *      BCM_E_XXX
  23919  */
  23920 STATIC int
  23921 _bcm_xgs3_l3_tnl_term_entry_init(int unit, bcm_tunnel_terminator_t *tnl_info,
  23922                                  soc_tunnel_term_t *entry)
  23923 {
  23924     int       idx;                /* Entry iteration index.     */
  23925     int       idx_max;            /* Entry widht.               */
  23926     uint32    *entry_ptr;         /* Filled entry pointer.      */
  23927     _bcm_tnl_term_type_t tnl_type;/* Tunnel type.               */
  23928     soc_field_t vrf_fld;          /* VRF id field name.         */
  23929     int         rv;               /* Operation return status.   */
  23930 
  23931     /* Input parameters check. */
  23932     if ((NULL == tnl_info) || (NULL == entry)) {
  23933         return (BCM_E_PARAM);
  23934     }
  23935 
  23936 #ifdef BCM_TOMAHAWK3_SUPPORT
  23937     if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
  23938         return _bcm_th3_l3_tnl_term_entry_init(unit, tnl_info, entry);
  23939     }
  23940 #endif
  23941 
  23942     /* Get tunnel type & sub_type. */
  23943     rv = _bcm_xgs3_l3_set_tnl_term_type(unit, tnl_info, &tnl_type);
  23944     BCM_IF_ERROR_RETURN(rv);
  23945 
  23946     /* Reset destination structure. */
  23947     sal_memset(entry, 0, sizeof(soc_tunnel_term_t));
  23948 
  23949     /* Set Destination/Source pair. */
  23950     entry_ptr = (uint32 *)&entry->entry_arr[0];
  23951     if (tnl_type.tnl_outer_hdr_ipv6) {
  23952 #if defined(BCM_TRX_SUPPORT)
  23953         /* Apply mask on source address. */
  23954         rv = bcm_xgs3_l3_mask6_apply(tnl_info->sip6_mask, tnl_info->sip6);
  23955         BCM_IF_ERROR_RETURN(rv);
  23956 
  23957         /* SIP [0-63] */
  23958         soc_mem_ip6_addr_set(unit, L3_TUNNELm,
  23959                              (uint32 *)&entry->entry_arr[0], IP_ADDRf,
  23960                              tnl_info->sip6, SOC_MEM_IP6_LOWER_ONLY);
  23961         /* SIP [64-127] */
  23962         soc_mem_ip6_addr_set(unit, L3_TUNNELm,
  23963                              (uint32 *)&entry->entry_arr[1], IP_ADDRf,
  23964                              tnl_info->sip6, SOC_MEM_IP6_UPPER_ONLY);
  23965         /* DIP [0-63] */
  23966         soc_mem_ip6_addr_set(unit, L3_TUNNELm,
  23967                              (uint32 *)&entry->entry_arr[2], IP_ADDRf,
  23968                              tnl_info->dip6, SOC_MEM_IP6_LOWER_ONLY);
  23969         /* DIP [64-127] */
  23970         soc_mem_ip6_addr_set(unit, L3_TUNNELm,
  23971                              (uint32 *)&entry->entry_arr[3], IP_ADDRf,
  23972                              tnl_info->dip6, SOC_MEM_IP6_UPPER_ONLY);
  23973 
  23974         /* SIP MASK [0-63] */
  23975         soc_mem_ip6_addr_set(unit, L3_TUNNELm,
  23976                              (uint32 *)&entry->entry_arr[0], IP_ADDR_MASKf,
  23977                              tnl_info->sip6_mask, SOC_MEM_IP6_LOWER_ONLY);
  23978         /* SIP MASK [64-127] */
  23979         soc_mem_ip6_addr_set(unit, L3_TUNNELm,
  23980                              (uint32 *)&entry->entry_arr[1], IP_ADDR_MASKf,
  23981                              tnl_info->sip6_mask, SOC_MEM_IP6_UPPER_ONLY);
  23982         /* DIP MASK [0-63] */
  23983         soc_mem_ip6_addr_set(unit, L3_TUNNELm,
  23984                              (uint32 *)&entry->entry_arr[2], IP_ADDR_MASKf,
  23985                              tnl_info->dip6_mask, SOC_MEM_IP6_LOWER_ONLY);
  23986         /* DIP MASK [64-127] */
  23987         soc_mem_ip6_addr_set(unit, L3_TUNNELm,
  23988                              (uint32 *)&entry->entry_arr[3], IP_ADDR_MASKf,
  23989                              tnl_info->dip6_mask, SOC_MEM_IP6_UPPER_ONLY);
  23990 #endif /* BCM_TRX_SUPPORT */
  23991     }  else {
  23992         tnl_info->sip &= tnl_info->sip_mask;
  23993 
  23994         /* Set destination ip. */
  23995         soc_L3_TUNNELm_field32_set(unit, entry_ptr, DIPf, tnl_info->dip);
  23996 
  23997         /* Set source ip. */
  23998         soc_L3_TUNNELm_field32_set(unit, entry_ptr, SIPf, tnl_info->sip);
  23999 #if defined(BCM_FIREBOLT_SUPPORT)
  24000         if (SOC_IS_FBX(unit)) {
  24001             /* Set destination subnet mask. */
  24002             soc_L3_TUNNELm_field32_set(unit, entry_ptr, DIP_MASKf,
  24003                                        tnl_info->dip_mask);
  24004 
  24005             /* Set source subnet mask. */
  24006             soc_L3_TUNNELm_field32_set(unit, entry_ptr, SIP_MASKf,
  24007                                        tnl_info->sip_mask);
  24008         }
  24009 #endif /* BCM_FIREBOLT_SUPPORT */
  24010     }
  24011 
  24012     /* Resolve vrf field name. */
  24013 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) ||\
  24014         defined(BCM_SCORPION_SUPPORT)
  24015     if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, TUNNEL_VRF_IDf)) {
  24016         vrf_fld = TUNNEL_VRF_IDf;
  24017         if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, TUNNEL_VRF_OVERRIDEf)) {
  24018              soc_L3_TUNNELm_field32_set(unit, entry_ptr, TUNNEL_VRF_OVERRIDEf, 1);
  24019         }
  24020     } else
  24021 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_SCORPION_SUPPORT */
  24022     {
  24023         vrf_fld = INVALIDf;
  24024     }
  24025 
  24026     /* Resolve number of entries hw entry occupies. */
  24027     idx_max = (tnl_type.tnl_outer_hdr_ipv6) ? SOC_TNL_TERM_IPV6_ENTRY_WIDTH : \
  24028               SOC_TNL_TERM_IPV4_ENTRY_WIDTH;
  24029 
  24030     for (idx = 0; idx < idx_max; idx++) {
  24031         entry_ptr = (uint32 *) &entry->entry_arr[idx];
  24032 
  24033         /* Set valid bit. */
  24034         soc_L3_TUNNELm_field32_set(unit, entry_ptr, VALIDf, 1);
  24035 
  24036         /* Set tunnel subtype. */
  24037         soc_L3_TUNNELm_field32_set(unit, entry_ptr, SUB_TUNNEL_TYPEf,
  24038                                    tnl_type.tnl_sub_type);
  24039 
  24040         /* Set tunnel type. */
  24041         soc_L3_TUNNELm_field32_set(unit, entry_ptr, TUNNEL_TYPEf,
  24042                                    tnl_type.tnl_auto);
  24043 #if defined(BCM_TRX_SUPPORT)
  24044         if (SOC_IS_FBX(unit)) {
  24045             /* Set entry mode. */
  24046             if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, MODEf)) {
  24047                 soc_L3_TUNNELm_field32_set(unit, entry_ptr, MODEf,
  24048                                            tnl_type.tnl_outer_hdr_ipv6);
  24049                 soc_L3_TUNNELm_field32_set(unit, entry_ptr, MODE_MASKf, 1);
  24050             } else if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, KEY_TYPEf)) {
  24051                 soc_L3_TUNNELm_field32_set(unit, entry_ptr, KEY_TYPEf,
  24052                         tnl_type.tnl_outer_hdr_ipv6);
  24053             }
  24054 
  24055 
  24056             /* Set tunnel type is GRE bit. */
  24057             if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, GRE_TUNNELf)) {
  24058                 soc_L3_TUNNELm_field32_set(unit, entry_ptr, GRE_TUNNELf,
  24059                                            tnl_type.tnl_gre);
  24060                 soc_L3_TUNNELm_field32_set(unit, entry_ptr, GRE_TUNNEL_MASKf, 1);
  24061 
  24062                 if (tnl_type.tnl_gre) {
  24063                     /* GRE IPv6 payload is allowed. */
  24064                     soc_L3_TUNNELm_field32_set(unit, entry_ptr, GRE_PAYLOAD_IPV6f,
  24065                                                tnl_type.tnl_gre_v6_payload);
  24066 
  24067                     /* GRE IPv6 payload is allowed. */
  24068                     soc_L3_TUNNELm_field32_set(unit, entry_ptr, GRE_PAYLOAD_IPV4f,
  24069                                                tnl_type.tnl_gre_v4_payload);
  24070                 }
  24071             }
  24072         }
  24073 #endif  /* BCM_TRX_SUPPORT */
  24074 
  24075        /* Set entry vrf id. */
  24076         if (INVALIDf != vrf_fld) {
  24077             soc_L3_TUNNELm_field32_set(unit, entry_ptr, vrf_fld, tnl_info->vrf);
  24078         }
  24079     }
  24080     return (BCM_E_NONE);
  24081 }
  24082 
  24083 
  24084 
  24085 /*
  24086  * Function:
  24087  *      bcm_xgs3_tunnel_terminator_add
  24088  * Purpose:
  24089  *      Add a tunnel terminator for DIP-SIP
  24090  * Parameters:
  24091  *      unit     - (IN) SOC unit number.
  24092  *      tnl_info - (IN) Tunnel terminator parameters.
  24093  * Returns:
  24094  *      BCM_E_XXX
  24095  */
  24096 int
  24097 bcm_xgs3_tunnel_terminator_add(int unit, bcm_tunnel_terminator_t *tnl_info)
  24098 {
  24099     bcm_tunnel_terminator_t tmp_info;    /* Entry lookup buffer.       */
  24100     _bcm_l3_ingress_intf_t  iif;         /* Ingress interface.         */
  24101     int old_iif = -1;                    /* Original ingress interface.*/
  24102     int rv;                              /* Operation result.          */
  24103 #ifdef BCM_TOMAHAWK_SUPPORT
  24104     int ecn_map_index;
  24105     int ecn_map_type;
  24106     int ecn_map_num;
  24107 #endif
  24108 #ifdef BCM_TRIDENT3_SUPPORT
  24109     uint32 vlan_profile_idx = 0;
  24110     uint32 action_profile_idx = 0;
  24111 #endif
  24112     uint32 fwd_vlan = tnl_info->fwd_vlan;
  24113     /*  Make sure module was initialized. */
  24114     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  24115         return (BCM_E_INIT);
  24116     }
  24117 
  24118     /* Make sure hw call is initialized.*/
  24119     if ((!BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_term_add)) ||
  24120         (!BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_term_get))) {
  24121         return (BCM_E_UNAVAIL);
  24122     }
  24123 
  24124     /* Check input parameters */
  24125     BCM_IF_ERROR_RETURN
  24126         (_bcm_xgs3_tunnel_terminator_validate(unit, tnl_info));
  24127 
  24128     /* Fill lkup buf. */
  24129     tmp_info = *tnl_info;
  24130 
  24131     /* Check if entry already exists. */
  24132     BCM_XGS3_L3_MODULE_LOCK(unit);
  24133     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_term_get) (unit, &tmp_info);
  24134     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  24135     if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) {
  24136         return (rv);
  24137     }
  24138 
  24139     /* Make sure replace flag is set if replacing existing entry. */
  24140     if (BCM_SUCCESS(rv)) {
  24141         if (0 == (tnl_info->flags & BCM_TUNNEL_REPLACE)) {
  24142             return (BCM_E_EXISTS);
  24143         }
  24144 
  24145         if (BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) && (tmp_info.vlan > BCM_VLAN_MAX)) {
  24146             old_iif = tmp_info.vlan;
  24147         }
  24148     }
  24149 
  24150    /* If SC L3IngressMode Set, then tnl_info->vlan contains the L3_IIF Idx */
  24151     if (BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) && (0 == tnl_info->vlan)) {
  24152         /* Check L3 Ingress Interface mode. */
  24153         if (!(BCM_XGS3_L3_INGRESS_MODE_ISSET(unit))) {
  24154              sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t));
  24155              iif.vrf      = tnl_info->vrf;
  24156              iif.if_class = tnl_info->if_class;
  24157              if ((tnl_info->flags & BCM_TUNNEL_TERM_DSCP_TRUST)
  24158                  && (tnl_info->qos_map_id != 0)) {
  24159                  iif.flags |= BCM_L3_INGRESS_DSCP_TRUST;
  24160                  iif.qos_map_id = tnl_info->qos_map_id;
  24161              }
  24162 #ifdef BCM_TOMAHAWK_SUPPORT             
  24163             if (SOC_IS_TOMAHAWKX(unit) &&
  24164                 soc_feature(unit, soc_feature_ecn_wred) &&
  24165                 (tnl_info->flags & BCM_TUNNEL_TERM_ECN_MAP)) {
  24166                 ecn_map_type = tnl_info->tunnel_term_ecn_map_id & 
  24167                                 _BCM_XGS5_ECN_MAP_TYPE_MASK;
  24168                 ecn_map_index = tnl_info->tunnel_term_ecn_map_id & 
  24169                                 _BCM_XGS5_ECN_MAP_NUM_MASK;
  24170                 ecn_map_num = 
  24171                     soc_mem_index_count(unit, ING_TUNNEL_ECN_DECAPm) / 
  24172                     _BCM_ECN_MAX_ENTRIES_PER_TUNNEL_TERM_MAP;
  24173                 if (ecn_map_type != _BCM_XGS5_ECN_MAP_TYPE_TUNNEL_TERM) {
  24174                     return BCM_E_PARAM;
  24175                 }
  24176                 if (ecn_map_index >= ecn_map_num) {
  24177                     return BCM_E_PARAM;
  24178                 }          
  24179                 if (!bcmi_xgs5_ecn_map_used_get(unit, ecn_map_index, 
  24180                                                 _bcmEcnmapTypeTunnelTerm)) {
  24181                     return BCM_E_PARAM;
  24182                 }
  24183                 iif.tunnel_term_ecn_map_id = ecn_map_index;
  24184                 iif.flags |= BCM_L3_INGRESS_TUNNEL_TERM_ECN_MAP;
  24185             }
  24186 #endif /* BCM_TOMAHAWK_SUPPORT */           
  24187              rv =_bcm_xgs3_l3_ingress_interface_add (unit, &iif);
  24188              if (BCM_FAILURE(rv)) {
  24189                  if (-1 != old_iif) {
  24190                      (void)_bcm_xgs3_l3_ingress_interface_delete(unit, old_iif);
  24191                  }
  24192                  return (rv);
  24193              }
  24194              tnl_info->vlan = iif.intf_id;
  24195         }
  24196     }
  24197 
  24198 #ifdef BCM_TRIDENT3_SUPPORT
  24199     if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, DEFAULT_VLAN_PROFILE_INDEXf)) {
  24200         void *entries[1];
  24201         tunnel_default_vlan_profile_entry_t tunnel_default_vlan_profile_entry;
  24202 
  24203         if (tnl_info->flags & BCM_TUNNEL_REPLACE) {
  24204             soc_tunnel_term_t key;
  24205             soc_tunnel_term_t entry;
  24206             uint32 *entry_ptr;
  24207             int index;
  24208 
  24209             rv = _bcm_tr2_l3_tnl_term_entry_init(unit, tnl_info, &key);
  24210 
  24211             /* Find existing tunnel terminator */
  24212             if (BCM_SUCCESS(rv)) {
  24213                 rv = soc_tunnel_term_match(unit, &key, &entry, &index);
  24214             }
  24215             entry_ptr = (uint32 *)&entry.entry_arr[0];
  24216 
  24217             if (BCM_SUCCESS(rv)) {
  24218                 uint32 old_vlan_profile_idx = soc_mem_field32_get(unit, L3_TUNNELm, entry_ptr,
  24219                                               DEFAULT_VLAN_PROFILE_INDEXf);
  24220 
  24221                 if (old_vlan_profile_idx) {
  24222                     /* valid existing vlan profile index; get it */
  24223                     BCM_IF_ERROR_RETURN(
  24224                                 soc_mem_read(unit, L3_TUNNEL_DEFAULT_VLAN_PROFILEm, MEM_BLOCK_ANY,
  24225                                              old_vlan_profile_idx, &tunnel_default_vlan_profile_entry));
  24226 
  24227                     /* get existing action profile */
  24228                     action_profile_idx = soc_mem_field32_get(unit, L3_TUNNEL_DEFAULT_VLAN_PROFILEm,
  24229                                              (uint32 *) &tunnel_default_vlan_profile_entry,
  24230                                              TAG_ACTION_PROFILE_PTRf);
  24231 
  24232                     /* delete action profile */
  24233                     (void)(_bcm_trx_vlan_action_profile_entry_delete(unit, action_profile_idx));
  24234 
  24235                     /* delete existing vlan profile */
  24236                     soc_profile_mem_delete(unit, _bcm_td3_tunnel_default_vlan_profile[unit], old_vlan_profile_idx);
  24237                 }
  24238             }
  24239         }
  24240 
  24241         if (fwd_vlan != 0) {
  24242             bcm_vlan_action_set_t action;
  24243             bcm_vlan_action_set_t_init(&action);
  24244             action.ut_outer = bcmVlanActionAdd;
  24245 
  24246             /* add new action profile */
  24247             BCM_IF_ERROR_RETURN
  24248                 (_bcm_trx_vlan_action_profile_entry_add(unit, &action, &action_profile_idx));
  24249 
  24250             sal_memset(&tunnel_default_vlan_profile_entry, 0, sizeof(tunnel_default_vlan_profile_entry));
  24251 
  24252             /* add new vlan profile */
  24253             soc_L3_TUNNEL_DEFAULT_VLAN_PROFILEm_field_set(unit, &tunnel_default_vlan_profile_entry,
  24254                                                   OUTER_VLAN_TAGf, (uint32 *)&fwd_vlan);
  24255 
  24256             soc_L3_TUNNEL_DEFAULT_VLAN_PROFILEm_field_set(unit, &tunnel_default_vlan_profile_entry,
  24257                                                   TAG_ACTION_PROFILE_PTRf, (uint32 *)&action_profile_idx);
  24258 
  24259             entries[0] = &tunnel_default_vlan_profile_entry;
  24260 
  24261             rv = soc_profile_mem_add(unit,
  24262                                      _bcm_td3_tunnel_default_vlan_profile[unit],
  24263                                      entries, 1, &vlan_profile_idx);
  24264 
  24265             if (BCM_FAILURE(rv)) {
  24266                 (void)(_bcm_trx_vlan_action_profile_entry_delete(unit, action_profile_idx));
  24267                 return rv;
  24268             }
  24269 
  24270             /* carry the profile idx for L3_TUNNEL soc_mem insert */
  24271             tnl_info->fwd_vlan = vlan_profile_idx;
  24272         }
  24273     }
  24274 #endif
  24275 
  24276     /* Insert new/updated entry. */
  24277     BCM_XGS3_L3_MODULE_LOCK(unit);
  24278     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_term_add) (unit, tnl_info);
  24279     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  24280     if (BCM_FAILURE(rv)) {
  24281         if (BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) &&
  24282             (tnl_info->vlan > BCM_VLAN_MAX)) {
  24283             (void)(_bcm_xgs3_l3_ingress_interface_delete(unit, iif.intf_id));
  24284         }
  24285 #ifdef BCM_TRIDENT3_SUPPORT
  24286         if (vlan_profile_idx != 0) {
  24287             (void)(soc_profile_mem_delete(unit,
  24288                        _bcm_td3_tunnel_default_vlan_profile[unit], vlan_profile_idx));
  24289 
  24290             (void)(_bcm_trx_vlan_action_profile_entry_delete(unit, action_profile_idx));
  24291         }
  24292 #endif
  24293     }
  24294 
  24295     if (fwd_vlan != 0) {
  24296         tnl_info->fwd_vlan = fwd_vlan;
  24297     }
  24298 
  24299     /* Remove original ingress interface. */
  24300     if (-1 != old_iif) {
  24301         if (!(BCM_XGS3_L3_INGRESS_MODE_ISSET(unit))){
  24302         (void)_bcm_xgs3_l3_ingress_interface_delete(unit, old_iif);
  24303     }
  24304     }
  24305 
  24306     return (rv);
  24307 }
  24308 
  24309 /*
  24310  * Function:
  24311  *      bcm_xgs3_tunnel_terminator_delete
  24312  * Purpose:
  24313  *      Delete a tunnel terminator for DIP-SIP +
  24314  * Parameters:
  24315  *      unit     - (IN) SOC unit number.
  24316  *      tnl_info - (IN) Tunnel terminator parameters.
  24317  * Returns:
  24318  *      BCM_E_XXX
  24319  */
  24320 
  24321 int
  24322 bcm_xgs3_tunnel_terminator_delete(int unit, bcm_tunnel_terminator_t *tnl_info)
  24323 {
  24324     int rv;
  24325     /*  Make sure module was initialized. */
  24326     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  24327         return (BCM_E_INIT);
  24328     }
  24329 
  24330     /* Make sure hw call is initialized.*/
  24331     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_term_del)) {
  24332         return (BCM_E_UNAVAIL);
  24333     }
  24334 
  24335     /* Check input parameters */
  24336     BCM_IF_ERROR_RETURN
  24337         (_bcm_xgs3_tunnel_terminator_validate(unit, tnl_info));
  24338 
  24339     /* Do entry lookup. */
  24340     BCM_XGS3_L3_MODULE_LOCK(unit);
  24341     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_term_get) (unit, tnl_info);
  24342     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  24343     if (BCM_FAILURE(rv)) {
  24344         return rv;
  24345     }
  24346 
  24347     /* Delete ingress interface. */
  24348     if (BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) &&
  24349         (tnl_info->vlan > BCM_VLAN_MAX)) {
  24350         if (!(BCM_XGS3_L3_INGRESS_MODE_ISSET(unit))){
  24351             BCM_IF_ERROR_RETURN
  24352                 (_bcm_xgs3_l3_ingress_interface_delete(unit, tnl_info->vlan));
  24353         }
  24354     }
  24355 
  24356     /* Delete tunnel entry. */
  24357     BCM_XGS3_L3_MODULE_LOCK(unit);
  24358     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_term_del) (unit, tnl_info);
  24359     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  24360     return rv;
  24361 }
  24362 
  24363 /*
  24364  * Function:
  24365  *      bcm_xgs3_tunnel_terminator_update
  24366  * Purpose:
  24367  *      Update a tunnel terminator for DIP-SIP +
  24368  *             on ER (DST_UDP_PORT/SRC_UDP_PORT)
  24369  * Parameters:
  24370  *      unit     - (IN) SOC unit number.
  24371  *      tnl_info - (IN) Tunnel terminator parameters.
  24372  * Returns:
  24373  *      BCM_E_XXX
  24374  */
  24375 int
  24376 bcm_xgs3_tunnel_terminator_update(int unit, bcm_tunnel_terminator_t *tnl_info)
  24377 {
  24378     if (NULL == tnl_info) {
  24379         return (BCM_E_PARAM);
  24380     }
  24381     tnl_info->flags |= BCM_TUNNEL_REPLACE;
  24382 
  24383     return bcm_xgs3_tunnel_terminator_add(unit,tnl_info);
  24384 }
  24385 
  24386 /*
  24387  * Function:
  24388  *     bcm_xgs3_tunnel_terminator_get
  24389  * Purpose:
  24390  *      Get a tunnel terminator for DIP-SIP +
  24391  *             on ER (DST_UDP_PORT/SRC_UDP_PORT)
  24392  * Parameters:
  24393  *      unit     - (IN) SOC unit number.
  24394  *      tnl_info - (IN) Tunnel terminator parameters.
  24395  * Returns:
  24396  *      BCM_E_XXX
  24397  */
  24398 int
  24399 bcm_xgs3_tunnel_terminator_get(int unit, bcm_tunnel_terminator_t *tnl_info)
  24400 {
  24401 
  24402     int rv;
  24403     /*  Make sure module was initialized. */
  24404     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  24405         return (BCM_E_INIT);
  24406     }
  24407 
  24408     /* Make sure hw call is initialized.*/
  24409     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_term_get)) {
  24410         return (BCM_E_UNAVAIL);
  24411     }
  24412 
  24413     /* Check input parameters */
  24414     BCM_IF_ERROR_RETURN
  24415         (_bcm_xgs3_tunnel_terminator_validate(unit, tnl_info));
  24416 
  24417 
  24418     /* Do entry lookup. */
  24419     BCM_XGS3_L3_MODULE_LOCK(unit);
  24420     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_term_get) (unit, tnl_info);
  24421     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  24422     return rv;
  24423 }
  24424 
  24425 /*
  24426  * Function:
  24427  *      bcm_xgs3_tunnel_terminator_traverse
  24428  * Purpose:
  24429  *      Traverse all tunnel terminator entries
  24430  * Parameters:
  24431  *      unit - SOC unit number
  24432  *      cb - User callback function, called once per entry
  24433  *      user_data - User supplied cookie used in parameter in callback function
  24434  * Returns:
  24435  *      BCM_E_XXX
  24436  */
  24437 int
  24438 bcm_xgs3_tunnel_terminator_traverse(int unit,
  24439                               bcm_tunnel_terminator_traverse_cb cb,
  24440                               void *user_data)
  24441 {
  24442     int rv;
  24443     /*	Make sure module was initialized. */
  24444     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  24445         return (BCM_E_INIT);
  24446     }
  24447 
  24448     BCM_XGS3_L3_MODULE_LOCK(unit);
  24449     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_term_traverse)
  24450                             (unit, cb, user_data);
  24451     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  24452 
  24453     return rv;
  24454 }
  24455 
  24456 /*
  24457  * Function:
  24458  *      _bcm_xgs3_tnl_type_to_hw_code
  24459  * Purpose:
  24460  * Translate tunnel type into value used in hardware
  24461  *    0: None
  24462  *    1: Config
  24463  *    2: Automatic 6to4
  24464  *    3: Automatic ISATAP
  24465  *    4: PIM_DR1
  24466  *    5: PIM_DR2
  24467  *    6: Firebolt - RESERVED/ER - GRE
  24468  *    7: Firebolt - RESERVED/ER - UDP
  24469  *    8: Firebolt - RESERVED/ER - MPLS
  24470  * Parameters:
  24471  *      unit        - (IN) SOC unit number.
  24472  *      tnl_type    - (IN) Tunnel type.
  24473  *      hw_code     - (OUT) HW code for tunnel type.
  24474  *      entry_type  - (OUT) Entry type.
  24475  * Returns:
  24476  *      BCM_E_XXX
  24477  */
  24478 STATIC INLINE int
  24479 _bcm_xgs3_tnl_type_to_hw_code(int unit, bcm_tunnel_type_t tnl_type,
  24480                               int *hw_code, int *entry_type)
  24481 {
  24482     /* Input parameters check. */
  24483     if ((NULL == hw_code) || (NULL == entry_type)) {
  24484         return (BCM_E_PARAM);
  24485     }
  24486 
  24487 #if defined(BCM_TRX_SUPPORT)
  24488     if (soc_feature(unit, soc_feature_tunnel_any_in_6)) {
  24489         return _bcm_trx_tnl_type_to_hw_code(unit, tnl_type, hw_code, entry_type);
  24490     } else
  24491 #endif /* BCM_TRX_SUPPORT */
  24492     {
  24493         *entry_type = BCM_XGS3_TUNNEL_INIT_V4;
  24494     }
  24495 
  24496     switch (tnl_type) {
  24497       case bcmTunnelTypeNone:
  24498            *hw_code = 0;
  24499            break;
  24500 
  24501       case bcmTunnelTypeIp4In4:
  24502       case bcmTunnelTypeIp6In4:
  24503       case bcmTunnelTypeIpAnyIn4:
  24504            *hw_code = 0x1;
  24505            break;
  24506 
  24507       case bcmTunnelTypeIp4In6:
  24508       case bcmTunnelTypeIp6In6:
  24509       case bcmTunnelTypeIpAnyIn6:
  24510            *hw_code = 0x1;
  24511            break;
  24512 
  24513       case bcmTunnelType6In4Uncheck:
  24514            *hw_code = 0x2;
  24515            break;
  24516 
  24517       case bcmTunnelType6In4:
  24518            *hw_code = 0x6;
  24519            break;
  24520 
  24521       case bcmTunnelTypeIsatap:
  24522            *hw_code = 0x3;
  24523            break;
  24524 
  24525       case bcmTunnelTypePimSmDr1:
  24526            *hw_code = 0x4;
  24527            break;
  24528 
  24529       case bcmTunnelTypePimSmDr2:
  24530            *hw_code = 0x5;
  24531            break;
  24532 
  24533       case bcmTunnelTypePim6SmDr1:
  24534            *hw_code = 0x4;
  24535            break;
  24536 
  24537       case bcmTunnelTypePim6SmDr2:
  24538            *hw_code = 0x5;
  24539            break;
  24540 
  24541 
  24542       case bcmTunnelTypeGre4In4:
  24543       case bcmTunnelTypeGre6In4:
  24544       case bcmTunnelTypeGreAnyIn4:
  24545            *hw_code = 0x6;
  24546            break;
  24547       case bcmTunnelTypeUdp:
  24548            *hw_code = 0x7;
  24549            break;
  24550 
  24551       case bcmTunnelTypeMpls:
  24552            *hw_code = 0x8;
  24553            break;
  24554 
  24555       default:
  24556            break;
  24557     }
  24558 
  24559     return (BCM_E_NONE);
  24560 }
  24561 
  24562 
  24563 /*
  24564  * Function:
  24565  *      _bcm_xgs3_tnl_hw_code_to_type
  24566  * Purpose:
  24567  * Translate hw code for tunnel type into api value
  24568  *    0: None
  24569  *    1: Config
  24570  *    2: Automatic 6to4
  24571  *    3: Automatic ISATAP
  24572  *    4: PIM_DR1
  24573  *    5: PIM_DR2
  24574  *    6: Firebolt - RESERVED/ER - GRE
  24575  *    7: Firebolt - RESERVED/ER - UDP
  24576  *    8: Firebolt - RESERVED/ER - MPLS
  24577  * Parameters:
  24578  *      unit        - (IN) SOC unit number.
  24579  *      hw_tnl_type - (IN) HW tunnel code.
  24580  *      entry_type  - (IN) Tunnel entry type.
  24581  *      tunnel_type - (OUT) Tunnel type.
  24582  * Returns:
  24583  *      BCM_E_XXX
  24584  */
  24585 STATIC INLINE int
  24586 _bcm_xgs3_tnl_hw_code_to_type(int unit, int hw_tnl_type,
  24587                               int entry_type, bcm_tunnel_type_t *tunnel_type)
  24588 {
  24589     /* Input parameters check. */
  24590     if (NULL == tunnel_type) {
  24591        return (BCM_E_PARAM);
  24592     }
  24593 
  24594     if ((entry_type == BCM_XGS3_TUNNEL_INIT_MPLS)
  24595 #ifdef BCM_TRIDENT3_SUPPORT
  24596         || (SOC_IS_TRIDENT3X(unit) && (entry_type == BCM_XGS3_TUNNEL_INIT_MPLS_TD3))
  24597 #endif /* BCM_TRIDENT3_SUPPORT */
  24598         ) {
  24599         *tunnel_type = bcmTunnelTypeMpls;
  24600         return BCM_E_NONE;
  24601     }
  24602 
  24603 #if defined(BCM_TRX_SUPPORT)
  24604     if (soc_feature(unit, soc_feature_tunnel_any_in_6)) {
  24605         return _bcm_trx_tnl_hw_code_to_type(unit, hw_tnl_type, entry_type, tunnel_type);
  24606     }
  24607 #if defined(BCM_TOMAHAWK_SUPPORT)
  24608     /* L2GRE and VxLAN need to be supported on Ranger3+
  24609        which has disabled soc_feature_tunnel_any_in_6*/
  24610     if (SOC_IS_TOMAHAWK(unit)) {
  24611         if (hw_tnl_type == 0x7) {
  24612             *tunnel_type = bcmTunnelTypeL2Gre;
  24613             return BCM_E_NONE;
  24614         } else if (hw_tnl_type == 0xB) {
  24615             *tunnel_type = bcmTunnelTypeVxlan;
  24616             return BCM_E_NONE;
  24617         } else {
  24618             return (BCM_E_PARAM);
  24619         }
  24620     }
  24621 #endif /* BCM_TOMAHAWK_SUPPORT */
  24622 #endif /* BCM_TRX_SUPPORT*/
  24623 
  24624     switch (hw_tnl_type) {
  24625       case 0:
  24626           *tunnel_type = bcmTunnelTypeNone;
  24627           break;
  24628       case 1:
  24629           *tunnel_type = bcmTunnelTypeIpAnyIn4;
  24630           break;
  24631       case 2:
  24632           *tunnel_type = bcmTunnelType6In4Uncheck;
  24633           break;
  24634       case 3:
  24635           *tunnel_type = bcmTunnelTypeIsatap;
  24636           break;
  24637       case 4:
  24638           *tunnel_type = (BCM_XGS3_TUNNEL_INIT_V4 == entry_type) ? \
  24639                          bcmTunnelTypePimSmDr1 : bcmTunnelTypePim6SmDr1;
  24640           break;
  24641       case 5:
  24642           *tunnel_type = (BCM_XGS3_TUNNEL_INIT_V4 == entry_type) ? \
  24643                          bcmTunnelTypePimSmDr2 : bcmTunnelTypePim6SmDr2;
  24644           break;
  24645       case 6:
  24646           *tunnel_type = bcmTunnelTypeGreAnyIn4;
  24647           break;
  24648       case 7:
  24649           *tunnel_type = bcmTunnelTypeUdp;
  24650           break;
  24651       case 8:
  24652           *tunnel_type = bcmTunnelTypeMpls;
  24653           break;
  24654       default:
  24655           return (BCM_E_PARAM);
  24656     }
  24657     return (BCM_E_NONE);
  24658 }
  24659 
  24660 /*
  24661  * Function:
  24662  *      _bcm_xgs3_tnl_init_hash_calc
  24663  * Purpose:
  24664  *      Calculate tunnel initiator entry hash(signature).
  24665  * Parameters:
  24666  *      unit     -  (IN)SOC unit number.
  24667  *      buf      -  (IN)Tunnel initiator entry information.
  24668  *      hash     -  (OUT) Hash(signature) calculated value.
  24669  * Returns:
  24670  *      BCM_X_XXX
  24671  */
  24672 STATIC int
  24673 _bcm_xgs3_tnl_init_hash_calc(int unit, void *buf, uint16 *hash)
  24674 {
  24675 
  24676     bcm_tunnel_initiator_t tnl_entry;
  24677 
  24678     if ((NULL == buf) || (NULL == hash)) {
  24679         return (BCM_E_PARAM);
  24680     }
  24681 
  24682 #ifdef BCM_TRIDENT2_SUPPORT
  24683     if (soc_feature(unit, soc_feature_vxlan)) {
  24684         if (bcmTunnelTypeVxlan == ((bcm_tunnel_initiator_t *)buf)->type) {
  24685             BCM_IF_ERROR_RETURN(
  24686                 _bcm_td2_vxlan_tunnel_initiator_hash_calc(
  24687                     unit, buf, hash));
  24688             return (BCM_E_NONE);
  24689         }
  24690     }
  24691 #endif /* BCM_TRIDENT2_SUPPORT */
  24692 #if defined(BCM_GREYHOUND2_SUPPORT)
  24693     if (soc_feature(unit, soc_feature_vxlan_lite)) {
  24694         if ((((bcm_tunnel_initiator_t *)buf)->type == bcmTunnelTypeVxlan) ||
  24695             (((bcm_tunnel_initiator_t *)buf)->type == bcmTunnelTypeVxlan6)) {
  24696             BCM_IF_ERROR_RETURN(
  24697                 bcmi_gh2_vxlan_tunnel_initiator_hash_calc(unit,
  24698                                                           buf, hash));
  24699             return BCM_E_NONE;
  24700         }
  24701     }
  24702 #endif /* BCM_GREYHOUND2_SUPPORT */
  24703 
  24704     /* Copy buffer to structure. */
  24705     sal_memcpy(&tnl_entry, buf, sizeof(bcm_tunnel_initiator_t));
  24706 
  24707     /* Ignore flow label for not V6 tunnels. */
  24708     if (_BCM_TUNNEL_OUTER_HEADER_IPV6(tnl_entry.type))  {
  24709        tnl_entry.flow_label = 0;
  24710     }
  24711 
  24712     /* Mask fields we don't want to include in hash. */
  24713     tnl_entry.flags = 0;
  24714 
  24715     if (SOC_IS_FBX(unit)) {
  24716         switch (tnl_entry.type) {
  24717           case bcmTunnelTypeIp4In4:
  24718           case bcmTunnelTypeIp6In4:
  24719               tnl_entry.type = bcmTunnelTypeIpAnyIn4;
  24720               break;
  24721           case bcmTunnelTypeIp4In6:
  24722           case bcmTunnelTypeIp6In6:
  24723               tnl_entry.type = bcmTunnelTypeIpAnyIn6;
  24724               break;
  24725           case  bcmTunnelTypeGre4In4:
  24726           case  bcmTunnelTypeGre6In4:
  24727               tnl_entry.type = bcmTunnelTypeGreAnyIn4;
  24728               break;
  24729           case    bcmTunnelTypeGre4In6:
  24730           case    bcmTunnelTypeGre6In6:
  24731               tnl_entry.type = bcmTunnelTypeGreAnyIn6;
  24732               break;
  24733           default:
  24734               break;
  24735         }
  24736     }
  24737 
  24738     /* Calculate mac address hash. */
  24739     *hash = _shr_crc16(0, (uint8 *)&tnl_entry,
  24740                        sizeof(bcm_tunnel_initiator_t));
  24741     return (BCM_E_NONE);
  24742 }
  24743 
  24744 /*
  24745  * Function:
  24746  *      _bcm_xgs3_tnl_init_cmp
  24747  * Purpose:
  24748  *      Routine compares tunnel initiator entry with entry in the chip
  24749  *      with specified index.
  24750  * Parameters:
  24751  *      unit       - (IN) SOC unit number.
  24752  *      buf        - (IN) Tunnel initiator entry to compare.
  24753  *      index      - (IN) Entry index in the chip to compare.
  24754  *      cmp_result - (OUT)Compare result.
  24755  * Returns:
  24756  *      BCM_E_XXX
  24757  */
  24758 STATIC int
  24759 _bcm_xgs3_tnl_init_cmp(int unit, void *buf, int index, int *cmp_result)
  24760 {
  24761 
  24762     bcm_tunnel_initiator_t hw_entry; /* Entry read from hw. */
  24763     bcm_tunnel_initiator_t *tnl_entry;       /* Api passed buffer.  */
  24764     int rv;
  24765 
  24766     if ((NULL == buf) || (NULL == cmp_result)) {
  24767         return (BCM_E_PARAM);
  24768     }
  24769 
  24770 #ifdef BCM_TRIDENT2_SUPPORT
  24771         if (soc_feature(unit, soc_feature_vxlan)) {
  24772             if (bcmTunnelTypeVxlan == ((bcm_tunnel_initiator_t *) buf)->type) {
  24773                 BCM_IF_ERROR_RETURN (
  24774                     _bcm_td2_vxlan_tunnel_initiator_cmp(
  24775                         unit, buf, index, cmp_result));
  24776                 return (BCM_E_NONE);
  24777             }
  24778         }
  24779 #endif /* BCM_TRIDENT2_SUPPORT */
  24780 #if defined(BCM_GREYHOUND2_SUPPORT)
  24781     if (soc_feature(unit, soc_feature_vxlan_lite)) {
  24782         if ((((bcm_tunnel_initiator_t *)buf)->type == bcmTunnelTypeVxlan) ||
  24783             (((bcm_tunnel_initiator_t *)buf)->type == bcmTunnelTypeVxlan6)) {
  24784             BCM_IF_ERROR_RETURN (
  24785                 bcmi_gh2_vxlan_tunnel_initiator_cmp(unit,
  24786                                                     buf, index, cmp_result));
  24787             return BCM_E_NONE;
  24788         }
  24789     }
  24790 #endif /* BCM_GREYHOUND2_SUPPORT */
  24791 
  24792     /* Initialization. */
  24793     bcm_tunnel_initiator_t_init(&hw_entry);
  24794 
  24795     /* Copy buffer to structure. */
  24796     tnl_entry = (bcm_tunnel_initiator_t *) buf;
  24797 
  24798     /* Get tunnel initiator entry from hw. */
  24799     if (BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_init_get)) {
  24800         BCM_XGS3_L3_MODULE_LOCK(unit);
  24801         rv = (BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_init_get) (unit, index,
  24802                                                           &hw_entry));
  24803         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  24804         BCM_IF_ERROR_RETURN(rv);
  24805     } else {
  24806         return (BCM_E_UNAVAIL);
  24807     }
  24808 
  24809     /* Compare source & destination ip. */
  24810     if (_BCM_TUNNEL_OUTER_HEADER_IPV6(tnl_entry->type)) {
  24811         if((sal_memcmp(tnl_entry->dip6, hw_entry.dip6, sizeof(bcm_ip6_t))) ||
  24812            (sal_memcmp(tnl_entry->sip6, hw_entry.sip6, sizeof(bcm_ip6_t))) ||
  24813            (tnl_entry->flow_label != hw_entry.flow_label)) {
  24814             *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  24815             return (BCM_E_NONE);
  24816         }
  24817     } else {
  24818         if ((tnl_entry->dip != hw_entry.dip) ||
  24819             (tnl_entry->sip != hw_entry.sip)) {
  24820             *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  24821             return (BCM_E_NONE);
  24822         }
  24823 
  24824         /* For all boards except FB A0 compare DSCP DF SEL v4/v6 */
  24825         if (SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, tnl_init_v4),
  24826                                 IPV4_DF_SELf)) {
  24827             if ((tnl_entry->flags & BCM_TUNNEL_INIT_SET_DF) !=
  24828                 (hw_entry.flags & BCM_TUNNEL_INIT_SET_DF)) {
  24829                 *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  24830                 return (BCM_E_NONE);
  24831             }
  24832         }
  24833     }
  24834 
  24835     /* Compare hw entry with passed one. */
  24836     if ((tnl_entry->dscp_sel != hw_entry.dscp_sel) ||
  24837         (tnl_entry->dscp != hw_entry.dscp)) {
  24838         *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  24839         return (BCM_E_NONE);
  24840     }
  24841 
  24842     /* Compare tunnel type / ttl */
  24843     if (SOC_IS_FBX(unit)) {
  24844         /* Tunnel type comparison.                                  */
  24845         /* Note: Only outer header matters in tunnel initialization */
  24846         if (tnl_entry->type != hw_entry.type) {
  24847             switch (tnl_entry->type) {
  24848               case bcmTunnelTypeIp4In4:
  24849               case bcmTunnelTypeIp6In4:
  24850                   if (bcmTunnelTypeIpAnyIn4 != hw_entry.type) {
  24851                       *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  24852                       return (BCM_E_NONE);
  24853                   }
  24854                   break;
  24855               case bcmTunnelTypeIp4In6:
  24856               case bcmTunnelTypeIp6In6:
  24857                   if (bcmTunnelTypeIpAnyIn6 != hw_entry.type) {
  24858                       *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  24859                       return (BCM_E_NONE);
  24860                   }
  24861                   break;
  24862               case  bcmTunnelTypeGre4In4:
  24863               case  bcmTunnelTypeGre6In4:
  24864                   if (bcmTunnelTypeGreAnyIn4 != hw_entry.type) {
  24865                       *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  24866                       return (BCM_E_NONE);
  24867                   }
  24868                   break;
  24869               case    bcmTunnelTypeGre4In6:
  24870               case    bcmTunnelTypeGre6In6:
  24871                   if (bcmTunnelTypeGreAnyIn6 != hw_entry.type) {
  24872                       *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  24873                       return (BCM_E_NONE);
  24874                   }
  24875                   break;
  24876               default:
  24877                   *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  24878                   return (BCM_E_NONE);
  24879             }
  24880         }
  24881         if (tnl_entry->ttl != hw_entry.ttl) {
  24882             *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  24883             return (BCM_E_NONE);
  24884         }
  24885         /* Compare destination mac. */
  24886         if (sal_memcmp(tnl_entry->dmac, hw_entry.dmac,
  24887                        sizeof(bcm_mac_t))) {
  24888             *cmp_result = BCM_L3_CMP_NOT_EQUAL;
  24889             return (BCM_E_NONE);
  24890         }
  24891     }
  24892     *cmp_result = BCM_L3_CMP_EQUAL;
  24893     return (BCM_E_NONE);
  24894 }
  24895 
  24896 /* Only be called when IPV6 tunnel insertion is full*/
  24897 int
  24898 bcm_xgs3_tnl_init_defrag(int unit)
  24899 {
  24900     _bcm_l3_tbl_t *tbl_ptr; /* Software table pointer. */
  24901     int lkup_idx;           /* Iteration index.        */
  24902     int idx_to, idx_from;
  24903     int idx_min, idx_max;
  24904     int half_ent_cnt = 0;
  24905     int ent_idx[2] = {0, 0};
  24906     int ifindex;
  24907     int rv = BCM_E_FULL;
  24908     _bcm_tnl_init_data_t tnl_info;
  24909     uint8 *egr_ip_tunnel_buf = NULL; /* EGR_IP_TUNNEL DMA buffer */
  24910     egr_ip_tunnel_entry_t *egr_ip_tunnel;
  24911     uint32 entry_type, tunnel_type;
  24912     bcm_tunnel_initiator_t hw_entry;
  24913 
  24914     soc_mem_t mem = BCM_XGS3_L3_MEM(unit, tnl_init_v4);
  24915 
  24916     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, if_tnl_init_set) ||
  24917         !BCM_XGS3_L3_HWCALL_CHECK(unit, if_tnl_init_get) ||
  24918         !BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_init_get) ||
  24919         !BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_init_add) ||
  24920         !BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_init_del)) {
  24921         rv = BCM_E_UNAVAIL;
  24922         goto clean_up;
  24923     }
  24924 
  24925     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, tnl_init);
  24926      /* get range for min and max indexes */
  24927     idx_min     = tbl_ptr->idx_min;
  24928     idx_max     = tbl_ptr->idx_max;
  24929 
  24930     egr_ip_tunnel_buf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES
  24931                                        (unit, mem),
  24932                                        "EGR_IP_TUNNEL buffer");
  24933     if (NULL == egr_ip_tunnel_buf) {
  24934         rv = BCM_E_MEMORY;
  24935         goto clean_up;
  24936     }
  24937     if ((rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY,
  24938                                  idx_min, idx_max,
  24939                                  egr_ip_tunnel_buf)) < 0) {
  24940         goto clean_up;
  24941     }
  24942     /*
  24943      * Find two half EGR_IP_TUNNEL_IPV6 entries,
  24944      * skip EGR_IP_TUNNEL entry 0 and 1, since entry 0 is reserved.
  24945      */
  24946     for (lkup_idx = idx_min + 2;
  24947          lkup_idx <= idx_max; lkup_idx += 2) {
  24948         egr_ip_tunnel = soc_mem_table_idx_to_pointer
  24949                          (unit, mem, egr_ip_tunnel_entry_t *,
  24950                          egr_ip_tunnel_buf, lkup_idx);
  24951 #ifdef BCM_TRIDENT3_SUPPORT
  24952         if (SOC_IS_TRIDENT3X(unit)) {
  24953             entry_type = soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel,
  24954                                                         DATA_TYPEf);
  24955         } else
  24956 #endif
  24957         {
  24958             entry_type = soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel,
  24959                                                         ENTRY_TYPEf);
  24960         }
  24961         tunnel_type = soc_EGR_IP_TUNNELm_field32_get(unit, egr_ip_tunnel,
  24962                                                      TUNNEL_TYPEf);
  24963         /* Only find IPV4 tunnel */
  24964         if (!(entry_type == 1 && tunnel_type == 0)) {
  24965             continue;
  24966         }
  24967         /* If this entry and the next entry are occupied, skip, else there is an empty entry */
  24968         if (BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, lkup_idx) &&
  24969             BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, lkup_idx + 1)) {
  24970             continue;
  24971         }
  24972         if (BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, lkup_idx)) {
  24973             ent_idx[half_ent_cnt] = lkup_idx;
  24974         } else {
  24975             ent_idx[half_ent_cnt] = lkup_idx + 1;
  24976         }
  24977 
  24978         half_ent_cnt++;
  24979         if (half_ent_cnt == 2) {
  24980             break;
  24981         }
  24982     }
  24983 
  24984     if (half_ent_cnt != 2) {
  24985         goto clean_up;
  24986     }
  24987     sal_memset(&hw_entry, 0, sizeof(hw_entry));
  24988     idx_from = ent_idx[1];
  24989     /* Read the entry will be moved from. */
  24990     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_init_get) (unit, idx_from, &hw_entry);
  24991     if (rv < 0) {
  24992        goto clean_up;
  24993     }
  24994     /* Find the free idx of the entry will be moved to. */
  24995     idx_to = (ent_idx[0] % 2) ?  (ent_idx[0] - 1) : (ent_idx[0] + 1);
  24996     /* Move entry to free entry. */
  24997     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_init_add) (unit, idx_to, &hw_entry, NULL);
  24998     if (rv < 0) {
  24999         goto clean_up;
  25000     }
  25001 
  25002     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, intf);
  25003     /* get range for min and max indexes. */
  25004     idx_min = tbl_ptr->idx_min;
  25005     idx_max = tbl_ptr->idx_max;
  25006 
  25007     /* trvaverse L3_INTF to modify tnl_idx. */
  25008     for (ifindex = idx_min; ifindex <= idx_max; ifindex++) {
  25009         if (!BCM_L3_INTF_USED_GET(unit, ifindex)) {
  25010             continue;
  25011         }
  25012         sal_memset(&tnl_info, 0, sizeof(tnl_info));
  25013         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_tnl_init_get) (unit, ifindex, &tnl_info);
  25014         if (rv < 0) {
  25015             goto clean_up;
  25016         }
  25017         if (tnl_info.tnl_idx == idx_from) {
  25018             tnl_info.tnl_idx = idx_to;
  25019             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_tnl_init_set) (unit, ifindex, &tnl_info);
  25020             if (rv < 0) {
  25021                 goto clean_up;
  25022             }
  25023         }
  25024     }
  25025 
  25026     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_init_del) (unit, idx_from, NULL);
  25027     if (rv < 0) {
  25028         goto clean_up;
  25029     }
  25030 
  25031     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, tnl_init);
  25032     BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, idx_to) =
  25033         BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, idx_from);
  25034     BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, idx_from) = 0;
  25035 
  25036 clean_up:
  25037     if (egr_ip_tunnel_buf) {
  25038         soc_cm_sfree(unit, egr_ip_tunnel_buf);
  25039     }
  25040     return (rv);
  25041 }
  25042 
  25043 /*
  25044  * Function:
  25045  *      bcm_xgs3_tnl_init_add
  25046  * Purpose:
  25047  *       Allocate tunnel initiator table index & Write tunnel initiator entry.
  25048  *       Routine trying to match new entry to an existing one,
  25049  *       if match found reference cound is incremented, otherwise
  25050  *       new index allocated & entry added to hw.
  25051  * Parameters:
  25052  *      unit       - (IN)StrataSwitch unit number.
  25053  *      flags      - (IN)Table shared flags.
  25054  *      tnl_entry  - (IN)Tunnel initiator entry.
  25055  *      index      - (OUT)next hop index.
  25056  * Returns:
  25057  *    BCM_E_XXX
  25058  */
  25059 int
  25060 bcm_xgs3_tnl_init_add(int unit, uint32 flags, bcm_tunnel_initiator_t *tnl_entry,
  25061                       int *index)
  25062 {
  25063     _bcm_l3_tbl_op_t data;        /* Operation data.               */
  25064     int rv = BCM_E_NONE;
  25065     if (!(flags & _BCM_L3_SHR_WRITE_DISABLE)) {
  25066         /* Make sure hw call is defined. */
  25067         if (!BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_init_add)) {
  25068             return (BCM_E_UNAVAIL);
  25069         }
  25070     }
  25071 
  25072     /* Initialization */
  25073     sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t));
  25074     data.tbl_ptr =  BCM_XGS3_L3_TBL_PTR(unit, tnl_init);
  25075     data.width = _BCM_EGR_IP_TUNNEL_DOUBLE_WIDE_ENTRY(unit, tnl_entry->type) ?\
  25076                   _BCM_DOUBLE_WIDE: _BCM_SINGLE_WIDE;
  25077     data.oper_flags = flags;
  25078     data.entry_buffer = (void *)tnl_entry;
  25079     data.hash_func = _bcm_xgs3_tnl_init_hash_calc;
  25080     data.cmp_func  = _bcm_xgs3_tnl_init_cmp;
  25081     data.add_func  = BCM_XGS3_L3_HWCALL(unit, tnl_init_add);
  25082     if (flags & _BCM_L3_SHR_WITH_ID) {
  25083         data.entry_index = *index;
  25084     }
  25085 
  25086     /* Add next hop table entry. */
  25087     rv = _bcm_xgs3_tbl_add(unit, &data);
  25088     if ((BCM_E_FULL == rv) && (data.width == _BCM_DOUBLE_WIDE)) {
  25089         if (BCM_E_NONE == bcm_xgs3_tnl_init_defrag(unit)) {
  25090             BCM_IF_ERROR_RETURN(_bcm_xgs3_tbl_add(unit, &data));
  25091         }
  25092     } else if (rv < 0) {
  25093         return rv;
  25094     }
  25095     *index = data.entry_index;
  25096 
  25097     return (BCM_E_NONE);
  25098 }
  25099 
  25100 
  25101 /*
  25102  * Function:
  25103  *      bcm_xgs3_tnl_init_del
  25104  * Purpose:
  25105  *      Delete tunnels initiator entry.
  25106  *      Entry kept if reference counter not equals to 1(Other tunnels
  25107  *      reference the same entry).
  25108  *
  25109  * Parameters:
  25110  *      unit      - (IN)StrataSwitch unit number.
  25111  *      flags     - (IN)Table shared flags.
  25112  *      ent_index - (IN)Entry index.
  25113  * Returns:
  25114  *    BCM_E_XXX
  25115  */
  25116 int
  25117 bcm_xgs3_tnl_init_del(int unit, uint32 flags, int ent_index)
  25118 {
  25119     bcm_tunnel_initiator_t hw_entry;     /* Entry read from hw.    */
  25120     _bcm_l3_tbl_op_t data;               /* Delete operation info. */
  25121     int rv;
  25122 
  25123     /* Initialization */
  25124     sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t));
  25125 
  25126     /* Default is single table entry operation.*/
  25127     data.width = _BCM_SINGLE_WIDE;
  25128 
  25129 
  25130     /* Check hw call is defined. */
  25131     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_init_del)) {
  25132         return (BCM_E_UNAVAIL);
  25133     }
  25134 
  25135     if (!(flags & _BCM_L3_SHR_WRITE_DISABLE)) {
  25136         /* Get tunnel initiator entry from hw. */
  25137         if (BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_init_get)) {
  25138             BCM_XGS3_L3_MODULE_LOCK(unit);
  25139             rv = (BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_init_get) (unit, ent_index,
  25140                                                               &hw_entry));
  25141             BCM_XGS3_L3_MODULE_UNLOCK(unit);
  25142             BCM_IF_ERROR_RETURN(rv);
  25143 
  25144             /* IPv6 tunnels occupy 2 slots. */
  25145             if(_BCM_EGR_IP_TUNNEL_DOUBLE_WIDE_ENTRY(unit, hw_entry.type)) {
  25146                 data.width = _BCM_DOUBLE_WIDE;
  25147             }
  25148         } else {
  25149             return (BCM_E_UNAVAIL);
  25150         }
  25151     }
  25152 
  25153     data.tbl_ptr =  BCM_XGS3_L3_TBL_PTR(unit, tnl_init);
  25154     data.entry_index = ent_index;
  25155     data.oper_flags = flags;
  25156     data.delete_func = BCM_XGS3_L3_HWCALL(unit, tnl_init_del);
  25157 
  25158     /* Delete tunnel initiator table entry. */
  25159     return  _bcm_xgs3_tbl_del(unit, &data);
  25160 }
  25161 
  25162 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)
  25163 /*
  25164  * Function:
  25165  *      _bcm_xgs3_l3_tnl_init_find
  25166  * Purpose:
  25167  *      Find a matched tunnel initiator.
  25168  * Parameters:
  25169  *      unit  - (IN)StrataSwitch unit number.
  25170  *      info  - (IN)Tunnel initiator information.
  25171  *      index - (OUT)HW Tunnel index.
  25172  * Returns:
  25173  *      BCM_E_XXX
  25174  */
  25175 int
  25176 _bcm_xgs3_l3_tnl_init_find(int unit, bcm_tunnel_initiator_t *info,
  25177                            int *tnl_idx)
  25178 {
  25179     _bcm_l3_tbl_op_t data; /* Operation data */
  25180 
  25181     /* Input parameters check. */
  25182     if ((NULL == info) || (NULL == tnl_idx)) {
  25183         return (BCM_E_PARAM);
  25184     }
  25185 
  25186     /* Initialization */
  25187     sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t));
  25188     
  25189     data.tbl_ptr =  BCM_XGS3_L3_TBL_PTR(unit, tnl_init);
  25190     data.width = _BCM_EGR_IP_TUNNEL_DOUBLE_WIDE_ENTRY(unit, info->type) ?
  25191         _BCM_DOUBLE_WIDE: _BCM_SINGLE_WIDE;
  25192     data.oper_flags = info->flags;
  25193     data.entry_buffer = (void *)info;
  25194     data.hash_func = _bcm_xgs3_tnl_init_hash_calc;
  25195     data.cmp_func  = _bcm_xgs3_tnl_init_cmp;
  25196 
  25197     /* Find entry */
  25198     BCM_IF_ERROR_RETURN (_bcm_xgs3_tbl_match(unit, &data));
  25199 
  25200     *tnl_idx = data.entry_index; 
  25201    
  25202     return (BCM_E_NONE);
  25203 }
  25204 #endif /* BCM_TRIDENT2_SUPPORT | BCM_GREYHOUND2_SUPPORT */
  25205 
  25206 /*
  25207  * Function:
  25208  *      bcm_xgs3_tunnel_initiator_set
  25209  * Purpose:
  25210  *      Set the tunnel initiator property for the given L3 interface
  25211  * Parameters:
  25212  *      unit     - (IN)SOC unit number.
  25213  *      intf     - (IN)L3 interface.
  25214  *      tnl_info - (IN)Tunnel initiator information.
  25215  * Returns:
  25216  *      BCM_E_XXX
  25217  */
  25218 int
  25219 bcm_xgs3_tunnel_initiator_set(int unit, bcm_l3_intf_t *intf,
  25220                                  bcm_tunnel_initiator_t *tnl_info)
  25221 {
  25222     _bcm_tnl_init_data_t cfg_ent; /* Tunnel configuration entry.   */
  25223     int ifindex;                  /* Interface index.              */
  25224     int support;                  /* Tunnel type is supported flag.*/
  25225     int rv;                       /* Operation return status.      */
  25226     uint32 shr_flags;             /* Table shared flags.           */
  25227     int tnl_dscp_tbl_sz, max_num_maps;
  25228 
  25229     /*  Make sure module was initialized. */
  25230     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  25231         return (BCM_E_INIT);
  25232     }
  25233 
  25234     /* Input parameters check. */
  25235     if ((NULL == intf) || (NULL == tnl_info)) {
  25236         return (BCM_E_PARAM);
  25237     }
  25238 
  25239     ifindex = intf->l3a_intf_id;
  25240     /* Validate interface index. */
  25241     if (ifindex >= BCM_XGS3_L3_IF_TBL_SIZE(unit)) {
  25242         return (BCM_E_PARAM);
  25243     }
  25244 
  25245     if (!BCM_L3_INTF_USED_GET(unit, ifindex)) {
  25246         return (BCM_E_NOT_FOUND);
  25247     }
  25248 
  25249     /* Validate ttl for firebolt based boards. */
  25250     if (!BCM_TTL_VALID(tnl_info->ttl)) {
  25251         return (BCM_E_PARAM);
  25252     }
  25253 
  25254     /* Validate IP tunnel DSCP SEL. */
  25255     if (tnl_info->dscp_sel > 2 || tnl_info->dscp_sel < 0) {
  25256         return (BCM_E_PARAM);
  25257     }
  25258 
  25259     /* Validate IP tunnel DSCP value. */
  25260     if (tnl_info->dscp > 63 || tnl_info->dscp < 0) {
  25261         return (BCM_E_PARAM);
  25262     }
  25263 
  25264     tnl_dscp_tbl_sz = soc_mem_index_count
  25265                           (unit, BCM_XGS3_L3_MEM(unit, tnl_dscp));
  25266     max_num_maps = tnl_dscp_tbl_sz/_BCM_TNL_DSCP_MAP_TBL_SIZE;
  25267     /* Validate DSCP map */
  25268     if ((tnl_info->dscp_map < 0) || (tnl_info->dscp_map > max_num_maps)) {
  25269         return (BCM_E_PARAM);
  25270     }
  25271 
  25272     /* Validate flow label value. */
  25273     if (_BCM_TUNNEL_OUTER_HEADER_IPV6(tnl_info->type)) {
  25274         if (tnl_info->flow_label > (1 << 20)) {
  25275             return (BCM_E_PARAM);
  25276         }
  25277     }
  25278 
  25279     BCM_IF_ERROR_RETURN
  25280         (_bcm_xgs3_tunnel_type_support_check(unit, tnl_info->type,
  25281                                              NULL, &support));
  25282     if (FALSE == support) {
  25283         return (BCM_E_UNAVAIL);
  25284     }
  25285 
  25286 
  25287     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, if_tnl_init_set) ||
  25288         !BCM_XGS3_L3_HWCALL_CHECK(unit, if_tnl_init_get)) {
  25289         return (BCM_E_UNAVAIL);
  25290     }
  25291 
  25292     /* Reset tunnel configuration buffer. */
  25293     sal_memset(&cfg_ent, 0, sizeof(_bcm_tnl_init_data_t));
  25294 
  25295     /* Check if interface already has tunnel attached. */
  25296         BCM_XGS3_L3_MODULE_LOCK(unit);
  25297         rv = (BCM_XGS3_L3_HWCALL_EXEC(unit, if_tnl_init_get) (unit, ifindex,
  25298                                                           &cfg_ent));
  25299         BCM_XGS3_L3_MODULE_UNLOCK(unit);
  25300         BCM_IF_ERROR_RETURN(rv);
  25301 
  25302     /* Check for tunnel replacement. */
  25303     if (cfg_ent.tnl_idx) {
  25304         if (!(tnl_info->flags & BCM_TUNNEL_REPLACE)) {
  25305             return (BCM_E_EXISTS);
  25306         }
  25307         /* Destroy original tunnel initiator. */
  25308         BCM_IF_ERROR_RETURN (bcm_xgs3_tunnel_initiator_clear(unit, intf));
  25309     }
  25310 
  25311     /* Convert tunnel specific flags to table management flags. */
  25312     BCM_IF_ERROR_RETURN
  25313         (_bcm_xgs3_tunnel_flags_to_shr(tnl_info->flags, &shr_flags));
  25314 
  25315     /* Add tunnel initiator entry to hw. */
  25316     BCM_IF_ERROR_RETURN(bcm_xgs3_tnl_init_add(unit, shr_flags, tnl_info,
  25317                                               &cfg_ent.tnl_idx));
  25318 
  25319     BCM_XGS3_L3_MODULE_LOCK(unit);
  25320     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_tnl_init_set) (unit, ifindex,
  25321                                                          &cfg_ent);
  25322     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  25323 
  25324     /* Do best effort clean up if needed. */
  25325     if (rv < 0) {
  25326         bcm_xgs3_tnl_init_del(unit, 0, cfg_ent.tnl_idx);
  25327     }
  25328     return rv;
  25329 }
  25330 
  25331 /*
  25332  * Function:
  25333  *      bcm_xgs3_tunnel_initiator_clear
  25334  * Purpose:
  25335  *      Delete the tunnel association for the given L3 interface
  25336  * Parameters:
  25337  *      unit - SOC unit number
  25338  *      intf - the given L3 interface
  25339  * Returns:
  25340  *      BCM_E_XXX
  25341  */
  25342 
  25343 int
  25344 bcm_xgs3_tunnel_initiator_clear(int unit, bcm_l3_intf_t *intf)
  25345 {
  25346     _bcm_tnl_init_data_t cfg_ent;       /* Tunnel configuration entry. */
  25347     int ifindex;                /* Interface index.            */
  25348     int rv;
  25349 
  25350     /*  Make sure module was initialized. */
  25351     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  25352         return (BCM_E_INIT);
  25353     }
  25354 
  25355     /* Input parameters check. */
  25356     if (NULL == intf) {
  25357         return (BCM_E_PARAM);
  25358     }
  25359 
  25360     ifindex = intf->l3a_intf_id;
  25361     /* Validate interface index. */
  25362     if (ifindex >= BCM_XGS3_L3_IF_TBL_SIZE(unit)) {
  25363         return (BCM_E_PARAM);
  25364     }
  25365 
  25366     if (!BCM_L3_INTF_USED_GET(unit, ifindex)) {
  25367         return (BCM_E_NOT_FOUND);
  25368     }
  25369 
  25370     /* Make sure required hw call is defined. */
  25371     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, if_tnl_init_reset) ||
  25372         !BCM_XGS3_L3_HWCALL_CHECK(unit, if_tnl_init_get)) {
  25373         return (BCM_E_UNAVAIL);
  25374     }
  25375 
  25376     /* Reset tunnel configuration buffer. */
  25377     sal_memset(&cfg_ent, 0, sizeof(_bcm_tnl_init_data_t));
  25378 
  25379     /* Read tunnel info from hw. */
  25380     BCM_XGS3_L3_MODULE_LOCK(unit);
  25381     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_tnl_init_get) (unit, ifindex,
  25382                                                          &cfg_ent);
  25383     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  25384     BCM_IF_ERROR_RETURN(rv);
  25385 
  25386     /* Make sure tunnel index is valid. */
  25387     if (!cfg_ent.tnl_idx) {
  25388         return (BCM_E_NOT_FOUND);
  25389     }
  25390 
  25391     /* Remove tunnel initiator entry to hw. */
  25392     BCM_IF_ERROR_RETURN(bcm_xgs3_tnl_init_del(unit, 0, cfg_ent.tnl_idx));
  25393 
  25394     BCM_XGS3_L3_MODULE_LOCK(unit);
  25395     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_tnl_init_reset) (unit, ifindex);
  25396     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  25397     return rv;
  25398 }
  25399 
  25400 /*
  25401  * Function:
  25402  *      bcm_xgs3_tunnel_initiator_get
  25403  * Purpose:
  25404  *      Get the tunnel initiator property for the given L3 interface
  25405  * Parameters:
  25406  *      unit - SOC unit number
  25407  *      intf - the given L3 interface
  25408  *      tunnel - (OUT) the tunnel header information
  25409  * Returns:
  25410  *      BCM_E_XXX
  25411  */
  25412 int
  25413 bcm_xgs3_tunnel_initiator_get(int unit, bcm_l3_intf_t *intf,
  25414                                  bcm_tunnel_initiator_t *tnl_info)
  25415 {
  25416     _bcm_tnl_init_data_t cfg_ent;       /* Tunnel configuration entry. */
  25417     int ifindex;                /* Interface index.            */
  25418     int rv;
  25419 
  25420     /*  Make sure module was initialized. */
  25421     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  25422         return (BCM_E_INIT);
  25423     }
  25424 
  25425     /* Input parameters check. */
  25426     if ((NULL == intf) || (NULL == tnl_info)) {
  25427         return (BCM_E_PARAM);
  25428     }
  25429 
  25430     ifindex = intf->l3a_intf_id;
  25431     /* Validate interface index. */
  25432     if (ifindex >= BCM_XGS3_L3_IF_TBL_SIZE(unit)) {
  25433         return (BCM_E_PARAM);
  25434     }
  25435 
  25436     if (!BCM_L3_INTF_USED_GET(unit, ifindex)) {
  25437         return (BCM_E_NOT_FOUND);
  25438     }
  25439 
  25440     /* Make sure required hw call is defined. */
  25441     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, if_tnl_init_get) ||
  25442         !BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_init_get)) {
  25443         return (BCM_E_UNAVAIL);
  25444     }
  25445 
  25446     /* Reset tunnel configuration buffer. */
  25447     sal_memset(&cfg_ent, 0, sizeof(_bcm_tnl_init_data_t));
  25448 
  25449     /* Read tunnel index/ (ER adj_mac_idx, ttl,type) from interface table. */
  25450     BCM_XGS3_L3_MODULE_LOCK(unit);
  25451     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_tnl_init_get) (unit, ifindex,
  25452                                                          &cfg_ent);
  25453     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  25454     BCM_IF_ERROR_RETURN(rv);
  25455 
  25456     /* Make sure tunnel index is valid. */
  25457     if (!cfg_ent.tnl_idx) {
  25458         return (BCM_E_NOT_FOUND);
  25459     }
  25460 
  25461     /* Get tunnel initiator entry info from hw. */
  25462     BCM_XGS3_L3_MODULE_LOCK(unit);
  25463     rv =BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_init_get) (unit, cfg_ent.tnl_idx,
  25464                                                       tnl_info);
  25465     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  25466     BCM_IF_ERROR_RETURN(rv);
  25467     return (BCM_E_NONE);
  25468 }
  25469 
  25470 /*
  25471  * Function:
  25472  *      bcm_xgs3_tunnel_initiator_traverse
  25473  * Purpose:
  25474  *      Traverse all tunnel initiator entries
  25475  * Parameters:
  25476  *      unit - SOC unit number
  25477  *      cb - User callback function, called once per entry
  25478  *      user_data - User supplied cookie used in parameter in callback function
  25479  * Returns:
  25480  *      BCM_E_XXX
  25481  */
  25482 int
  25483 bcm_xgs3_tunnel_initiator_traverse(int unit,
  25484                               bcm_tunnel_initiator_traverse_cb cb,
  25485                               void *user_data)
  25486 {
  25487     int num_intf, idx;
  25488     bcm_l3_intf_t intf;
  25489     bcm_tunnel_initiator_t info;
  25490     int rv = BCM_E_NONE;
  25491 
  25492     /*  Make sure module was initialized. */
  25493     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  25494         return (BCM_E_INIT);
  25495     }
  25496 
  25497     /* Get interface table size. */
  25498     num_intf = BCM_XGS3_L3_IF_TBL_SIZE(unit);
  25499 
  25500     sal_memset(&intf, 0, sizeof(bcm_l3_intf_t));
  25501 
  25502     for(idx = 0; idx < num_intf; idx++) {
  25503         /* Reset buffer before read. */
  25504         bcm_tunnel_initiator_t_init(&info);
  25505 
  25506         /* Get tunnel initiator through interface Id */
  25507         intf.l3a_intf_id = idx;
  25508         rv = bcm_xgs3_tunnel_initiator_get(unit, &intf, &info);
  25509 
  25510         /* Check for read errors & invalid entries. */
  25511         if (rv < 0) {
  25512             if (rv != BCM_E_NOT_FOUND) {
  25513                 break;
  25514             }
  25515             continue;
  25516         }
  25517 
  25518 		if (cb) {
  25519             rv = (*cb) (unit, &info, user_data);
  25520 #ifdef BCM_CB_ABORT_ON_ERR
  25521             if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
  25522                 break;
  25523             }
  25524 #endif
  25525         }
  25526     }
  25527 
  25528     /* Reset last read status. */
  25529     if (BCM_E_NOT_FOUND == rv) {
  25530         rv = BCM_E_NONE;
  25531     }
  25532 
  25533     return rv;
  25534 }
  25535 
  25536 /*
  25537  * Function:
  25538  *      bcm_xgs3_tunnel_dscp_map_create
  25539  * Purpose:
  25540  *      Create a tunnel DSCP map instance.
  25541  * Parameters:
  25542  *      unit         - (IN)  SOC unit #
  25543  *      flags        - (IN)  BCM_L3_XXX
  25544  *      dscp_map_id  - (OUT) Allocated DSCP map ID
  25545  * Returns:
  25546  *      BCM_E_XXX
  25547  */
  25548 int
  25549 bcm_xgs3_tunnel_dscp_map_create(int unit, uint32 flags, int *dscp_map_id)
  25550 {
  25551     int idx;              /* Iteration index.           */
  25552     int idx_max;          /* Iteration index max value. */
  25553 
  25554     /*  Make sure module was initialized. */
  25555     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  25556         return (BCM_E_INIT);
  25557     }
  25558 
  25559     /* Input parameters check. */
  25560     if (NULL == dscp_map_id) {
  25561         return (BCM_E_PARAM);
  25562     }
  25563 
  25564     if (flags & BCM_L3_WITH_ID) {
  25565         if (BCM_L3_DSCP_MAP_USED_GET(unit, *dscp_map_id) &&
  25566             !(flags & BCM_L3_REPLACE)) {
  25567             return (BCM_E_EXISTS);
  25568         }
  25569         BCM_L3_DSCP_MAP_USED_SET(unit, *dscp_map_id);
  25570         return (BCM_E_NONE);
  25571     }
  25572 
  25573     idx_max = BCM_XGS3_L3_TUNNEL_DSCP_MAP_TBL_SIZE(unit);
  25574 
  25575     for (idx = 0; idx < idx_max; idx++) {
  25576         if (!BCM_L3_DSCP_MAP_USED_GET(unit, idx)) {
  25577             BCM_L3_DSCP_MAP_USED_SET(unit, idx);
  25578             *dscp_map_id = idx;
  25579             return (BCM_E_NONE);
  25580         }
  25581     }
  25582     return (BCM_E_FULL);
  25583 }
  25584 
  25585 /*
  25586  * Function:
  25587  *      bcm_xgs3_tunnel_dscp_map_destroy
  25588  * Purpose:
  25589  *      Destroy an existing tunnel DSCP map instance.
  25590  * Parameters:
  25591  *      unit        - (IN) SOC unit #
  25592  *      dscp_map_id - (IN) DSCP map ID
  25593  * Returns:
  25594  *      BCM_E_XXX
  25595  */
  25596 int
  25597 bcm_xgs3_tunnel_dscp_map_destroy(int unit, int dscp_map_id)
  25598 {
  25599     int idx_max;  /* Maximum dscp map index. */
  25600 
  25601     /*  Make sure module was initialized. */
  25602     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  25603         return (BCM_E_INIT);
  25604     }
  25605 
  25606     idx_max = SOC_IS_TRX(unit) ? 1 : BCM_XGS3_L3_TUNNEL_DSCP_MAP_TBL_SIZE(unit);
  25607     if ((dscp_map_id < 0) || (dscp_map_id >= idx_max)) {
  25608         return (BCM_E_PARAM);
  25609     }
  25610 
  25611     BCM_L3_DSCP_MAP_USED_CLR(unit, dscp_map_id);
  25612 
  25613     return (BCM_E_NONE);
  25614 }
  25615 
  25616 /*
  25617  * Function:
  25618  *      bcm_xgs3_tunnel_dscp_map_set
  25619  * Purpose:
  25620  *      Set the mapping of { internal priority, color }
  25621  *      to a DSCP value for outer tunnel headers
  25622  *      in the specified DSCP map instance.
  25623  * Parameters:
  25624  *      unit         - (IN) BCM device number.
  25625  *      dscp_map_id  - (IN) DSCP map ID
  25626  *      dscp_map     - (IN) DSCP map structure.
  25627  * Returns:
  25628  *      BCM_E_XXX
  25629  */
  25630 int
  25631 bcm_xgs3_tunnel_dscp_map_set(int unit, int dscp_map_id,
  25632                              bcm_tunnel_dscp_map_t *dscp_map)
  25633 {
  25634     int cng, index, rv;
  25635 
  25636     /*  Make sure module was initialized. */
  25637     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  25638         return (BCM_E_INIT);
  25639     }
  25640 
  25641     /* Make sure required hw call is defined. */
  25642     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_dscp_set)) {
  25643         return (BCM_E_UNAVAIL);
  25644     }
  25645 
  25646     cng = _BCM_COLOR_ENCODING(unit, dscp_map->color);
  25647 
  25648     /* Get the base index for this DSCP map */
  25649     index = (dscp_map_id * 32);
  25650 
  25651     /* Add the offset based on priority and color values */
  25652     index += ((dscp_map->priority << 2) | (cng & 3));
  25653 
  25654     /* Set tunnel dscp entry info in hw. */
  25655     BCM_XGS3_L3_MODULE_LOCK(unit);
  25656     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_dscp_set)(unit, index, dscp_map);
  25657     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  25658     return rv;
  25659 }
  25660 
  25661 /*
  25662  * Function:
  25663  *      bcm_xgs3_tunnel_dscp_map_get
  25664  * Purpose:
  25665  *      Get the mapping of { internal priority, color }
  25666  *      to a DSCP value for outer tunnel headers
  25667  *      in the specified DSCP map instance.
  25668  * Parameters:
  25669  *      unit         - (IN)  BCM device number.#
  25670  *      dscp_map_id  - (IN)  DSCP map ID
  25671  *      dscp_map     - (OUT) DSCP map structure.
  25672  * Returns:
  25673  *      BCM_E_XXX
  25674  */
  25675 int
  25676 bcm_xgs3_tunnel_dscp_map_get(int unit, int dscp_map_id,
  25677                              bcm_tunnel_dscp_map_t *dscp_map)
  25678 {
  25679     int cng, index, rv;
  25680 
  25681     /*  Make sure module was initialized. */
  25682     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  25683         return (BCM_E_INIT);
  25684     }
  25685 
  25686     /* Make sure required hw call is defined. */
  25687     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_dscp_get)) {
  25688         return (BCM_E_UNAVAIL);
  25689     }
  25690 
  25691     cng = _BCM_COLOR_ENCODING(unit, dscp_map->color);
  25692 
  25693     /* Get the base index for this DSCP map in EGR_DSCP_TABLEm */
  25694     index = (dscp_map_id * 32);
  25695 
  25696     /* Add the offset based on priority and color values */
  25697     index += ((dscp_map->priority << 2) | (cng & 3));
  25698 
  25699     /* Get tunnel dscp entry info from hw. */
  25700     BCM_XGS3_L3_MODULE_LOCK(unit);
  25701     rv  = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_dscp_get) (unit, index, dscp_map);
  25702     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  25703     return rv;
  25704 }
  25705 
  25706 #if defined(BCM_TRX_SUPPORT)
  25707 /*
  25708  * Function:
  25709  *      _bcm_trx_tunnel_dscp_map_port_set
  25710  * Purpose:
  25711  *      Set the mapping of { internal priority, color }
  25712  *      to a DSCP value for outer tunnel headers
  25713  *      in the specified egress port/ports.
  25714  * Parameters:
  25715  *      unit         - (IN) BCM device number.
  25716  *      port         - (IN) Egress port number.
  25717  *      dscp_map     - (IN) DSCP map structure.
  25718  * Returns:
  25719  *      BCM_E_XXX
  25720  */
  25721 int
  25722 _bcm_trx_tunnel_dscp_map_port_set(int unit, bcm_port_t port,
  25723                              bcm_tunnel_dscp_map_t *dscp_map)
  25724 {
  25725     int cng, index, rv;
  25726     bcm_module_t mod_out;
  25727     bcm_port_t port_out;
  25728     bcm_trunk_t tgid_out;
  25729     int id_out;
  25730     int is_local;
  25731     /*  Make sure module was initialized. */
  25732     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  25733         return (BCM_E_INIT);
  25734     }
  25735 
  25736     if ((dscp_map == NULL) ||
  25737         (dscp_map->priority < BCM_PRIO_MIN) ||
  25738         (dscp_map->priority > BCM_PRIO_MAX) ||
  25739         (dscp_map->dscp < 0) ||
  25740         (dscp_map->dscp > 63)) {
  25741         return (BCM_E_PARAM);
  25742     }
  25743 
  25744     /* Make sure required hw call is defined. */
  25745     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_dscp_set)) {
  25746         return (BCM_E_UNAVAIL);
  25747     }
  25748 
  25749     cng = _BCM_COLOR_ENCODING(unit, dscp_map->color);
  25750 
  25751     /* Add the offset based on priority and color values */
  25752     if (BCM_GPORT_IS_SET(port)) {
  25753         BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, port,
  25754                         &mod_out, &port_out, &tgid_out, &id_out));
  25755         if (BCM_GPORT_IS_SUBPORT_PORT(port)) {
  25756 
  25757 #if defined(BCM_HGPROXY_COE_SUPPORT)
  25758             if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
  25759                 _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) {
  25760                 BCM_IF_ERROR_RETURN(
  25761                     _bcmi_coe_subport_physical_port_get(unit,
  25762                                                         port,
  25763                                                         &port));
  25764             } else
  25765 #endif
  25766 
  25767 #if defined(BCM_KATANA2_SUPPORT)
  25768             if ((soc_feature(unit, soc_feature_linkphy_coe) ||
  25769                 soc_feature(unit, soc_feature_subtag_coe)) &&
  25770                 _BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit,
  25771                     port)) {
  25772                 BCM_IF_ERROR_RETURN(_bcm_kt2_modport_to_pp_port_get(unit,
  25773                         mod_out, port_out, &port));
  25774                 if (((port < SOC_INFO(unit).pp_port_index_min) || 
  25775                    (port > SOC_INFO(unit).pp_port_index_max))) {
  25776                     return BCM_E_PORT;
  25777                 } 
  25778            } else
  25779 #endif
  25780            {
  25781                return BCM_E_PORT;
  25782            }
  25783         } else {
  25784             if ((-1 != tgid_out) || (-1 != id_out)) {
  25785                 return BCM_E_PORT;
  25786             }
  25787 
  25788             BCM_IF_ERROR_RETURN
  25789                 (_bcm_esw_modid_is_local(unit, mod_out, &is_local));
  25790             if (!is_local) {
  25791                 return BCM_E_PORT;
  25792             } else {
  25793                 BCM_IF_ERROR_RETURN(
  25794                         bcm_esw_port_local_get(unit, port, &port));
  25795             }
  25796         }
  25797     } else if (!SOC_PORT_VALID(unit, port)) {
  25798         return BCM_E_PORT;
  25799     }
  25800 
  25801     /* KT2 supports 170 ports * 64 entries */
  25802     index = ((port & SOC_PORT_ADDR_MAX(unit)) << 6) | \
  25803             ((dscp_map->priority & 0xF)  << 2) | \
  25804             (cng & 0x3);
  25805 
  25806     /* Set tunnel dscp entry info in hw. */
  25807     BCM_XGS3_L3_MODULE_LOCK(unit);
  25808     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_dscp_set)(unit, index, dscp_map);
  25809     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  25810     return rv;
  25811 }
  25812 
  25813 /*
  25814  * Function:
  25815  *      _bcm_trx_tunnel_dscp_map_port_get
  25816  * Purpose:
  25817  *      Get the mapping of { internal priority, color }
  25818  *      to a DSCP value for outer tunnel headers
  25819  *      in the specified egress port/ports.
  25820  * Parameters:
  25821  *      unit         - (IN)  BCM device number.#
  25822  *      port         - (IN) Egress port number.
  25823  *      dscp_map     - (OUT) DSCP map structure.
  25824  * Returns:
  25825  *      BCM_E_XXX
  25826  */
  25827 int
  25828 _bcm_trx_tunnel_dscp_map_port_get(int unit, bcm_port_t port,
  25829                                  bcm_tunnel_dscp_map_t *dscp_map)
  25830 {
  25831     int cng, index, rv;
  25832     bcm_module_t mod_out;
  25833     bcm_port_t port_out;
  25834     bcm_trunk_t tgid_out;
  25835     int id_out;
  25836     int is_local;
  25837 
  25838     /*  Make sure module was initialized. */
  25839     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  25840         return (BCM_E_INIT);
  25841     }
  25842 
  25843     if ((dscp_map == NULL) ||
  25844         (dscp_map->priority < BCM_PRIO_MIN) ||
  25845         (dscp_map->priority > BCM_PRIO_MAX)) {
  25846         return (BCM_E_PARAM);
  25847     }
  25848 
  25849     /* Make sure required hw call is defined. */
  25850     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, tnl_dscp_get)) {
  25851         return (BCM_E_UNAVAIL);
  25852     }
  25853 
  25854     cng = _BCM_COLOR_ENCODING(unit, dscp_map->color);
  25855 
  25856     /* Add the offset based on port, priority and color values */
  25857     if (BCM_GPORT_IS_SET(port)) {
  25858         BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, port,
  25859                         &mod_out, &port_out, &tgid_out, &id_out));
  25860         if (BCM_GPORT_IS_SUBPORT_PORT(port)) {
  25861 
  25862 #if defined(BCM_HGPROXY_COE_SUPPORT)
  25863             if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
  25864                 _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) {
  25865                 BCM_IF_ERROR_RETURN(
  25866                     _bcmi_coe_subport_physical_port_get(unit,
  25867                                                         port,
  25868                                                         &port));
  25869             } else
  25870 #endif
  25871 
  25872 #if defined(BCM_KATANA2_SUPPORT)
  25873             if ((soc_feature(unit, soc_feature_linkphy_coe) ||
  25874                 soc_feature(unit, soc_feature_subtag_coe)) &&
  25875                 _BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit,
  25876                     port)) {
  25877                 BCM_IF_ERROR_RETURN(_bcm_kt2_modport_to_pp_port_get(unit,
  25878                         mod_out, port_out, &port));
  25879                 if (((port < SOC_INFO(unit).pp_port_index_min) || 
  25880                    (port > SOC_INFO(unit).pp_port_index_max))) {
  25881                     return BCM_E_PORT;
  25882                 } 
  25883            } else
  25884 #endif
  25885            {
  25886                return BCM_E_PORT;
  25887            }
  25888         } else {
  25889             if ((-1 != tgid_out) || (-1 != id_out)) {
  25890                 return BCM_E_PORT;
  25891             }
  25892 
  25893             BCM_IF_ERROR_RETURN
  25894                 (_bcm_esw_modid_is_local(unit, mod_out, &is_local));
  25895             if (!is_local) {
  25896                 return BCM_E_PORT;
  25897             } else {
  25898                 BCM_IF_ERROR_RETURN(
  25899                         bcm_esw_port_local_get(unit, port, &port));
  25900             }
  25901         }
  25902     } else if (!SOC_PORT_VALID(unit, port)) {
  25903         return BCM_E_PORT;
  25904     }
  25905 
  25906     /* KT2 supports 170 ports * 64 entries */
  25907     index = ((port & SOC_PORT_ADDR_MAX(unit)) << 6) | \
  25908             ((dscp_map->priority & 0xF)  << 2) | \
  25909             (cng & 0x3);
  25910 
  25911     /* Get tunnel dscp entry info from hw. */
  25912     BCM_XGS3_L3_MODULE_LOCK(unit);
  25913     rv = BCM_XGS3_L3_HWCALL_EXEC(unit, tnl_dscp_get) (unit, index, dscp_map);
  25914     BCM_XGS3_L3_MODULE_UNLOCK(unit);
  25915     return rv;
  25916 }
  25917 #endif /* BCM_TRX_SUPPORT */
  25918 
  25919 /*
  25920  * Function:
  25921  *      bcm_xgs3_tunnel_config_set
  25922  * Purpose:
  25923  *      Set the global tunnel initiator property
  25924  * Parameters:
  25925  *      unit    - (IN)SOC unit number.
  25926  *      tconfig - (IN)L3 tunneling configuration
  25927  * Returns:
  25928  *      BCM_E_XXX
  25929  */
  25930 
  25931 int
  25932 bcm_xgs3_tunnel_config_set(int unit, bcm_tunnel_config_t *tconfig)
  25933 {
  25934     soc_reg_t reg;
  25935     /*  Make sure module was initialized. */
  25936     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  25937         return (BCM_E_INIT);
  25938     }
  25939 
  25940     /* Input parameters check.*/
  25941     if ((NULL == tconfig) || (tconfig->ip4_id > 0xffff) ||
  25942         (tconfig->ip4_id < 0)) {
  25943         return (BCM_E_PARAM);
  25944     }
  25945 
  25946     /* Check if IPv4 ID space is global */
  25947 #if defined BCM_TRIUMPH2_SUPPORT
  25948     if (SOC_IS_TRIUMPH2(unit)  || SOC_IS_APOLLO(unit)   ||
  25949         SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit)  ||
  25950         SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) ||
  25951         SOC_IS_KATANAX(unit)   || SOC_IS_TRIUMPH3(unit)) {
  25952         int val;
  25953         egr_fragment_id_table_entry_t entry;
  25954         BCM_IF_ERROR_RETURN
  25955             (bcm_esw_switch_control_get(unit, bcmSwitchTunnelIp4IdShared, &val));
  25956         if (val) {
  25957             sal_memset(&entry, 0, sizeof(egr_fragment_id_table_entry_t));
  25958             soc_EGR_FRAGMENT_ID_TABLEm_field32_set(unit, &entry, FRAGMENT_IDf,
  25959                                                    tconfig->ip4_id);
  25960             BCM_IF_ERROR_RETURN
  25961                 (soc_mem_write(unit, EGR_FRAGMENT_ID_TABLEm, SOC_BLOCK_ALL,
  25962                                0, &entry));
  25963         }
  25964     }
  25965 #endif
  25966 
  25967     /*
  25968      * IPv4 ID for non-triumph2 devices
  25969      */
  25970     if (SOC_REG_IS_VALID(unit, EGR_TUNNEL_CONTROLr)) {
  25971         BCM_IF_ERROR_RETURN
  25972             (soc_reg_field32_modify(unit, EGR_TUNNEL_CONTROLr, REG_PORT_ANY,
  25973                                     IPV4_IDf, tconfig->ip4_id));
  25974     }
  25975 
  25976     /*
  25977      * PIM Sparse Mode DR1 Header
  25978      */
  25979     reg = EGR_TUNNEL_PIMDR1_CFG0r;
  25980 #ifdef BCM_TRIDENT3_SUPPORT
  25981     if (SOC_IS_TRIDENT3X(unit)) {
  25982         reg = FLEX_EDITOR_TUNNEL_PIMDR1_CFG0r;
  25983     }
  25984 #endif
  25985     if (SOC_REG_IS_VALID(unit, reg)) {
  25986         BCM_IF_ERROR_RETURN
  25987             (soc_reg_field32_modify(unit, reg, REG_PORT_ANY,
  25988                                     MS_PIMSM_HDRf, tconfig->ms_pimsm_hdr1));
  25989     }
  25990 
  25991     reg = EGR_TUNNEL_PIMDR1_CFG1r;
  25992 #ifdef BCM_TRIDENT3_SUPPORT
  25993     if (SOC_IS_TRIDENT3X(unit)) {
  25994         reg = FLEX_EDITOR_TUNNEL_PIMDR1_CFG1r;
  25995     }
  25996 #endif
  25997     if (SOC_REG_IS_VALID(unit, reg)) {
  25998         BCM_IF_ERROR_RETURN
  25999             (soc_reg_field32_modify(unit, reg, REG_PORT_ANY,
  26000                                     LS_PIMSM_HDRf, tconfig->ls_pimsm_hdr1));
  26001     }
  26002 
  26003     /*
  26004      * PIM Sparse Mode DR2 Header
  26005      */
  26006     reg = EGR_TUNNEL_PIMDR2_CFG0r;
  26007 #ifdef BCM_TRIDENT3_SUPPORT
  26008     if (SOC_IS_TRIDENT3X(unit)) {
  26009         reg = FLEX_EDITOR_TUNNEL_PIMDR2_CFG0r;
  26010     }
  26011 #endif
  26012     if (SOC_REG_IS_VALID(unit, reg)) {
  26013         BCM_IF_ERROR_RETURN
  26014             (soc_reg_field32_modify(unit, reg, REG_PORT_ANY,
  26015                                     MS_PIMSM_HDRf, tconfig->ms_pimsm_hdr2));
  26016     }
  26017 
  26018     reg = EGR_TUNNEL_PIMDR2_CFG1r;
  26019 #ifdef BCM_TRIDENT3_SUPPORT
  26020     if (SOC_IS_TRIDENT3X(unit)) {
  26021         reg = FLEX_EDITOR_TUNNEL_PIMDR2_CFG1r;
  26022     }
  26023 #endif
  26024     if (SOC_REG_IS_VALID(unit, reg)) {
  26025         BCM_IF_ERROR_RETURN
  26026             (soc_reg_field32_modify(unit, reg, REG_PORT_ANY,
  26027                                     LS_PIMSM_HDRf, tconfig->ls_pimsm_hdr2));
  26028     }
  26029 
  26030     return (BCM_E_NONE);
  26031 }
  26032 
  26033 /*
  26034  * Function:
  26035  *      bcm_xgs3_tunnel_config_get
  26036  * Purpose:
  26037  *      Get the global tunnel initiator property
  26038  * Parameters:
  26039  *      unit - SOC unit number
  26040  *      tconfig - Global information about the L3 tunneling configuration
  26041  * Returns:
  26042  *      BCM_E_XXX
  26043  */
  26044 
  26045 int
  26046 bcm_xgs3_tunnel_config_get(int unit, bcm_tunnel_config_t *tconfig)
  26047 {
  26048     uint32 reg_val;         /* Register value */
  26049 
  26050     /*  Make sure module was initialized. */
  26051     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  26052         return (BCM_E_INIT);
  26053     }
  26054 
  26055     /* Input parameters check.*/
  26056     if (NULL == tconfig) {
  26057         return (BCM_E_PARAM);
  26058     }
  26059 
  26060     /* Check if IPv4 ID space is global */
  26061 #if defined BCM_TRIUMPH2_SUPPORT
  26062     if (SOC_IS_TRIUMPH2(unit)      || SOC_IS_APOLLO(unit) ||
  26063             SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) ||
  26064             SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) ||
  26065             SOC_IS_KATANAX(unit)   || SOC_IS_TRIUMPH3(unit)) {
  26066         int val;
  26067         egr_fragment_id_table_entry_t entry;
  26068         BCM_IF_ERROR_RETURN
  26069             (bcm_esw_switch_control_get(unit, bcmSwitchTunnelIp4IdShared, &val));
  26070         if (val) {
  26071             BCM_IF_ERROR_RETURN
  26072                 (soc_mem_read(unit, EGR_FRAGMENT_ID_TABLEm, SOC_BLOCK_ANY,
  26073                                0, &entry));
  26074             tconfig->ip4_id = soc_EGR_FRAGMENT_ID_TABLEm_field32_get
  26075                                   (unit, &entry, FRAGMENT_IDf);
  26076         }
  26077     }
  26078 #endif
  26079 
  26080     /*
  26081      * IPv4 ID for non-triumph2 devices
  26082      */
  26083     if (SOC_REG_IS_VALID(unit, EGR_TUNNEL_CONTROLr)) {
  26084         BCM_IF_ERROR_RETURN(READ_EGR_TUNNEL_CONTROLr(unit, &reg_val));
  26085         tconfig->ip4_id =
  26086             soc_reg_field_get(unit, EGR_TUNNEL_CONTROLr, reg_val, IPV4_IDf);
  26087     }
  26088 
  26089     /*
  26090      * PIM Sparse Mode DR1 Header
  26091      */
  26092     if (SOC_REG_IS_VALID(unit, EGR_TUNNEL_PIMDR1_CFG0r)) {
  26093         BCM_IF_ERROR_RETURN(READ_EGR_TUNNEL_PIMDR1_CFG0r(unit, &reg_val));
  26094         tconfig->ms_pimsm_hdr1 = soc_reg_field_get(unit, EGR_TUNNEL_PIMDR1_CFG0r,
  26095                                                reg_val, MS_PIMSM_HDRf);
  26096     }
  26097 
  26098     if (SOC_REG_IS_VALID(unit, EGR_TUNNEL_PIMDR1_CFG1r)) {
  26099         BCM_IF_ERROR_RETURN(READ_EGR_TUNNEL_PIMDR1_CFG1r(unit, &reg_val));
  26100         tconfig->ls_pimsm_hdr1 = soc_reg_field_get(unit, EGR_TUNNEL_PIMDR1_CFG1r,
  26101                                                reg_val, LS_PIMSM_HDRf);
  26102     }
  26103 
  26104     /*
  26105      * PIM Sparse Mode DR2 Header
  26106      */
  26107     if (SOC_REG_IS_VALID(unit, EGR_TUNNEL_PIMDR2_CFG0r)) {
  26108         BCM_IF_ERROR_RETURN(READ_EGR_TUNNEL_PIMDR2_CFG0r(unit, &reg_val));
  26109         tconfig->ms_pimsm_hdr2 = soc_reg_field_get(unit, EGR_TUNNEL_PIMDR2_CFG0r,
  26110                                                reg_val, MS_PIMSM_HDRf);
  26111     }
  26112 
  26113     if (SOC_REG_IS_VALID(unit, EGR_TUNNEL_PIMDR2_CFG1r)) {
  26114         BCM_IF_ERROR_RETURN(READ_EGR_TUNNEL_PIMDR2_CFG1r(unit, &reg_val));
  26115         tconfig->ls_pimsm_hdr2 = soc_reg_field_get(unit, EGR_TUNNEL_PIMDR2_CFG1r,
  26116                                                reg_val, LS_PIMSM_HDRf);
  26117     }
  26118 
  26119     return (BCM_E_NONE);
  26120 }
  26121 
  26122 
  26123 int
  26124 bcm_xgs3_ip6_defip_find_index(int unit, int index, bcm_l3_route_t *lpm_cfg)
  26125 {
  26126     return (BCM_E_UNAVAIL);
  26127 }
  26128 
  26129 
  26130 /*
  26131  * Function:
  26132  *      _bcm_xgs3_ecmp_grp_get
  26133  * Purpose:
  26134  *      Get ecmp group next hop members by index.
  26135  * Parameters:
  26136  *      unit       - (IN)SOC unit number.
  26137  *      ecmp_index - (IN)Ecmp group id to read.
  26138  *      ecmp_count - (IN)Maximum number of entries to read.
  26139  *      nh_idx     - (OUT)Next hop indexes.
  26140  * Returns:
  26141  *      BCM_E_XXX
  26142  */
  26143 STATIC int
  26144 _bcm_xgs3_ecmp_grp_get(int unit, int ecmp_idx, int ecmp_count, int *nh_idx)
  26145 {
  26146     int idx;                                /* Iteration index.              */
  26147     int max_ent_count;                      /* Number of entries to read.    */
  26148     uint32 hw_buf[SOC_MAX_MEM_WORDS]; /* Buffer to read hw entry.      */
  26149     int one_entry_grp = TRUE;               /* Single next hop entry group.  */
  26150     int rv = BCM_E_UNAVAIL;                 /* Operation return status.      */
  26151 #ifdef BCM_TOMAHAWK3_SUPPORT
  26152     int lb_mode;
  26153 #endif
  26154 
  26155     /* Input parameters sanity check. */
  26156     if ((NULL == nh_idx) || (ecmp_count < 1)) {
  26157         return (BCM_E_PARAM);
  26158     }
  26159 
  26160     /* Zero all next hop indexes first. */
  26161     sal_memset(nh_idx, 0, ecmp_count * sizeof(int));
  26162     sal_memset(hw_buf, 0, SOC_MAX_MEM_WORDS * sizeof(uint32));
  26163 
  26164 #ifdef BCM_TRX_SUPPORT
  26165     if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) {
  26166         /* Get group base pointer. */
  26167         if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  26168              idx = ecmp_idx;
  26169         } else {
  26170               if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  26171                      idx = ecmp_idx;
  26172               } else {
  26173                      idx = ecmp_idx * BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  26174                }
  26175        }
  26176 
  26177         /* Read zero based ecmp count. */
  26178         rv = soc_mem_read(unit, L3_ECMP_COUNTm, MEM_BLOCK_ANY, idx, hw_buf);
  26179         if (BCM_FAILURE(rv)) {
  26180             return rv;
  26181         }
  26182 
  26183         if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMP_COUNTm)) {
  26184             rv = soc_mem_read(unit, INITIAL_L3_ECMP_COUNTm, MEM_BLOCK_ANY, idx, hw_buf);
  26185             BCM_IF_ERROR_RETURN(rv);
  26186         }
  26187         else if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMP_GROUPm)) {
  26188             rv = soc_mem_read(unit, INITIAL_L3_ECMP_GROUPm, MEM_BLOCK_ANY, idx, hw_buf);
  26189             BCM_IF_ERROR_RETURN(rv);
  26190         }
  26191 
  26192         max_ent_count = soc_mem_field32_get(unit, L3_ECMP_COUNTm, hw_buf, COUNTf);
  26193         if (!BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  26194             if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group) == 0) {
  26195                 ecmp_idx *= BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  26196             }
  26197         }
  26198         if (SOC_IS_GREYHOUND(unit) || SOC_IS_HURRICANE3(unit) ||
  26199             SOC_IS_GREYHOUND2(unit)) {
  26200             ecmp_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, hw_buf, BASE_PTRf);
  26201         }
  26202         max_ent_count++; /* Count is zero based. */
  26203 #ifdef BCM_TOMAHAWK3_SUPPORT
  26204         if (soc_feature(unit, soc_feature_l3_ecmp_weighted)) {
  26205             lb_mode = soc_L3_ECMP_COUNTm_field32_get(unit,
  26206                                   hw_buf, LB_MODEf);
  26207             switch(lb_mode) {
  26208                 case BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_256:
  26209                     max_ent_count = 256;
  26210                     break;
  26211                 case BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_512:
  26212                     max_ent_count = 512;
  26213                     break;
  26214                 case BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_1024:
  26215                     max_ent_count = 1024;
  26216                     break;
  26217                 case BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_2048:
  26218                     max_ent_count = 2048;
  26219                     break;
  26220                 case BCM_TH3_L3_ECMP_LB_MODE_WEIGHTED_4096:
  26221                     max_ent_count = 4096;
  26222                     break;
  26223                 default:
  26224                     break;
  26225             }
  26226         }
  26227 #endif
  26228     } else
  26229 #endif  /* BCM_TRX_SUPPORT */
  26230     {
  26231         ecmp_idx *= BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  26232         /* Check number of entries to read. */
  26233         max_ent_count = (ecmp_count < BCM_XGS3_L3_ECMP_MAX_PATHS(unit)) ?  \
  26234                         ecmp_count : BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  26235     }
  26236 
  26237     /* Read all the indexes from hw. */
  26238     for (idx = 0; idx < max_ent_count; idx++) {
  26239 
  26240         /* Read next hop index. */
  26241         rv = soc_mem_read(unit, L3_ECMPm, MEM_BLOCK_ANY,
  26242                           (ecmp_idx + idx), hw_buf);
  26243         if (rv < 0) {
  26244             break;
  26245         }
  26246         nh_idx[idx] = soc_mem_field32_get(unit, L3_ECMPm,
  26247                                           hw_buf, NEXT_HOP_INDEXf);
  26248         /* Check if group contains . */
  26249         if (idx && (nh_idx[idx] != nh_idx[0])) {
  26250             one_entry_grp = FALSE;
  26251         }
  26252 
  26253         if (0 == soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  26254              /* Next hops popuplated in cycle,stop once you read first entry again */
  26255              if (idx && (FALSE == one_entry_grp) && (nh_idx[idx] == nh_idx[0])) {
  26256                  nh_idx[idx] = 0;
  26257                  break;
  26258              }
  26259         } else {
  26260              one_entry_grp = FALSE;
  26261         }
  26262     }
  26263     /* Reset rest of the group if only 1 next hop is present. */
  26264     if (one_entry_grp) {
  26265        sal_memset(nh_idx + 1, 0, (ecmp_count - 1) * sizeof(int));
  26266     }
  26267     return rv;
  26268 }
  26269 
  26270 #if defined(BCM_HURRICANE3_SUPPORT) || defined(BCM_TRX_SUPPORT)
  26271 /*
  26272  * Function:
  26273  *      _bcm_xgs3_ecmp_grp_mem_set
  26274  * Purpose:
  26275  *      helper function to write mem field for multi memory format
  26276  */
  26277 STATIC void
  26278 _bcm_xgs3_ecmp_grp_mem_set(int unit, const soc_mem_t* mem_array, int count,
  26279                            uint32** entry_array,
  26280                            soc_field_t field, uint32 value)
  26281 {
  26282     int i;
  26283 
  26284     for (i = 0; i < count; i++) {
  26285         if (SOC_MEM_IS_VALID(unit, mem_array[i]) &&
  26286             SOC_MEM_FIELD_VALID(unit, mem_array[i], field)) {
  26287             soc_mem_field32_set(unit, mem_array[i], entry_array[i],
  26288                                 field , value);
  26289         }
  26290     }
  26291 }
  26292 #endif /* BCM_HURRICANE3_SUPPORT || BCM_TRX_SUPPORT */
  26293 
  26294 #ifdef BCM_TRX_SUPPORT
  26295 /*
  26296  * Function:
  26297  *      _bcm_xgs3_ecmp_grp_mem_write
  26298  * Purpose:
  26299  *      helper function to write entry into mem for multi memory format
  26300  */
  26301 STATIC int
  26302 _bcm_xgs3_ecmp_grp_mem_write(int unit, const soc_mem_t* mem_array, int count,
  26303                              uint32** entry_array, int index)
  26304 {
  26305     int i;
  26306 
  26307     for (i = 0; i < count; i++) {
  26308         if (SOC_MEM_IS_VALID(unit, mem_array[i])) {
  26309             BCM_IF_ERROR_RETURN(
  26310                 soc_mem_write(unit, mem_array[i], MEM_BLOCK_ALL,
  26311                               index, entry_array[i]));
  26312         }
  26313     }
  26314 
  26315     return BCM_E_NONE;
  26316 }
  26317 #endif /* BCM_TRX_SUPPORT */
  26318 
  26319 /*
  26320  * Function:
  26321  *      _bcm_xgs3_ecmp_grp_add
  26322  * Purpose:
  26323  *      Add ecmp group next hop members, or reset ecmp group entry.
  26324  *      NOTE: Function always writes all the entries in ecmp group.
  26325  *            If there is not enough nh indexes - next hops written
  26326  *            in cycle.
  26327  * Parameters:
  26328  *      unit       - (IN)SOC unit number.
  26329  *      ecmp_grp   - (IN)ecmp group id to write.
  26330  *      buf        - (IN)Next hop indexes or NULL for entry reset.
  26331  *      info       - (IN)ECMP additional info
  26332  * Returns:
  26333  *      BCM_E_XXX
  26334  */
  26335 STATIC int
  26336 _bcm_xgs3_ecmp_grp_add(int unit, int ecmp_grp, void *buf, void *info)
  26337 {
  26338 #ifdef BCM_TRX_SUPPORT
  26339     uint32 l3_ecmp_count[SOC_MAX_MEM_FIELD_WORDS];  /* l3_ecmp_count buf */
  26340 #endif
  26341     uint32 l3_ecmp[SOC_MAX_MEM_FIELD_WORDS];        /* l3_ecmp buf       */
  26342 #if defined(BCM_HURRICANE3_SUPPORT) || defined(BCM_TRX_SUPPORT) ||\
  26343     defined(BCM_GREYHOUND_SUPPORT)
  26344     uint32 hw_buf[3][SOC_MAX_MEM_WORDS];         /* Buffer to read hw entry.*/
  26345 #endif /* BCM_HURRICANE3_SUPPORT || BCM_TRX_SUPPORT || BCM_GREYHOUND_SUPPORT */
  26346 #if defined(BCM_HURRICANE3_SUPPORT) || defined(BCM_TRX_SUPPORT)
  26347     uint32* hw_buf_ptr[3];
  26348     const soc_mem_t l3_ecmp_count_mem[3] = {L3_ECMP_COUNTm,
  26349                                             INITIAL_L3_ECMP_COUNTm,
  26350                                             INITIAL_L3_ECMP_GROUPm};
  26351 #endif /* BCM_HURRICANE3_SUPPORT || BCM_TRX_SUPPORT */
  26352     int max_grp_size=0;                       /* Maximum ecmp group size.*/
  26353     int ecmp_idx;                           /* Ecmp table entry index. */
  26354     int *nh_idx;                            /* Ecmp group nh indexes.  */
  26355     int nh_cycle_idx;                       /* NH cycle index.         */
  26356     int idx=0;                                /* Iteration index.        */
  26357     int rv = BCM_E_NONE;                 /* Operation return value. */
  26358     _bcm_l3_ecmp_group_info_t *ecmp_info = info;
  26359     _bcm_l3_ecmp_group_buffer_t *ecmp_buffer = buf;
  26360 #if defined(BCM_GREYHOUND_SUPPORT)
  26361     _bcm_l3_tbl_op_t data;
  26362 #endif
  26363 #if defined(BCM_HURRICANE3_SUPPORT)
  26364     uint32 reg_val, value;
  26365     ing_l3_next_hop_entry_t ing_nh;
  26366     int l3_ecmp_oif_flds[8] = {  L3_OIF_0f, 
  26367                              L3_OIF_1f, 
  26368                              L3_OIF_2f, 
  26369                              L3_OIF_3f, 
  26370                              L3_OIF_4f, 
  26371                              L3_OIF_5f, 
  26372                              L3_OIF_6f, 
  26373                              L3_OIF_7f }; 
  26374 #endif
  26375 
  26376     /* Input parameters check. */
  26377     if (ecmp_buffer == NULL || ecmp_info == NULL ||
  26378         ecmp_buffer->group_buffer == NULL) {
  26379         return (BCM_E_PARAM);
  26380     }
  26381 
  26382     /* Cast input buffer. */
  26383     nh_idx = ecmp_buffer->group_buffer;
  26384 #ifdef BCM_TRX_SUPPORT
  26385     if ((SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) && (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) {
  26386          max_grp_size = ecmp_info->max_paths;
  26387          ecmp_idx = ecmp_grp;
  26388     } else
  26389 #endif  /* BCM_TRX_SUPPORT */
  26390    {
  26391        max_grp_size = BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  26392        /* Calculate table index. */
  26393        ecmp_idx = ecmp_grp * BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  26394    }
  26395 
  26396 #if defined(BCM_GREYHOUND_SUPPORT)
  26397     if (SOC_IS_GREYHOUND(unit) || SOC_IS_HURRICANE3(unit) ||
  26398         SOC_IS_GREYHOUND2(unit)) {
  26399         max_grp_size = ecmp_info->max_paths;
  26400         if (BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit,ecmp_grp), \
  26401                                                         ecmp_grp)) {
  26402             /* Group has already exists, get base ptr from group table */
  26403             sal_memset (hw_buf[0], 0, SOC_MAX_MEM_WORDS * sizeof(uint32));
  26404             BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMP_COUNTm,
  26405                                 MEM_BLOCK_ANY, ecmp_grp, hw_buf[0]));
  26406             ecmp_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm,
  26407                                            hw_buf[0], BASE_PTRf);
  26408         } else {
  26409             /* Get index to the first slot in the ECMP table
  26410                    * that can accomodate max_grp_size */
  26411             data.width = ecmp_info->max_paths;
  26412             data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp);
  26413             data.oper_flags = _BCM_L3_SHR_TABLE_TRAVERSE_CONTROL;
  26414             data.entry_index = -1;
  26415             rv = _bcm_xgs3_tbl_free_idx_get(unit, &data);
  26416             if (BCM_FAILURE(rv)) {
  26417                 return rv;
  26418             }
  26419             ecmp_idx = data.entry_index;
  26420             BCM_XGS3_L3_ENT_REF_CNT_INC(data.tbl_ptr, data.entry_index, max_grp_size);
  26421 		}
  26422     
  26423         if (ecmp_idx >= BCM_XGS3_L3_ECMP_TBL_SIZE(unit)) {
  26424             return BCM_E_FULL;
  26425         }
  26426     }
  26427 #endif /* BCM_GREYHOUND_SUPPORT */
  26428 
  26429 #if defined(BCM_HURRICANE3_SUPPORT) || defined(BCM_TRX_SUPPORT)
  26430     sal_memset (hw_buf[0], 0, SOC_MAX_MEM_WORDS * sizeof(uint32));
  26431     sal_memset (hw_buf[1], 0, SOC_MAX_MEM_WORDS * sizeof(uint32));
  26432     sal_memset (hw_buf[2], 0, SOC_MAX_MEM_WORDS * sizeof(uint32));
  26433     hw_buf_ptr[0] = hw_buf[0];
  26434     hw_buf_ptr[1] = hw_buf[1];
  26435     hw_buf_ptr[2] = hw_buf[2];
  26436 #endif /* BCM_HURRICANE3_SUPPORT || BCM_TRX_SUPPORT */
  26437 
  26438     /* Write all the indexes to hw. */
  26439     for (idx = 0, nh_cycle_idx = 0; idx < max_grp_size; idx++, nh_cycle_idx++) {
  26440 
  26441         /* Set next hop index. */
  26442         sal_memset (l3_ecmp, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
  26443 
  26444         /* If this is the last nhop then program black-hole. */
  26445         if ( (!idx) && (!nh_idx[nh_cycle_idx]) ) {
  26446               nh_cycle_idx = 0;
  26447         } else  if (!nh_idx[nh_cycle_idx]) {
  26448         /* If next hop index is not set start from the beginning. */
  26449 #ifdef BCM_TRX_SUPPORT
  26450             if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) {
  26451                 /* No entry replication is required. */
  26452                 break;
  26453             }
  26454 #endif  /* BCM_TRX_SUPPORT */
  26455             nh_cycle_idx = 0;
  26456         }
  26457         soc_mem_field32_set(unit, L3_ECMPm, l3_ecmp, NEXT_HOP_INDEXf,
  26458                             nh_idx[nh_cycle_idx]);
  26459         /* Write buffer to hw. */
  26460         rv = soc_mem_write(unit, L3_ECMPm, MEM_BLOCK_ALL,
  26461                            (ecmp_idx + idx), l3_ecmp);
  26462         if (BCM_FAILURE(rv)) {
  26463             break;
  26464         }
  26465 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \
  26466         defined(BCM_TRX_SUPPORT)
  26467         /* Write initial ecmp table. */
  26468         if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMPm)) {
  26469             /* Write buffer to hw. */
  26470             rv = soc_mem_write(unit, INITIAL_L3_ECMPm, MEM_BLOCK_ALL,
  26471                                         (ecmp_idx + idx), l3_ecmp);
  26472             if (BCM_FAILURE(rv)) {
  26473                 break;
  26474             }
  26475         }
  26476 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */
  26477 
  26478 #ifdef BCM_HURRICANE3_SUPPORT
  26479         if (soc_feature(unit, soc_feature_urpf)) {
  26480 
  26481             /* Check if URPF is enabled on device */
  26482             BCM_IF_ERROR_RETURN(
  26483                  READ_L3_DEFIP_RPF_CONTROLr(unit, &reg_val));
  26484             if (reg_val) {
  26485                 if (idx < 8) {
  26486                     BCM_IF_ERROR_RETURN (soc_mem_read(unit, 
  26487                             ING_L3_NEXT_HOPm, MEM_BLOCK_ANY, 
  26488                             nh_idx[idx], &ing_nh));
  26489 
  26490                     value  = soc_ING_L3_NEXT_HOPm_field32_get(unit, 
  26491                             &ing_nh, L3_OIFf);
  26492 
  26493                     _bcm_xgs3_ecmp_grp_mem_set(unit, l3_ecmp_count_mem, 3,
  26494                                                hw_buf_ptr,
  26495                             l3_ecmp_oif_flds[idx], value);
  26496                     _bcm_xgs3_ecmp_grp_mem_set(unit, l3_ecmp_count_mem, 3,
  26497                                                hw_buf_ptr,
  26498                             URPF_COUNTf, idx);
  26499                 } else {
  26500                     /* Inorder to avoid TRAP_TO_CPU, urpf_mode on L3_IIF/PORT 
  26501                      * must be set to STRICT_MODE / LOOSE_MODE 
  26502                      */
  26503                     _bcm_xgs3_ecmp_grp_mem_set(unit, l3_ecmp_count_mem, 3,
  26504                                                hw_buf_ptr,
  26505                             ECMP_GT8f , 1);
  26506                 }
  26507             }
  26508         }
  26509 #endif  /* BCM_HURRICANE3_SUPPORT */
  26510     }
  26511 
  26512 #ifdef BCM_TRX_SUPPORT
  26513     if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm) && BCM_SUCCESS(rv)) {
  26514         int ecmp_count_idx;
  26515         if (SOC_IS_GREYHOUND(unit) || SOC_IS_HURRICANE3(unit) ||
  26516             SOC_IS_GREYHOUND2(unit)) {
  26517             ecmp_count_idx = ecmp_grp;
  26518         } else {
  26519             ecmp_count_idx = ecmp_idx;
  26520         }
  26521 
  26522         if (!BCM_XGS3_L3_MAX_ECMP_MODE(unit)) { 
  26523             /* Set Max Group Size. */
  26524             sal_memset (l3_ecmp_count, 0,
  26525                         SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
  26526             soc_mem_field32_set(unit, L3_ECMP_COUNTm, l3_ecmp_count, 
  26527                             COUNTf, max_grp_size - 1);
  26528 
  26529             rv = soc_mem_write(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL,
  26530                            (ecmp_count_idx+1), l3_ecmp_count);
  26531             BCM_IF_ERROR_RETURN(rv);
  26532         }
  26533         /* Set zero based ecmp count. */
  26534         if (!idx) {
  26535             _bcm_xgs3_ecmp_grp_mem_set(unit, l3_ecmp_count_mem, 3,
  26536                                        hw_buf_ptr, COUNTf, idx);
  26537         } else {
  26538             _bcm_xgs3_ecmp_grp_mem_set(unit, l3_ecmp_count_mem, 3,
  26539                                        hw_buf_ptr, COUNTf, idx - 1);
  26540         }
  26541 
  26542         /* Set group base pointer. */
  26543         _bcm_xgs3_ecmp_grp_mem_set(unit, l3_ecmp_count_mem, 3,
  26544                                    hw_buf_ptr, BASE_PTRf, ecmp_idx);
  26545 
  26546         /* write memory */
  26547         BCM_IF_ERROR_RETURN(
  26548               _bcm_xgs3_ecmp_grp_mem_write(
  26549                   unit, l3_ecmp_count_mem, 3,
  26550                   hw_buf_ptr, ecmp_count_idx));
  26551 
  26552 #ifdef BCM_TRIUMPH2_SUPPORT
  26553         /* mode 1 = max possible ecmp groups */
  26554         if (BCM_XGS3_L3_MAX_ECMP_MODE(unit)) {
  26555             /* Save the max possible paths for this ECMP group in s/w */ 
  26556             BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[ecmp_grp] = ecmp_info->max_paths;
  26557         }
  26558 #endif
  26559     }
  26560 #endif  /* BCM_TRX_SUPPORT */
  26561     return rv;
  26562 }
  26563 
  26564 
  26565 /*
  26566  * Function:
  26567  *      _bcm_xgs3_ecmp_grp_del
  26568  * Purpose:
  26569  *      Reset ecmp group next hop members
  26570  * Parameters:
  26571  *      unit       - (IN)SOC unit number.
  26572  *      ecmp_grp   - (IN)ecmp group id to write.
  26573  *      info       - (IN)ECMP additional info
  26574  * Returns:
  26575  *      BCM_E_XXX
  26576  */
  26577 STATIC int
  26578 _bcm_xgs3_ecmp_grp_del(int unit, int ecmp_grp, void *info)
  26579 {
  26580     uint32 hw_buf[SOC_MAX_MEM_WORDS]; /* Buffer to read hw entry.*/
  26581     int ecmp_idx;               /* Ecmp table entry index. */
  26582     int idx;                    /* Iteration index.        */
  26583     int rv = BCM_E_UNAVAIL;     /* Operation return value. */
  26584     int max_grp_size=0;          /* Maximum ecmp group size.*/
  26585 #if defined(BCM_GREYHOUND_SUPPORT)
  26586     _bcm_l3_tbl_op_t data;
  26587     data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp);
  26588 #endif /* BCM_GREYHOUND_SUPPORT */
  26589 
  26590     /* Initialize ecmp entry. */
  26591         sal_memset (hw_buf, 0, SOC_MAX_MEM_WORDS * sizeof(uint32));
  26592 
  26593        /* Calculate table index. */
  26594 #ifdef BCM_TRX_SUPPORT
  26595        if ((SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) && (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))){
  26596             if (info == NULL) {
  26597                 return BCM_E_INTERNAL;
  26598             }
  26599             max_grp_size = ((_bcm_l3_ecmp_group_info_t*)info)->max_paths;
  26600             ecmp_idx = ecmp_grp;
  26601        } else
  26602 #endif
  26603       {
  26604           max_grp_size = BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  26605           ecmp_idx = ecmp_grp * BCM_XGS3_L3_ECMP_MAX_PATHS(unit);
  26606        }
  26607 #if defined(BCM_GREYHOUND_SUPPORT)
  26608 
  26609     if (SOC_IS_GREYHOUND(unit) || SOC_IS_HURRICANE3(unit) ||
  26610         SOC_IS_GREYHOUND2(unit)) {
  26611         BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMP_COUNTm,
  26612                             MEM_BLOCK_ANY, ecmp_grp, hw_buf));
  26613         ecmp_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, \
  26614                                        hw_buf, BASE_PTRf);
  26615             
  26616     }
  26617     /* clear the buffer */
  26618     sal_memset (hw_buf, 0, SOC_MAX_MEM_WORDS * sizeof(uint32));
  26619 #endif /* BCM_GREYHOUND_SUPPORT */
  26620 
  26621     /* Write all the indexes to hw. */
  26622     for (idx = 0; idx < max_grp_size; idx++) {
  26623         /* Write buffer to hw. */
  26624         rv = soc_mem_write(unit, L3_ECMPm, MEM_BLOCK_ALL,
  26625                            (ecmp_idx + idx), hw_buf);
  26626 
  26627         if (BCM_FAILURE(rv)) {
  26628             return rv;
  26629         }
  26630 
  26631 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \
  26632         defined(BCM_TRX_SUPPORT)
  26633         /* Write initial ecmp table. */
  26634         if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMPm)) {
  26635             /* Write buffer to hw. */
  26636             rv = soc_mem_write(unit, INITIAL_L3_ECMPm, MEM_BLOCK_ALL,
  26637                            (ecmp_idx + idx), hw_buf);
  26638             if (BCM_FAILURE(rv)) {
  26639                 return rv;
  26640             }
  26641         }
  26642 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */
  26643     }
  26644 
  26645 
  26646 #if defined(BCM_GREYHOUND_SUPPORT)
  26647     /* Decrement ref count for the entries in ecmp table
  26648      * Ref count for ecmp_group table is decremented in common table del func. */
  26649     BCM_XGS3_L3_ENT_REF_CNT_DEC(data.tbl_ptr, ecmp_idx, max_grp_size);
  26650 #endif /* BCM_GREYHOUND_SUPPORT */
  26651 
  26652 #ifdef BCM_TRX_SUPPORT
  26653     if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) {
  26654         /* Set group base pointer. */
  26655         if (soc_feature(unit, soc_feature_l3_dynamic_ecmp_group)) {
  26656             ecmp_idx = ecmp_grp;
  26657         }
  26658 
  26659         rv = soc_mem_write(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL,
  26660                            ecmp_idx, hw_buf);
  26661         BCM_IF_ERROR_RETURN(rv);
  26662 
  26663         if (!BCM_XGS3_L3_MAX_ECMP_MODE(unit)) {
  26664             rv = soc_mem_write(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL,
  26665                            (ecmp_idx+1), hw_buf);
  26666             BCM_IF_ERROR_RETURN(rv);
  26667         }
  26668         if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMP_COUNTm)) {
  26669             rv = soc_mem_write(unit, INITIAL_L3_ECMP_COUNTm, MEM_BLOCK_ALL,
  26670                            ecmp_idx, hw_buf);
  26671         }
  26672         if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMP_GROUPm)) {
  26673             rv = soc_mem_write(unit, INITIAL_L3_ECMP_GROUPm, MEM_BLOCK_ALL,
  26674                            ecmp_idx, hw_buf);
  26675         }
  26676 
  26677 #ifdef BCM_TRIUMPH2_SUPPORT
  26678         if (BCM_XGS3_L3_MAX_ECMP_MODE(unit)) {
  26679             /* Reset the max paths of the deleted group */
  26680             BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[ecmp_grp] = 0;
  26681         }
  26682 #endif
  26683     }
  26684 #endif  /* BCM_TRX_SUPPORT */
  26685 
  26686     return rv;
  26687 }
  26688 
  26689 /*
  26690  * Function:
  26691  *      _bcm_xgs3_l3_tnl_term_entry_parse
  26692  * Purpose:
  26693  *      Parse tunnel terminator entry portion.
  26694  * Parameters:
  26695  *      unit     - (IN)  BCM device number.
  26696  *      entry    - (IN)  SOC buffer with tunne information.
  26697  *      tnl_info - (OUT) BCM buffer with tunnel info.
  26698  * Returns:
  26699  *      BCM_E_XXX
  26700  */
  26701 STATIC int
  26702 _bcm_xgs3_l3_tnl_term_entry_parse(int unit, soc_tunnel_term_t *entry,
  26703                                   bcm_tunnel_terminator_t *tnl_info)
  26704 {
  26705     _bcm_tnl_term_type_t tnl_type;  /* Tunnel type information.   */
  26706     uint32 *entry_ptr;              /* Filled entry pointer.      */
  26707     soc_field_t vrf_fld = INVALIDf; /* Vrf id field if supported. */
  26708 
  26709     /* Input parameters check. */
  26710     if ((NULL == tnl_info) || (NULL == entry)) {
  26711         return (BCM_E_PARAM);
  26712     }
  26713 
  26714     /* Reset destination structure. */
  26715     bcm_tunnel_terminator_t_init(tnl_info);
  26716     sal_memset(&tnl_type, 0, sizeof(_bcm_tnl_term_type_t));
  26717 
  26718     entry_ptr = (uint32 *)&entry->entry_arr[0];
  26719 
  26720     /* Get valid bit. */
  26721     if (!soc_L3_TUNNELm_field32_get(unit, entry_ptr, VALIDf)) {
  26722         return (BCM_E_NOT_FOUND);
  26723     }
  26724 
  26725     if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, MODEf)) {
  26726         tnl_type.tnl_outer_hdr_ipv6 =
  26727             soc_L3_TUNNELm_field32_get(unit, entry_ptr, MODEf);
  26728     } else if(SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, KEY_TYPEf)) {
  26729         tnl_type.tnl_outer_hdr_ipv6 =
  26730             soc_L3_TUNNELm_field32_get(unit, entry_ptr, KEY_TYPEf);
  26731     }
  26732 
  26733 
  26734     /* Get Destination/Source pair. */
  26735     if (tnl_type.tnl_outer_hdr_ipv6) {
  26736 #if defined(BCM_TRX_SUPPORT)
  26737         /* SIP [0-63] */
  26738         soc_mem_ip6_addr_get(unit, L3_TUNNELm,
  26739                              (uint32 *)&entry->entry_arr[0], IP_ADDRf,
  26740                              tnl_info->sip6, SOC_MEM_IP6_LOWER_ONLY);
  26741         /* SIP [64-127] */
  26742         soc_mem_ip6_addr_get(unit, L3_TUNNELm,
  26743                              (uint32 *)&entry->entry_arr[1], IP_ADDRf,
  26744                              tnl_info->sip6, SOC_MEM_IP6_UPPER_ONLY);
  26745         /* DIP [0-63] */
  26746         soc_mem_ip6_addr_get(unit, L3_TUNNELm,
  26747                              (uint32 *)&entry->entry_arr[2], IP_ADDRf,
  26748                              tnl_info->dip6, SOC_MEM_IP6_LOWER_ONLY);
  26749         /* DIP [64-127] */
  26750         soc_mem_ip6_addr_get(unit, L3_TUNNELm,
  26751                              (uint32 *)&entry->entry_arr[3], IP_ADDRf,
  26752                              tnl_info->dip6, SOC_MEM_IP6_UPPER_ONLY);
  26753 
  26754         /* SIP MASK [0-63] */
  26755         soc_mem_ip6_addr_get(unit, L3_TUNNELm,
  26756                              (uint32 *)&entry->entry_arr[0], IP_ADDR_MASKf,
  26757                              tnl_info->sip6_mask, SOC_MEM_IP6_LOWER_ONLY);
  26758         /* SIP MASK [64-127] */
  26759         soc_mem_ip6_addr_get(unit, L3_TUNNELm,
  26760                              (uint32 *)&entry->entry_arr[1], IP_ADDR_MASKf,
  26761                              tnl_info->sip6_mask, SOC_MEM_IP6_UPPER_ONLY);
  26762         /* DIP MASK [0-63] */
  26763         soc_mem_ip6_addr_get(unit, L3_TUNNELm,
  26764                              (uint32 *)&entry->entry_arr[2], IP_ADDR_MASKf,
  26765                              tnl_info->dip6_mask, SOC_MEM_IP6_LOWER_ONLY);
  26766         /* DIP MASK [64-127] */
  26767         soc_mem_ip6_addr_get(unit, L3_TUNNELm,
  26768                              (uint32 *)&entry->entry_arr[3], IP_ADDR_MASKf,
  26769                              tnl_info->dip6_mask, SOC_MEM_IP6_UPPER_ONLY);
  26770 #endif /* BCM_TRX_SUPPORT */
  26771 
  26772     }  else {
  26773         /* Get destination ip. */
  26774         tnl_info->dip = soc_L3_TUNNELm_field32_get(unit, entry_ptr, DIPf);
  26775 
  26776         /* Get source ip. */
  26777         tnl_info->sip = soc_L3_TUNNELm_field32_get(unit, entry_ptr, SIPf);
  26778 
  26779         /* Destination subnet mask. */
  26780         tnl_info->dip_mask = BCM_XGS3_L3_IP4_FULL_MASK;
  26781 
  26782         /* Source subnet mask. */
  26783         if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, SIP_MASKf)) {
  26784             tnl_info->sip_mask = soc_L3_TUNNELm_field32_get(unit, entry_ptr,
  26785                                                             SIP_MASKf);
  26786         } else {
  26787             tnl_info->sip_mask = (tnl_info->sip == 0) ? 0x0 :
  26788                 BCM_XGS3_L3_IP4_FULL_MASK;
  26789         }
  26790     }
  26791 
  26792     /* Get tunnel subtype. */
  26793     tnl_type.tnl_sub_type =
  26794         soc_L3_TUNNELm_field32_get(unit, entry_ptr, SUB_TUNNEL_TYPEf);
  26795 
  26796     /* Get tunnel type. */
  26797     tnl_type.tnl_auto =
  26798         soc_L3_TUNNELm_field32_get(unit, entry_ptr, TUNNEL_TYPEf);
  26799 
  26800     /* Copy DSCP from outer header flag. */
  26801     if (soc_L3_TUNNELm_field32_get(unit, entry_ptr, USE_OUTER_HDR_DSCPf)) {
  26802         tnl_info->flags |= BCM_TUNNEL_TERM_USE_OUTER_DSCP;
  26803     }
  26804     /* Copy TTL from outer header flag. */
  26805     if (soc_L3_TUNNELm_field32_get(unit, entry_ptr, USE_OUTER_HDR_TTLf)) {
  26806         tnl_info->flags |= BCM_TUNNEL_TERM_USE_OUTER_TTL;
  26807     }
  26808     /* Keep inner header DSCP flag. */
  26809     if (soc_L3_TUNNELm_field32_get(unit, entry_ptr,
  26810                                    DONOT_CHANGE_INNER_HDR_DSCPf)) {
  26811         tnl_info->flags |= BCM_TUNNEL_TERM_KEEP_INNER_DSCP;
  26812     }
  26813 
  26814     soc_mem_pbmp_field_get(unit, L3_TUNNELm, entry_ptr, ALLOWED_PORT_BITMAPf,
  26815                            &tnl_info->pbmp);
  26816 
  26817     /* IPMC lokup  vlan id.. */
  26818     if(SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, IINTFf)) {
  26819         tnl_info->vlan = soc_L3_TUNNELm_field32_get(unit, entry_ptr, IINTFf);
  26820     }
  26821     /* Get Tunnel class id for VFP match */
  26822     if (SOC_IS_SCORPION(unit)) {
  26823         if(SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, CLASS_IDf)) {
  26824             tnl_info->tunnel_class = soc_L3_TUNNELm_field32_get(unit, entry_ptr,
  26825                                     CLASS_IDf);
  26826         }
  26827     } else {
  26828         if(SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, TUNNEL_CLASS_IDf)) {
  26829             tnl_info->tunnel_class = soc_L3_TUNNELm_field32_get(unit, entry_ptr,
  26830                                     TUNNEL_CLASS_IDf);
  26831         }
  26832     }
  26833 
  26834 #ifdef BCM_FIREBOLT_SUPPORT
  26835     if (SOC_IS_FBX(unit)) {
  26836 #if defined (BCM_RAVEN_SUPPORT) || defined(BCM_FIREBOLT2_SUPPORT) ||  \
  26837     defined (BCM_SCORPION_SUPPORT)
  26838         /* Set vrf id field. */
  26839         vrf_fld = TUNNEL_VRF_IDf;
  26840 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_SCORPION_SUPPORT */
  26841 
  26842         /*  Get trust dscp per tunnel */
  26843         if (soc_feature(unit, soc_feature_tunnel_dscp_trust)) {
  26844             if (soc_L3_TUNNELm_field32_get(unit, entry_ptr, USE_TUNNEL_DSCPf)) {
  26845                 tnl_info->flags |= BCM_TUNNEL_TERM_DSCP_TRUST;
  26846             }
  26847         }
  26848 #ifdef BCM_TRX_SUPPORT
  26849         /* Get gre tunnel indicator. */
  26850         if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, GRE_TUNNELf)){
  26851             tnl_type.tnl_gre =
  26852                 soc_L3_TUNNELm_field32_get(unit, entry_ptr, GRE_TUNNELf);
  26853         }
  26854 
  26855         /* Get gre IPv4 payload allowed. */
  26856         if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, GRE_PAYLOAD_IPV4f)){
  26857             tnl_type.tnl_gre_v4_payload =
  26858                 soc_L3_TUNNELm_field32_get(unit, entry_ptr, GRE_PAYLOAD_IPV4f);
  26859         }
  26860 
  26861         /* Get gre IPv6 payload allowed. */
  26862         if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, GRE_PAYLOAD_IPV6f)){
  26863             tnl_type.tnl_gre_v6_payload =
  26864                 soc_L3_TUNNELm_field32_get(unit, entry_ptr, GRE_PAYLOAD_IPV6f);
  26865         }
  26866 #endif  /* BCM_TRX_SUPPORT */
  26867     }
  26868 #endif /* BCM_FIREBOLT_SUPPORT */
  26869     /* Get tunnel type & sub_type. */
  26870     BCM_IF_ERROR_RETURN
  26871         (_bcm_xgs3_l3_get_tnl_term_type(unit, tnl_info, &tnl_type));
  26872 
  26873     /* Get vrf id. */
  26874     if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, vrf_fld)){
  26875         tnl_info->vrf = soc_L3_TUNNELm_field32_get(unit, entry_ptr, vrf_fld);
  26876     } else {
  26877         tnl_info->vrf = BCM_L3_VRF_DEFAULT;
  26878     }
  26879 
  26880     return (BCM_E_NONE);
  26881 }
  26882 
  26883 /*
  26884  * Function:
  26885  *      _bcm_xgs3_l3_tnl_term_get
  26886  * Purpose:
  26887  *      Get a tunnel terminator for DIP-SIP/ for ER UDP dst/src port.
  26888  * Parameters:
  26889  *      unit     -(IN)SOC unit number.
  26890  *      tnl_info -(IN)Buffer to fill tunnel info.
  26891  * Returns:
  26892  *      BCM_E_XXX
  26893  */
  26894 STATIC int
  26895 _bcm_xgs3_l3_tnl_term_get(int unit, bcm_tunnel_terminator_t *tnl_info)
  26896 {
  26897     soc_tunnel_term_t key;      /* Buffer to fill lookup key.    */
  26898     soc_tunnel_term_t entry;    /* Buffer to read entry from hw. */
  26899     int index;
  26900 
  26901     /* Initialize lookup key. */
  26902 #ifdef BCM_TOMAHAWK3_SUPPORT
  26903     if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
  26904         BCM_IF_ERROR_RETURN
  26905             (_bcm_th3_l3_tnl_term_entry_init(unit, tnl_info, &key));
  26906     } else
  26907 #endif
  26908 #ifdef BCM_TRIUMPH2_SUPPORT
  26909     if (SOC_IS_TRIUMPH2(unit)  || SOC_IS_APOLLO(unit)   ||
  26910         SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit)  ||
  26911         SOC_IS_KATANAX(unit)   || SOC_IS_TRIDENT2X(unit) ||
  26912         SOC_IS_TOMAHAWKX(unit)  || SOC_IS_TRIDENT3X(unit)) {
  26913         BCM_IF_ERROR_RETURN
  26914             (_bcm_tr2_l3_tnl_term_entry_init(unit, tnl_info, &key));
  26915     } else
  26916 #endif /* BCM_TRIUMPH2_SUPPORT */
  26917 #if defined(BCM_TRIUMPH3_SUPPORT)
  26918     if (SOC_IS_TRIUMPH3(unit)) {
  26919         BCM_IF_ERROR_RETURN
  26920             (_bcm_tr3_l3_tnl_term_entry_init(unit, tnl_info, &key));
  26921     } else
  26922 #endif /* BCM_TRIUMPH3_SUPPORT */
  26923     if (!soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
  26924         BCM_IF_ERROR_RETURN
  26925             (_bcm_xgs3_l3_tnl_term_entry_init(unit, tnl_info, &key));
  26926     }
  26927 
  26928     /* Find tunnel terminator in TCAM. */
  26929     BCM_IF_ERROR_RETURN(soc_tunnel_term_match(unit,&key, &entry, &index));
  26930 
  26931     /* Parse lookup result. */
  26932 #ifdef BCM_TOMAHAWK3_SUPPORT
  26933     if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
  26934         BCM_IF_ERROR_RETURN
  26935           (_bcm_th3_l3_tnl_term_entry_parse(unit, &entry, tnl_info));
  26936     } else
  26937 #endif
  26938 #ifdef BCM_TRIUMPH2_SUPPORT
  26939     if (SOC_IS_TRIUMPH2(unit)  || SOC_IS_APOLLO(unit)    ||
  26940         SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit)   ||
  26941         SOC_IS_KATANAX(unit)   || SOC_IS_TRIDENT2X(unit) ||
  26942         SOC_IS_TOMAHAWKX(unit)  || SOC_IS_TRIDENT3X(unit)) {
  26943         BCM_IF_ERROR_RETURN
  26944           (_bcm_tr2_l3_tnl_term_entry_parse(unit, &entry, tnl_info));
  26945     } else
  26946 #endif
  26947 
  26948 #if defined(BCM_TRIUMPH3_SUPPORT)
  26949     if (SOC_IS_TRIUMPH3(unit))  {
  26950         BCM_IF_ERROR_RETURN
  26951           (_bcm_tr3_l3_tnl_term_entry_parse(unit, &entry, tnl_info));
  26952     } else
  26953 #endif
  26954 
  26955     {
  26956         BCM_IF_ERROR_RETURN
  26957           (_bcm_xgs3_l3_tnl_term_entry_parse(unit, &entry, tnl_info));
  26958     }
  26959 
  26960     return (BCM_E_NONE);
  26961 }
  26962 
  26963 
  26964 #ifdef BCM_TOMAHAWK3_SUPPORT
  26965 STATIC int
  26966 _bcm_xgs3_l3_tnl_term_hash_entry_add(int unit, bcm_tunnel_terminator_t *tnl_info, uint32 *entry_ptr)
  26967 {
  26968     int bit_num = 0;
  26969     int tmp_val;                    /* Temp value to check flags. */
  26970     soc_mem_t mem = L3_TUNNEL_DOUBLEm;
  26971     void *profile_entry_ptr;
  26972     uint32 prof_id;
  26973     allowed_port_bitmap_profile_entry_t allowed_ports_profile;
  26974     _bcm_tnl_term_type_t tnl_type;/* Tunnel type. */
  26975 
  26976     /* Get tunnel type & sub_type. */
  26977     BCM_IF_ERROR_RETURN
  26978         (_bcm_xgs3_l3_set_tnl_term_type(unit, tnl_info, &tnl_type));
  26979 
  26980     if (tnl_type.tnl_outer_hdr_ipv6 == 1) {
  26981         mem = L3_TUNNEL_QUADm;
  26982     }
  26983 
  26984     if (tnl_info->flags & BCM_TUNNEL_REPLACE) {
  26985         int rv = BCM_E_NONE;        /* Operation return status.      */
  26986         soc_tunnel_term_t key;      /* Buffer to read entry from hw. */
  26987         soc_tunnel_term_t entry;
  26988         int index;
  26989         int prof_id;
  26990         uint32 *entry_ptr_existing;
  26991 
  26992         rv = _bcm_th3_l3_tnl_term_entry_init(unit, tnl_info, &key);
  26993         /* Find tunnel terminator. */
  26994         if (BCM_SUCCESS(rv)) {
  26995             rv = soc_tunnel_term_match(unit,&key, &entry, &index);
  26996         }
  26997         entry_ptr_existing = (uint32 *)&entry.entry_arr[0];
  26998         if (BCM_SUCCESS(rv)) {
  26999             prof_id = soc_mem_field32_get(unit, mem, entry_ptr_existing,
  27000                                          (mem == L3_TUNNEL_DOUBLEm) ?
  27001                                             IPV4__ALLOWED_PORT_BITMAP_PROFILE_PTRf:
  27002                                             IPV6__ALLOWED_PORT_BITMAP_PROFILE_PTRf);
  27003             soc_profile_mem_delete(unit, _bcm_get_tnl_port_bitmap_profile(unit), prof_id);
  27004         }
  27005     }
  27006 
  27007     tmp_val = (tnl_info->flags & BCM_TUNNEL_TERM_USE_OUTER_DSCP) ? 1 : 0;
  27008     soc_mem_field32_set(unit, mem, entry_ptr,
  27009                (mem == L3_TUNNEL_DOUBLEm) ? IPV4__USE_OUTER_HDR_DSCPf : IPV6__USE_OUTER_HDR_DSCPf, tmp_val);
  27010 
  27011     /* Set flag to use outer header TTL value or not. */
  27012     tmp_val = (tnl_info->flags & BCM_TUNNEL_TERM_USE_OUTER_TTL) ? 1 : 0;
  27013     soc_mem_field32_set(unit, mem, entry_ptr,
  27014                (mem == L3_TUNNEL_DOUBLEm) ? IPV4__USE_OUTER_HDR_TTLf:IPV6__USE_OUTER_HDR_TTLf, tmp_val);
  27015 
  27016     /* Set flag to preserve inner header DSCP value or not. */
  27017     tmp_val = (tnl_info->flags & BCM_TUNNEL_TERM_KEEP_INNER_DSCP) ? 1 : 0;
  27018     soc_mem_field32_set(unit, mem, entry_ptr,
  27019                (mem == L3_TUNNEL_DOUBLEm) ? IPV4__DONOT_CHANGE_INNER_HDR_DSCPf : IPV6__DONOT_CHANGE_INNER_HDR_DSCPf,
  27020                tmp_val);
  27021 
  27022         profile_entry_ptr = &allowed_ports_profile;
  27023         soc_mem_pbmp_field_set(unit, ALLOWED_PORT_BITMAP_PROFILEm, profile_entry_ptr, ING_PORT_BITMAPf,
  27024                                      &tnl_info->pbmp);
  27025         BCM_IF_ERROR_RETURN(
  27026             soc_profile_mem_add(unit, _bcm_get_tnl_port_bitmap_profile(unit),
  27027                                 &profile_entry_ptr, 1, &prof_id));
  27028         soc_mem_field32_set(unit, mem, entry_ptr, (mem == L3_TUNNEL_DOUBLEm) ?
  27029                                 IPV4__ALLOWED_PORT_BITMAP_PROFILE_PTRf:
  27030                                 IPV6__ALLOWED_PORT_BITMAP_PROFILE_PTRf, prof_id);
  27031 
  27032     /* Sev vlan id for ipmc lookup.*/
  27033     if(SOC_MEM_FIELD_VALID(unit, mem, IPV4__IINTFf) ||
  27034        SOC_MEM_FIELD_VALID(unit, mem, IPV6__IINTFf)) {
  27035         soc_mem_field32_set(unit, mem, entry_ptr, (mem == L3_TUNNEL_DOUBLEm) ? IPV4__IINTFf : IPV6__IINTFf, tnl_info->vlan);
  27036     }
  27037 
  27038      /* Set Tunnel class id for VFP match. */
  27039      bit_num = soc_mem_field_length(unit, mem, (mem == L3_TUNNEL_DOUBLEm) ? IPV4__TUNNEL_CLASS_IDf : IPV6__TUNNEL_CLASS_IDf);
  27040      if (bit_num) {
  27041          if ((tnl_info->tunnel_class < 0) ||
  27042              (tnl_info->tunnel_class > (( 1 << bit_num ) - 1))) {
  27043              return BCM_E_PARAM;
  27044          }
  27045          soc_mem_field32_set(unit, mem, entry_ptr,
  27046                   (mem == L3_TUNNEL_DOUBLEm) ? IPV4__TUNNEL_CLASS_IDf : IPV6__TUNNEL_CLASS_IDf,
  27047                   tnl_info->tunnel_class);
  27048      } else {
  27049          if (tnl_info->tunnel_class != 0) {
  27050              return BCM_E_PARAM;
  27051          }
  27052      }
  27053      return BCM_E_NONE;
  27054 }
  27055 #endif
  27056 
  27057 /*
  27058  * Function:
  27059  *      _bcm_xgs3_l3_tnl_term_add
  27060  * Purpose:
  27061  *      Add tunnel termination entry to the hw.
  27062  * Parameters:
  27063  *      unit     - (IN)SOC unit number.
  27064  *      tnl_info - (IN)Tunnel terminator parameters.
  27065  * Returns:
  27066  *      BCM_E_XXX
  27067  */
  27068 STATIC int
  27069 _bcm_xgs3_l3_tnl_term_add(int unit, bcm_tunnel_terminator_t *tnl_info)
  27070 {
  27071     soc_tunnel_term_t entry;        /* Buffer to writh to hw.     */
  27072     uint32 *entry_ptr;              /* Filled entry pointer.      */
  27073     int tmp_val;                    /* Temp value to check flags. */
  27074     uint32 index;                   /* HW index.                  */
  27075     int rv = BCM_E_NONE;            /* Operation return status.   */
  27076     int bit_num = 0;
  27077     soc_mem_t mem = L3_TUNNELm;
  27078 
  27079 
  27080 #if defined(BCM_TOMAHAWK3_SUPPORT)
  27081     if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
  27082         _bcm_tnl_term_type_t tnl_type;/* Tunnel type. */
  27083         mem = L3_TUNNEL_DOUBLEm;
  27084         if ((tnl_info->type == bcmTunnelTypeAutoMulticast) ||
  27085             (tnl_info->type == bcmTunnelTypeAutoMulticast6)) {
  27086              /* AMT tunnels not supported */
  27087              return BCM_E_UNAVAIL;
  27088         }
  27089 
  27090 
  27091         /* Get tunnel type & sub_type. */
  27092         BCM_IF_ERROR_RETURN
  27093             (_bcm_xgs3_l3_set_tnl_term_type(unit, tnl_info, &tnl_type));
  27094 
  27095         if (tnl_type.tnl_protocol == 0x11) {
  27096             /*UDP not supported */
  27097              return BCM_E_UNAVAIL;
  27098         }
  27099 
  27100         if (tnl_type.tnl_outer_hdr_ipv6 == 1) {
  27101             mem = L3_TUNNEL_QUADm;
  27102         }
  27103 
  27104         rv = _bcm_th3_l3_tnl_term_entry_init(unit, tnl_info, &entry);
  27105     } else
  27106 #endif
  27107     /* Initialize lookup key. */
  27108 #ifdef BCM_TRIUMPH2_SUPPORT
  27109     if (SOC_IS_TRIUMPH2(unit)  || SOC_IS_APOLLO(unit)    ||
  27110         SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit)   ||
  27111         SOC_IS_KATANAX(unit)   || SOC_IS_TRIDENT2X(unit) ||
  27112         SOC_IS_TOMAHAWKX(unit)  || SOC_IS_TRIDENT3X(unit)) {
  27113         rv = _bcm_tr2_l3_tnl_term_entry_init(unit, tnl_info, &entry);
  27114     } else
  27115 #endif /* BCM_TRIUMPH2_SUPPORT */
  27116 #if defined(BCM_TRIUMPH3_SUPPORT)
  27117     if (SOC_IS_TRIUMPH3(unit)) {
  27118         rv = _bcm_tr3_l3_tnl_term_entry_init(unit, tnl_info, &entry);
  27119     } else
  27120 #endif /* BCM_TRIUMPH3_SUPPORT */
  27121     {
  27122         rv =  _bcm_xgs3_l3_tnl_term_entry_init(unit, tnl_info, &entry);
  27123     }
  27124     BCM_IF_ERROR_RETURN(rv);
  27125 
  27126     entry_ptr = (uint32 *)&entry.entry_arr[0];
  27127 
  27128 
  27129     if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
  27130 #ifdef BCM_TOMAHAWK3_SUPPORT
  27131         BCM_IF_ERROR_RETURN(
  27132             _bcm_xgs3_l3_tnl_term_hash_entry_add(unit, tnl_info, entry_ptr));
  27133 #endif
  27134     } else {
  27135     /* Set flag to use outer header DSCP value or not. */
  27136     tmp_val = (tnl_info->flags & BCM_TUNNEL_TERM_USE_OUTER_DSCP) ? 1 : 0;
  27137         soc_mem_field32_set(unit, mem, entry_ptr, USE_OUTER_HDR_DSCPf, tmp_val);
  27138 
  27139     /* Set flag to use outer header TTL value or not. */
  27140     tmp_val = (tnl_info->flags & BCM_TUNNEL_TERM_USE_OUTER_TTL) ? 1 : 0;
  27141         soc_mem_field32_set(unit, mem, entry_ptr, USE_OUTER_HDR_TTLf, tmp_val);
  27142 
  27143     /* Set flag to preserve inner header DSCP value or not. */
  27144     tmp_val = (tnl_info->flags & BCM_TUNNEL_TERM_KEEP_INNER_DSCP) ? 1 : 0;
  27145         soc_mem_field32_set(unit, mem, entry_ptr,
  27146                                DONOT_CHANGE_INNER_HDR_DSCPf, tmp_val);
  27147 
  27148     /* Set l3 port bitmap. */
  27149         soc_mem_pbmp_field_set(unit, mem, entry_ptr, ALLOWED_PORT_BITMAPf,
  27150                            &tnl_info->pbmp);
  27151 
  27152     /* Sev vlan id for ipmc lookup.*/
  27153         if(SOC_MEM_FIELD_VALID(unit, mem, IINTFf)) {
  27154             soc_mem_field32_set(unit, mem, entry_ptr, IINTFf, tnl_info->vlan);
  27155     }
  27156 
  27157     /* Set profile index for default forwarding vlan.*/
  27158     if(SOC_MEM_FIELD_VALID(unit, mem, DEFAULT_VLAN_PROFILE_INDEXf)) {
  27159         soc_mem_field32_set(unit, mem, entry_ptr, DEFAULT_VLAN_PROFILE_INDEXf, tnl_info->fwd_vlan);
  27160     }
  27161 
  27162      /* Set Tunnel class id for VFP match. */
  27163     if (SOC_IS_SCORPION(unit)) {
  27164            bit_num = soc_mem_field_length(unit, mem, CLASS_IDf);
  27165         if (bit_num) {
  27166             if ((tnl_info->tunnel_class < 0) ||
  27167                 (tnl_info->tunnel_class > (( 1 << bit_num ) - 1))) {
  27168                 return BCM_E_PARAM;
  27169             }
  27170                soc_mem_field32_set(unit, mem, entry_ptr, CLASS_IDf,
  27171                                     tnl_info->tunnel_class);
  27172         }
  27173     } else {
  27174            bit_num = soc_mem_field_length(unit, mem, TUNNEL_CLASS_IDf);
  27175         if (bit_num) {
  27176             if ((tnl_info->tunnel_class < 0) ||
  27177                 (tnl_info->tunnel_class > (( 1 << bit_num ) - 1))) {
  27178                 return BCM_E_PARAM;
  27179             }
  27180                soc_mem_field32_set(unit, mem, entry_ptr, TUNNEL_CLASS_IDf,
  27181                                     tnl_info->tunnel_class);
  27182         } else {
  27183             if (tnl_info->tunnel_class != 0) {
  27184                 return BCM_E_PARAM;
  27185             }
  27186         }
  27187     }
  27188 
  27189 #ifdef BCM_FIREBOLT_SUPPORT
  27190     if (SOC_IS_FBX(unit)) {
  27191         if (soc_feature(unit, soc_feature_tunnel_dscp_trust)) {
  27192             if (tnl_info->flags & BCM_TUNNEL_TERM_DSCP_TRUST) {
  27193                     soc_mem_field32_set(unit, mem, entry_ptr, USE_TUNNEL_DSCPf, 1);
  27194             }
  27195         }
  27196     }
  27197 #endif /* BCM_FIREBOLT_SUPPORT */
  27198     }
  27199 
  27200 #ifdef BCM_TRIUMPH2_SUPPORT
  27201     if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) ||
  27202             SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) ||
  27203             SOC_IS_KATANAX(unit) || SOC_IS_TRIDENT2X(unit) ||
  27204             SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
  27205 #ifdef BCM_TOMAHAWK3_SUPPORT
  27206         if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
  27207             rv = _bcm_th3_l3_tnl_term_add(unit, entry_ptr, tnl_info);
  27208         } else
  27209 #endif
  27210         {
  27211             rv = _bcm_tr2_l3_tnl_term_add(unit, entry_ptr, tnl_info);
  27212         }
  27213         BCM_IF_ERROR_RETURN(rv);
  27214     }
  27215 #endif
  27216 
  27217 #if defined(BCM_TRIUMPH3_SUPPORT)
  27218     if (SOC_IS_TRIUMPH3(unit)) {
  27219         rv = _bcm_tr3_l3_tnl_term_add(unit, entry_ptr, tnl_info);
  27220         BCM_IF_ERROR_RETURN(rv);
  27221     }
  27222 #endif
  27223 
  27224     rv = soc_tunnel_term_insert(unit, &entry, &index);
  27225     return rv;
  27226 }
  27227 
  27228 /*
  27229  * Function:
  27230  *      _bcm_xgs3_l3_tnl_term_del
  27231  * Purpose:
  27232  *      Write a singe tunnel termination entry to the hw.
  27233  * Parameters:
  27234  *      unit     - (IN)SOC unit number.
  27235  *      tnl_info - (IN)Tunnel terminator parameters.
  27236  * Returns:
  27237  *      BCM_E_XXX
  27238  */
  27239 STATIC int
  27240 _bcm_xgs3_l3_tnl_term_del(int unit, bcm_tunnel_terminator_t *tnl_info)
  27241 {
  27242     soc_tunnel_term_t key;      /* Buffer to read entry from hw. */
  27243     int rv = BCM_E_NONE;        /* Operation return status.      */
  27244 #ifdef BCM_TOMAHAWK3_SUPPORT
  27245     soc_tunnel_term_t entry;
  27246     uint32 *entry_ptr;                 /* Filled entry pointer.      */
  27247     int index;
  27248     int prof_id;
  27249     soc_mem_t mem = L3_TUNNEL_DOUBLEm;
  27250 #endif
  27251     /* Initialize lookup key. */
  27252 #ifdef BCM_TRIUMPH2_SUPPORT
  27253     if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) ||
  27254             SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) ||
  27255             SOC_IS_KATANAX(unit) || SOC_IS_TRIDENT2X(unit) ||
  27256             SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
  27257 #ifdef BCM_TOMAHAWK3_SUPPORT
  27258         if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
  27259             rv = _bcm_th3_l3_tnl_term_entry_init(unit, tnl_info, &key);
  27260         } else
  27261 #endif
  27262         {
  27263             rv = _bcm_tr2_l3_tnl_term_entry_init(unit, tnl_info, &key);
  27264         }
  27265     } else
  27266 #endif /* BCM_TRIUMPH2_SUPPORT */
  27267 #if defined(BCM_TRIUMPH3_SUPPORT)
  27268     if (SOC_IS_TRIUMPH3(unit)) {
  27269         rv = _bcm_tr3_l3_tnl_term_entry_init(unit, tnl_info, &key);
  27270     } else
  27271 #endif /* BCM_TRIUMPH3_SUPPORT */
  27272     {
  27273         if (!soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
  27274             rv =  _bcm_xgs3_l3_tnl_term_entry_init(unit, tnl_info, &key);
  27275         }
  27276     }
  27277     BCM_IF_ERROR_RETURN(rv);
  27278 
  27279 #ifdef BCM_TOMAHAWK3_SUPPORT
  27280     if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
  27281         _bcm_tnl_term_type_t tnl_type;/* Tunnel type. */
  27282 
  27283         /* Get tunnel type & sub_type. */
  27284         BCM_IF_ERROR_RETURN
  27285             (_bcm_xgs3_l3_set_tnl_term_type(unit, tnl_info, &tnl_type));
  27286 
  27287         if (tnl_type.tnl_outer_hdr_ipv6 == 1) {
  27288             mem = L3_TUNNEL_QUADm;
  27289         }
  27290 
  27291         /* Find tunnel terminator in TCAM. */
  27292         rv = soc_tunnel_term_match(unit,&key, &entry, &index);
  27293         entry_ptr = (uint32 *)&entry.entry_arr[0];
  27294         if (BCM_SUCCESS(rv)) {
  27295             prof_id = soc_mem_field32_get(unit, mem, entry_ptr,
  27296                                          (mem == L3_TUNNEL_DOUBLEm) ?
  27297                                             IPV4__ALLOWED_PORT_BITMAP_PROFILE_PTRf:
  27298                                             IPV6__ALLOWED_PORT_BITMAP_PROFILE_PTRf);
  27299             soc_profile_mem_delete(unit, _bcm_get_tnl_port_bitmap_profile(unit), prof_id);
  27300         }
  27301     }
  27302 #endif
  27303 #ifdef BCM_TRIDENT3_SUPPORT
  27304     if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, DEFAULT_VLAN_PROFILE_INDEXf)) {
  27305         tunnel_default_vlan_profile_entry_t tunnel_default_vlan_profile_entry;
  27306         soc_tunnel_term_t entry;
  27307         uint32 *entry_ptr;
  27308         int index;
  27309 
  27310         rv = soc_tunnel_term_match(unit,&key, &entry, &index);
  27311         entry_ptr = (uint32 *)&entry.entry_arr[0];
  27312         if (BCM_SUCCESS(rv)) {
  27313             uint32 action_profile_idx;
  27314             uint32 vlan_profile_idx = soc_mem_field32_get(unit, L3_TUNNELm, entry_ptr,
  27315                                             DEFAULT_VLAN_PROFILE_INDEXf);
  27316             if (vlan_profile_idx) {
  27317                 BCM_IF_ERROR_RETURN(
  27318                     soc_mem_read(unit, L3_TUNNEL_DEFAULT_VLAN_PROFILEm, MEM_BLOCK_ANY,
  27319                             vlan_profile_idx, &tunnel_default_vlan_profile_entry));
  27320 
  27321                 action_profile_idx = soc_mem_field32_get(unit, L3_TUNNEL_DEFAULT_VLAN_PROFILEm,
  27322                                             (uint32 *) &tunnel_default_vlan_profile_entry,
  27323                                             TAG_ACTION_PROFILE_PTRf);
  27324 
  27325                 /* delete action profile */
  27326                 (void)(_bcm_trx_vlan_action_profile_entry_delete(unit, action_profile_idx));
  27327 
  27328                 /* delete vlan profile */
  27329                 soc_profile_mem_delete(unit, _bcm_td3_tunnel_default_vlan_profile[unit], vlan_profile_idx);
  27330             }
  27331         }
  27332     }
  27333 #endif
  27334     /* Find tunnel terminator in TCAM. */
  27335     return soc_tunnel_term_delete(unit, &key);
  27336 }
  27337 
  27338 /*
  27339  * Function:
  27340  *      _bcm_xgs3_l3_tnl_term_traverse
  27341  * Purpose:
  27342  *      Traverse L3 tunnel terminator entries.
  27343  * Parameters:
  27344  *      unit     - (IN)SOC unit number.
  27345  *      tnl_info - (IN)Tunnel terminator parameters.
  27346  * Returns:
  27347  *      BCM_E_XXX
  27348  */
  27349 STATIC int
  27350 _bcm_xgs3_l3_tnl_term_traverse(int unit,
  27351                                 bcm_tunnel_terminator_traverse_cb cb,
  27352                                 void *user_data)
  27353 {
  27354     int num_tnl, idx;
  27355     soc_tunnel_term_t entry;
  27356     int entry_type;
  27357     bcm_tunnel_terminator_t info;
  27358     int rv = BCM_E_NONE, width;
  27359     soc_mem_t mem = L3_TUNNELm;
  27360     soc_field_t valid_f = VALIDf;
  27361 
  27362     /*	Make sure module was initialized. */
  27363     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  27364         return (BCM_E_INIT);
  27365     }
  27366 
  27367     if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
  27368         mem = L3_TUNNEL_DOUBLEm;
  27369         valid_f = BASE_VALID_0f;
  27370     }
  27371     /* Get L3 tunnel terminator table size. */
  27372     num_tnl = soc_mem_index_count(unit, mem);
  27373 
  27374     for(idx = num_tnl - 1; idx >= 0; idx--) {
  27375         SOC_IF_ERROR_RETURN
  27376             (soc_mem_read(unit, mem, MEM_BLOCK_ANY, idx,
  27377                             (uint32 *)&entry.entry_arr[0]));
  27378 
  27379         if (!soc_mem_field32_get(unit, mem,
  27380                                 (uint32 *)&entry.entry_arr[0], valid_f)) {
  27381             continue;
  27382         }
  27383 
  27384 #if defined(BCM_TRX_SUPPORT)
  27385         /* Get tunnel termination type IPv4/IPv6 */
  27386         if (SOC_MEM_FIELD_VALID(unit, mem, MODEf)) {
  27387             entry_type = soc_mem_field32_get(unit, mem,
  27388                                             (uint32 *)&entry.entry_arr[0], MODEf);
  27389         } else if (SOC_MEM_FIELD_VALID(unit, mem, KEY_TYPEf)) {
  27390             entry_type = soc_mem_field32_get(unit, mem,
  27391                                             (uint32 *)&entry.entry_arr[0], KEY_TYPEf);
  27392         } else
  27393 #endif /* BCM_TRX_SUPPORT */
  27394         {
  27395           entry_type = 0; /* IPV4 default type */
  27396         }
  27397 
  27398         if (0x1 == entry_type) { /* IPV6 */
  27399             if (!soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
  27400             for (width = 1; width < SOC_TNL_TERM_IPV6_ENTRY_WIDTH; width++) {
  27401                 SOC_IF_ERROR_RETURN
  27402                     (READ_L3_TUNNELm(unit, MEM_BLOCK_ANY, (idx + width),
  27403                                     (uint32 *)&entry.entry_arr[width]));
  27404             }
  27405             /* Skip IPv6 entry */
  27406             idx += (SOC_TNL_TERM_IPV6_ENTRY_WIDTH - 1);
  27407         }
  27408         }
  27409 
  27410         /* tunnel terminator parse*/
  27411 #ifdef BCM_TOMAHAWK3_SUPPORT
  27412         if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
  27413             rv = _bcm_th3_l3_tnl_term_entry_parse(unit, &entry, &info);
  27414         } else
  27415 #endif
  27416 #ifdef BCM_TRIUMPH2_SUPPORT
  27417         if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) ||
  27418             SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) ||
  27419             SOC_IS_KATANAX(unit) || SOC_IS_TRIDENT2X(unit) ||
  27420             SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
  27421             rv = _bcm_tr2_l3_tnl_term_entry_parse(unit, &entry, &info);
  27422         } else
  27423 #endif
  27424 #if defined(BCM_TRIUMPH3_SUPPORT)
  27425         if (SOC_IS_TRIUMPH3(unit)) {
  27426             rv = _bcm_tr3_l3_tnl_term_entry_parse(unit, &entry, &info);
  27427         } else
  27428 #endif
  27429         {
  27430             rv = _bcm_xgs3_l3_tnl_term_entry_parse(unit, &entry, &info);
  27431         }
  27432 
  27433         /* Check read errors. */
  27434         if BCM_FAILURE(rv) {
  27435             break;
  27436         }
  27437 
  27438         if (cb) {
  27439             rv = (*cb) (unit, &info, user_data);
  27440 #ifdef BCM_CB_ABORT_ON_ERR
  27441             if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
  27442                 break;
  27443             }
  27444 #endif
  27445         }
  27446     }
  27447 
  27448     /* Reset last read status. */
  27449     if (BCM_E_NOT_FOUND == rv) {
  27450         rv = BCM_E_NONE;
  27451     }
  27452 
  27453     return rv;
  27454 }
  27455 
  27456 /*
  27457  * Function:
  27458  *      _bcm_xgs3_l3_tnl_init_get
  27459  * Purpose:
  27460  *      Get a tunnel initiator entry.
  27461  * Parameters:
  27462  *      unit     -(IN)SOC unit number.
  27463  *      idx      -(IN)Entry index to read.
  27464  *      tnl_info -(IN)Buffer to fill tunnel info.
  27465  * Returns:
  27466  *      BCM_E_XXX
  27467  */
  27468 STATIC int
  27469 _bcm_xgs3_l3_tnl_init_get(int unit, int idx,
  27470                           bcm_tunnel_initiator_t *tnl_info)
  27471 {
  27472     uint32 tnl_entry[SOC_MAX_MEM_WORDS]; /* Buffer to read hw entry.  */
  27473     soc_mem_t mem;                         /* Tunnel initiator table memory.*/
  27474     int df_val;                            /* Don't fragment encoded value. */
  27475     int rv;                                /* Operation return status.      */
  27476 #ifdef BCM_FIREBOLT_SUPPORT
  27477     int tnl_type;                          /* Tunnel type.                  */
  27478 #endif /* BCM_FIREBOLT_SUPPORT */
  27479     uint32 entry_type = BCM_XGS3_TUNNEL_INIT_V4;/* Entry type (IPv4/IPv6/MPLS)*/
  27480     soc_field_t field = 0;
  27481 
  27482     /* Get table memory. */
  27483     mem = BCM_XGS3_L3_MEM(unit, tnl_init_v4);
  27484 
  27485     rv = BCM_XGS3_MEM_READ(unit, mem, idx, tnl_entry);
  27486     BCM_IF_ERROR_RETURN(rv);
  27487 
  27488 
  27489     if (SOC_IS_TRIDENT3X(unit)) {
  27490         field = DATA_TYPEf;
  27491     } else {
  27492         field = ENTRY_TYPEf;
  27493     }
  27494 #if defined(BCM_TRX_SUPPORT)
  27495     if (SOC_MEM_FIELD_VALID(unit, mem, field)) {
  27496         /* Get entry_type. */
  27497         entry_type = soc_mem_field32_get(unit, mem, tnl_entry, field);
  27498 #ifdef BCM_TRIDENT3_SUPPORT
  27499         if (SOC_IS_TRIDENT3X(unit) &&
  27500             (entry_type == BCM_XGS3_TUNNEL_INIT_V6_TD3)) {
  27501             entry_type = BCM_XGS3_TUNNEL_INIT_V6;
  27502         }
  27503 #endif
  27504 
  27505         if (BCM_XGS3_TUNNEL_INIT_V6 == entry_type) {
  27506             mem = BCM_XGS3_L3_MEM(unit, tnl_init_v6);
  27507             idx >>= 1;    /* Each record takes two slots. */
  27508 
  27509             rv = BCM_XGS3_MEM_READ(unit, mem, idx, tnl_entry);
  27510             BCM_IF_ERROR_RETURN(rv);
  27511         } else if ((BCM_XGS3_TUNNEL_INIT_MPLS == entry_type)
  27512 #ifdef BCM_TRIDENT3_SUPPORT
  27513                    || (SOC_IS_TRIDENT3X(unit) &&
  27514                        (BCM_XGS3_TUNNEL_INIT_MPLS_TD3 == entry_type))
  27515 #endif /* BCM_TRIDENT3_SUPPORT */
  27516                    ) {
  27517              mem = BCM_XGS3_L3_MEM(unit, tnl_init_mpls);
  27518              if (soc_feature(unit, soc_feature_egr_ip_tnl_mpls_double_wide)) {
  27519                  idx >>= 1; /* Each record takes two slots. */
  27520              }
  27521              rv = BCM_XGS3_MEM_READ(unit, mem, idx, tnl_entry);
  27522              BCM_IF_ERROR_RETURN(rv);
  27523         }
  27524     }
  27525 #endif /* BCM_TRX_SUPPORT */
  27526 
  27527     /* Parse hw buffer. */
  27528     if (BCM_XGS3_TUNNEL_INIT_V4 == entry_type) {
  27529         /* Get destination ip. */
  27530         tnl_info->dip = soc_mem_field32_get(unit, mem, tnl_entry, DIPf);
  27531 
  27532         /* Get source ip. */
  27533         tnl_info->sip = soc_mem_field32_get(unit, mem, tnl_entry, SIPf);
  27534     } else if (BCM_XGS3_TUNNEL_INIT_V6 == entry_type) {
  27535         /* Get destination ip. */
  27536         soc_mem_ip6_addr_get(unit, mem, tnl_entry, DIPf, tnl_info->dip6,
  27537                              SOC_MEM_IP6_FULL_ADDR);
  27538 
  27539         /* Get source ip. */
  27540         soc_mem_ip6_addr_get(unit, mem, tnl_entry, SIPf, tnl_info->sip6,
  27541                              SOC_MEM_IP6_FULL_ADDR);
  27542     }
  27543 
  27544     if ((entry_type != BCM_XGS3_TUNNEL_INIT_MPLS)
  27545 #ifdef BCM_TRIDENT3_SUPPORT
  27546         && (entry_type != BCM_XGS3_TUNNEL_INIT_MPLS_TD3)
  27547 #endif /* BCM_TRIDENT3_SUPPORT  */
  27548         ) {
  27549         /* Tunnel header DSCP select. */
  27550         tnl_info->dscp_sel = soc_mem_field32_get(unit, mem, tnl_entry, DSCP_SELf);
  27551 
  27552         /* Tunnel header DSCP value. */
  27553         if (bcmTunnelDscpAssign == tnl_info->dscp_sel) {
  27554             tnl_info->dscp = soc_mem_field32_get(unit, mem, tnl_entry, DSCPf);
  27555         }
  27556 
  27557         /* Tunnel DSCP map */
  27558         if ((bcmTunnelDscpMap == tnl_info->dscp_sel) &&
  27559            SOC_MEM_FIELD_VALID(unit, mem, DSCP_MAPPING_PTRf)) {
  27560             tnl_info->dscp_map = soc_mem_field32_get(unit, mem, tnl_entry,
  27561                                                      DSCP_MAPPING_PTRf);
  27562         }
  27563     }
  27564 
  27565     if (SOC_MEM_FIELD_VALID(unit, mem, IPV4_DF_SELf)) {
  27566         /* IP tunnel hdr DF bit for IPv4 */
  27567         df_val = soc_mem_field32_get(unit, mem, tnl_entry, IPV4_DF_SELf);
  27568         if (0x2 <= df_val) {
  27569             tnl_info->flags |= BCM_TUNNEL_INIT_USE_INNER_DF;
  27570         } else if (0x1 == df_val) {
  27571             tnl_info->flags |= BCM_TUNNEL_INIT_IPV4_SET_DF;
  27572         }
  27573     }
  27574 
  27575     if (SOC_MEM_FIELD_VALID(unit, mem, IPV6_DF_SELf)) {
  27576         /* IP tunnel hdr DF bit for IPv6 */
  27577         if (soc_mem_field32_get(unit, mem, tnl_entry, IPV6_DF_SELf)) {
  27578             tnl_info->flags |= BCM_TUNNEL_INIT_IPV6_SET_DF;
  27579         }
  27580     }
  27581 
  27582 #ifdef BCM_FIREBOLT_SUPPORT
  27583     if(SOC_IS_FBX(unit)) {
  27584        if ((BCM_XGS3_TUNNEL_INIT_MPLS == entry_type)
  27585 #ifdef BCM_TRIDENT3_SUPPORT
  27586            || (SOC_IS_TRIDENT3X(unit) &&
  27587                (BCM_XGS3_TUNNEL_INIT_MPLS_TD3 == entry_type))
  27588 #endif /* BCM_TRIDENT3_SUPPORT */
  27589            ) {
  27590 
  27591            /* Get TTL. */
  27592 
  27593 #ifdef BCM_TRIDENT3_SUPPORT
  27594            if (SOC_IS_TRIDENT3X(unit)) {
  27595                int val = 0;
  27596                /*Get TTL from MPLS_ENTRY_0*/
  27597                bcm_td3_ip_tnl_mpls_label_info_get(unit, tnl_entry,
  27598                        bcmiMplsTtl, 0, &val);
  27599                tnl_info->ttl = val;
  27600            } else
  27601 #endif
  27602            {
  27603                tnl_info->ttl = soc_mem_field32_get(unit, mem, tnl_entry, MPLS_TTL_0f);
  27604            }
  27605            /* Get tunnel type. */
  27606            tnl_type = soc_mem_field32_get(unit, mem, tnl_entry, field);
  27607        } else {
  27608            /* Get TTL. */
  27609            if (SOC_MEM_FIELD_VALID(unit, mem, TTLf)) {
  27610            tnl_info->ttl = soc_mem_field32_get(unit, mem, tnl_entry, TTLf);
  27611            }
  27612 
  27613            /* Get tunnel type. */
  27614            tnl_type = soc_mem_field32_get(unit, mem, tnl_entry, TUNNEL_TYPEf);
  27615        }
  27616 
  27617         /* Translate hw tunnel type into API encoding. */
  27618         rv = _bcm_xgs3_tnl_hw_code_to_type(unit, tnl_type, entry_type,
  27619                                            &tnl_info->type);
  27620         BCM_IF_ERROR_RETURN(rv);
  27621 #if defined(BCM_TRX_SUPPORT)
  27622         if (SOC_MEM_FIELD_VALID(unit, mem, FLOW_LABELf)) {
  27623             tnl_info->flow_label = soc_mem_field32_get(unit, mem, tnl_entry,
  27624                                                        FLOW_LABELf);
  27625         }
  27626 #endif /* BCM_TRX_SUPPORT*/
  27627 
  27628        if (tnl_info->type != bcmTunnelTypeMpls) {
  27629            /* Get mac address. */
  27630            if (SOC_MEM_FIELD_VALID(unit, mem, DEST_ADDR_UPPERf)) {
  27631                soc_mem_mac_address_get(unit, mem, tnl_entry, DEST_ADDR_UPPERf,
  27632                        tnl_info->dmac, SOC_MEM_MAC_UPPER_ONLY);
  27633                soc_mem_mac_address_get(unit, mem, tnl_entry, DEST_ADDR_LOWERf,
  27634                        tnl_info->dmac, SOC_MEM_MAC_LOWER_ONLY);
  27635 
  27636            } else {
  27637                if (SOC_MEM_FIELD_VALID(unit, mem, DEST_ADDRf)) {
  27638                    soc_mem_mac_addr_get(unit, mem, tnl_entry,
  27639                                         DEST_ADDRf, tnl_info->dmac);
  27640                }
  27641            }
  27642        }
  27643     }
  27644 #if defined BCM_TRIUMPH2_SUPPORT
  27645     if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) ||
  27646             SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) ||
  27647             SOC_IS_TRIDENT2X(unit) || (!SOC_IS_TOMAHAWK3(unit) && SOC_IS_TOMAHAWKX(unit)) ||
  27648             SOC_IS_KATANAX(unit)) {
  27649         int val;
  27650         egr_fragment_id_table_entry_t entry;
  27651 
  27652         rv = bcm_esw_switch_control_get(unit, bcmSwitchTunnelIp4IdShared, &val);
  27653         BCM_IF_ERROR_RETURN(rv);
  27654         if (!val) {
  27655             rv = soc_mem_read(unit, EGR_FRAGMENT_ID_TABLEm, SOC_BLOCK_ANY,
  27656                               idx, &entry);
  27657             BCM_IF_ERROR_RETURN(rv);
  27658             tnl_info->ip4_id = soc_EGR_FRAGMENT_ID_TABLEm_field32_get
  27659                                    (unit, &entry, FRAGMENT_IDf);
  27660         } else {
  27661             return BCM_E_CONFIG;
  27662         }
  27663     }
  27664 #endif
  27665 #ifdef BCM_TRIDENT2_SUPPORT
  27666     if (SOC_MEM_FIELD_VALID(unit, mem, L4_DEST_PORTf)) {
  27667         tnl_info->udp_dst_port =
  27668             soc_mem_field32_get(unit, mem, tnl_entry, L4_DEST_PORTf);
  27669     }
  27670 #endif /* BCM_TRIDENT2_SUPPORT */
  27671 
  27672 #ifdef BCM_GREYHOUND2_SUPPORT
  27673     if (SOC_MEM_FIELD_VALID(unit, mem, L4_DST_PORTf)) {
  27674         tnl_info->udp_dst_port =
  27675             soc_mem_field32_get(unit, mem, tnl_entry, L4_DST_PORTf);
  27676     }
  27677 #endif /* BCM_GREYHOUND2_SUPPORT */
  27678 #endif /* BCM_FIREBOLT_SUPPORT */
  27679 
  27680 #ifdef BCM_MONTEREY_SUPPORT
  27681     if (SOC_MEM_FIELD_VALID(unit, mem, L4_SRC_PORTf)) {
  27682         tnl_info->udp_src_port =
  27683             soc_mem_field32_get(unit, mem, tnl_entry, L4_SRC_PORTf);
  27684     }
  27685 #endif /* BCM_MONTEREY_SUPPORT */
  27686 
  27687     return (BCM_E_NONE);
  27688 }
  27689 
  27690 /*
  27691  * Function:
  27692  *      _bcm_xgs3_l3_tnl_init_add
  27693  * Purpose:
  27694  *      Add tunnel initiator entry to hw.
  27695  * Parameters:
  27696  *      unit     - (IN)SOC unit number.
  27697  *      idx      - (IN)Index to insert tunnel initiator index.
  27698  *      buf      - (IN)Tunnel initiator entry info.
  27699  * Returns:
  27700  *      BCM_E_XXX
  27701  */
  27702 STATIC int
  27703 _bcm_xgs3_l3_tnl_init_add(int unit, int idx, void *buf, void *info)
  27704 {
  27705     uint32 tnl_entry[SOC_MAX_MEM_WORDS]; /* Buffer to write hw entry.*/
  27706     bcm_tunnel_initiator_t *tnl_info;     /* Tunnel initiator structure.   */
  27707     soc_mem_t mem;                        /* Tunnel initiator table memory.*/
  27708     int df_val;                           /* Don't fragment encoding.      */
  27709     int ipv6;                             /* IPv6 tunnel initiator.        */
  27710 #ifdef BCM_FIREBOLT_SUPPORT
  27711     int entry_type = 0;                   /* HW entry type IPv4/IPv6/MPLS  */
  27712     int hw_type_code = 0;                 /* Tunnel type.                  */
  27713 #endif /* BCM_FIREBOLT_SUPPORT */
  27714 #if defined(BCM_TRX_SUPPORT)
  27715     soc_field_t field = 0;
  27716     if (SOC_IS_TRIDENT3X(unit)) {
  27717         field = DATA_TYPEf;
  27718     } else {
  27719         field = ENTRY_TYPEf;
  27720     }
  27721 #endif
  27722 
  27723     /* Input parameters check. */
  27724     if (NULL == buf) {
  27725         return (BCM_E_PARAM);
  27726     }
  27727 
  27728     /* Read buffer from hw. */
  27729     tnl_info = (bcm_tunnel_initiator_t *) buf;
  27730 
  27731     ipv6 = _BCM_TUNNEL_OUTER_HEADER_IPV6(tnl_info->type);
  27732 
  27733     /* Get table memory. */
  27734     if (ipv6) {
  27735         idx >>= 1;
  27736         mem = BCM_XGS3_L3_MEM(unit, tnl_init_v6);
  27737     } else {
  27738         mem =  BCM_XGS3_L3_MEM(unit, tnl_init_v4);
  27739     }
  27740 
  27741     if (!SOC_MEM_IS_VALID(unit, mem)) {
  27742         return (BCM_E_UNAVAIL);
  27743     }
  27744 
  27745     /* Zero write buffer. */
  27746     sal_memset(tnl_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, tnl_init_v6));
  27747 
  27748     if (ipv6) {
  27749         /* Set destination ipv6 address. */
  27750         soc_mem_ip6_addr_set(unit, mem, tnl_entry, DIPf, tnl_info->dip6,
  27751                              SOC_MEM_IP6_FULL_ADDR);
  27752 
  27753         /* Set source ipv6 address. */
  27754         soc_mem_ip6_addr_set(unit, mem, tnl_entry, SIPf, tnl_info->sip6,
  27755                              SOC_MEM_IP6_FULL_ADDR);
  27756     } else {
  27757         /* Set destination address. */
  27758         soc_mem_field_set(unit, mem, tnl_entry, DIPf, (uint32 *)&tnl_info->dip);
  27759 
  27760         /* Set source address. */
  27761         soc_mem_field_set(unit, mem, tnl_entry, SIPf, (uint32 *)&tnl_info->sip);
  27762     }
  27763 
  27764     if ((!ipv6) && SOC_MEM_FIELD_VALID(unit, mem, IPV4_DF_SELf)) {
  27765         /* Outer IPv4 tunnel hdr DF bit for Inner IPv4 hdr. */
  27766         df_val = 0;
  27767         if (tnl_info->flags & BCM_TUNNEL_INIT_USE_INNER_DF) {
  27768             df_val |= 0x2;
  27769         } else if (tnl_info->flags & BCM_TUNNEL_INIT_IPV4_SET_DF) {
  27770             df_val |= 0x1;
  27771         }
  27772         soc_mem_field32_set(unit, mem, tnl_entry, IPV4_DF_SELf, df_val);
  27773     }
  27774 
  27775     if ((!ipv6) && SOC_MEM_FIELD_VALID(unit, mem, IPV6_DF_SELf)) {
  27776         /* Outer IPv4 tunnel hdr DF bit for Inner IPv6 hdr. */
  27777         df_val = (tnl_info->flags & BCM_TUNNEL_INIT_IPV6_SET_DF) ? 0x1 : 0;
  27778         soc_mem_field32_set(unit, mem, tnl_entry, IPV6_DF_SELf, df_val);
  27779     }
  27780 
  27781     /* Set DSCP value.  */
  27782     if (SOC_MEM_FIELD_VALID(unit, mem, DSCPf)) {
  27783     soc_mem_field32_set(unit, mem, tnl_entry, DSCPf, tnl_info->dscp);
  27784     }
  27785 
  27786     /* Tunnel header DSCP select. */
  27787     soc_mem_field32_set(unit, mem, tnl_entry, DSCP_SELf, tnl_info->dscp_sel);
  27788 
  27789     /* DSCP map */
  27790     if ((bcmTunnelDscpMap == tnl_info->dscp_sel) &&
  27791        (SOC_MEM_FIELD_VALID(unit, mem, DSCP_MAPPING_PTRf))) {
  27792         soc_mem_field32_set(unit, mem, tnl_entry, DSCP_MAPPING_PTRf,
  27793                             tnl_info->dscp_map);
  27794     }
  27795 
  27796 #if defined(BCM_FIREBOLT_SUPPORT)
  27797     if(SOC_IS_FBX(unit)) {
  27798         /* Set TTL. */
  27799         if (SOC_MEM_FIELD_VALID(unit, mem, TTLf)) {
  27800         soc_mem_field32_set(unit, mem, tnl_entry, TTLf, tnl_info->ttl);
  27801         }
  27802 
  27803         /* Set tunnel type. */
  27804         BCM_IF_ERROR_RETURN (_bcm_xgs3_tnl_type_to_hw_code(unit, tnl_info->type,
  27805                                                            &hw_type_code,
  27806                                                            &entry_type));
  27807 
  27808         soc_mem_field32_set(unit, mem, tnl_entry, TUNNEL_TYPEf, hw_type_code);
  27809 
  27810 #if defined(BCM_TRX_SUPPORT)
  27811         /* Set flow label. */
  27812         if (ipv6 && SOC_MEM_FIELD_VALID(unit, mem, FLOW_LABELf)) {
  27813             soc_mem_field32_set(unit, mem, tnl_entry, FLOW_LABELf,
  27814                                 tnl_info->flow_label);
  27815         }
  27816 
  27817         /* Set entry type. */
  27818         if (SOC_MEM_FIELD_VALID(unit, mem, field)) {
  27819             soc_mem_field32_set(unit, mem, tnl_entry, field, entry_type);
  27820         }
  27821 #endif /* BCM_TRX_SUPPORT */
  27822 
  27823         /* Set destination mac address. */
  27824         if (SOC_MEM_FIELD_VALID(unit, mem, DEST_ADDRf)) {
  27825             soc_mem_mac_addr_set(unit, mem, &tnl_entry, DEST_ADDRf, tnl_info->dmac);
  27826         }
  27827 #if defined (BCM_SCORPION_SUPPORT)
  27828         /* Set lower portion of destination mac address. */
  27829         if (SOC_MEM_FIELD_VALID(unit, mem, DEST_ADDR_LOWERf)) {
  27830             soc_mem_mac_address_set(unit, mem, &tnl_entry, DEST_ADDR_LOWERf,
  27831                                     tnl_info->dmac, SOC_MEM_MAC_LOWER_ONLY);
  27832         }
  27833 
  27834         /* Set upper portion of destination mac address. */
  27835         if (SOC_MEM_FIELD_VALID(unit, mem, DEST_ADDR_UPPERf)) {
  27836             soc_mem_mac_address_set(unit, mem, &tnl_entry, DEST_ADDR_UPPERf,
  27837                                     tnl_info->dmac, SOC_MEM_MAC_UPPER_ONLY);
  27838         }
  27839 #endif /* BCM_SCORPION_SUPPORT */
  27840     }
  27841 #if defined(BCM_TRIUMPH2_SUPPORT)
  27842     
  27843     /* Program the IPv4 ID if not using global ID space */
  27844     if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) ||
  27845             SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) ||
  27846             SOC_IS_TRIDENT2X(unit) || (SOC_IS_TOMAHAWKX(unit) && !SOC_IS_TOMAHAWK3(unit)) ||
  27847             SOC_IS_KATANAX(unit)) {
  27848         int val;
  27849         uint16 random;
  27850         egr_fragment_id_table_entry_t entry;
  27851         BCM_IF_ERROR_RETURN
  27852             (bcm_esw_switch_control_get(unit, bcmSwitchTunnelIp4IdShared, &val));
  27853         if (!val) {
  27854             sal_memset(&entry, 0, sizeof(egr_fragment_id_table_entry_t));
  27855             if (tnl_info->flags & BCM_TUNNEL_INIT_IP4_ID_SET_FIXED) {
  27856                 soc_EGR_FRAGMENT_ID_TABLEm_field32_set(unit, &entry,
  27857                                                        FRAGMENT_IDf,
  27858                                                        tnl_info->ip4_id);
  27859             } else if (tnl_info->flags & BCM_TUNNEL_INIT_IP4_ID_SET_RANDOM) {
  27860                 random = (uint16) (sal_time_usecs() & 0xFFFF);
  27861                 soc_EGR_FRAGMENT_ID_TABLEm_field32_set(unit, &entry,
  27862                                                        FRAGMENT_IDf,
  27863                                                        random);
  27864             } else {
  27865                 /* Default is random */
  27866                 random = (uint16) (sal_time_usecs() & 0xFFFF);
  27867                 soc_EGR_FRAGMENT_ID_TABLEm_field32_set(unit, &entry,
  27868                                                        FRAGMENT_IDf,
  27869                                                        random);
  27870             }
  27871             BCM_IF_ERROR_RETURN
  27872                 (soc_mem_write(unit, EGR_FRAGMENT_ID_TABLEm, SOC_BLOCK_ALL,
  27873                                idx, &entry));
  27874         } else {
  27875             return BCM_E_CONFIG;
  27876         }
  27877     }
  27878 #endif
  27879 #endif /* BCM_FIREBOLT_SUPPORT */
  27880 
  27881 #ifdef BCM_MONTEREY_SUPPORT
  27882     if ((tnl_info->type == bcmTunnelTypeRoeIn4) ||
  27883         (tnl_info->type == bcmTunnelTypeRoeIn6)) {
  27884         soc_mem_field32_set(unit, mem, tnl_entry, L4_SRC_PORTf,
  27885                                         tnl_info->udp_src_port);
  27886         soc_mem_field32_set(unit, mem, tnl_entry, L4_DEST_PORTf,
  27887                                         tnl_info->udp_dst_port);
  27888     }
  27889 #endif /* BCM_MONTEREY_SUPPORT */
  27890 
  27891     /* Write buffer to hw. */
  27892     return BCM_XGS3_MEM_WRITE(unit, mem, idx, tnl_entry);
  27893 }
  27894 
  27895 /*
  27896  * Function:
  27897  *      _bcm_xgs3_l3_tnl_init_del
  27898  * Purpose:
  27899  *      Delete tunnel initiator entry from hw.
  27900  * Parameters:
  27901  *      unit     - (IN)SOC unit number.
  27902  *      idx      - (IN)Index to insert tunnel initiator index.
  27903  * Returns:
  27904  *      BCM_E_XXX
  27905  */
  27906 STATIC int
  27907 _bcm_xgs3_l3_tnl_init_del(int unit, int idx, void *info)
  27908 {
  27909     uint32 tnl_entry[SOC_MAX_MEM_WORDS];  /* Buffer to write hw entry.  */
  27910     soc_mem_t mem;                              /* Tunnel initiator memory.   */
  27911 #if defined(BCM_TRX_SUPPORT)
  27912     uint32 entry_type = BCM_XGS3_TUNNEL_INIT_V4;/* Entry type (IPv4/IPv6/MPLS)*/
  27913     int field = 0;
  27914 
  27915     if (SOC_IS_TRIDENT3X(unit)) {
  27916         field = DATA_TYPEf;
  27917     } else {
  27918         field = ENTRY_TYPEf;
  27919     }
  27920 #endif /* BCM_TRX_SUPPORT*/
  27921 
  27922     /* Get table memory. */
  27923     mem = BCM_XGS3_L3_MEM(unit, tnl_init_v4);
  27924 
  27925 #if defined(BCM_TRX_SUPPORT)
  27926     if (SOC_MEM_FIELD_VALID(unit, mem, field)) {
  27927         /* Parse hw buffer. */
  27928         BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, tnl_entry));
  27929 
  27930         /* Get entry_type. */
  27931         entry_type = soc_mem_field32_get(unit, mem, tnl_entry, field);
  27932 
  27933         if (BCM_XGS3_TUNNEL_INIT_V6 == entry_type) {
  27934             mem = BCM_XGS3_L3_MEM(unit, tnl_init_v6);
  27935             idx >>= 1;    /* Each record takes two slots. */
  27936         } else if ((BCM_XGS3_TUNNEL_INIT_MPLS == entry_type)
  27937 #ifdef BCM_TRIDENT3_SUPPORT
  27938                    || (SOC_IS_TRIDENT3(unit) &&
  27939                        (BCM_XGS3_TUNNEL_INIT_MPLS_TD3 == entry_type))
  27940 #endif /* BCM_TRIDENT3_SUPPORT */
  27941                    ) {
  27942             mem = BCM_XGS3_L3_MEM(unit, tnl_init_mpls);
  27943             if ((soc_feature(unit, soc_feature_egr_ip_tnl_mpls_double_wide))
  27944                 || (soc_feature(unit, soc_feature_th3_style_simple_mpls))) {
  27945                 idx >>=1;
  27946             }
  27947         }
  27948     }
  27949 #endif /* BCM_TRX_SUPPORT */
  27950     /* Zero write buffer. */
  27951     sal_memset(&tnl_entry, 0, SOC_MAX_MEM_WORDS * sizeof(uint32));
  27952 
  27953     /* Write buffer to hw. */
  27954     return BCM_XGS3_MEM_WRITE(unit, mem, idx, &tnl_entry);
  27955 }
  27956 
  27957 
  27958 /*
  27959  * Function:
  27960  *      _bcm_xgs3_l3_tnl_dscp_get
  27961  * Purpose:
  27962  *      Get a tunnel dscp entry.
  27963  * Parameters:
  27964  *      unit     -(IN)SOC unit number.
  27965  *      idx      -(IN)Entry index to read.
  27966  *      tnl_info -(IN)Buffer to fill tunnel info.
  27967  * Returns:
  27968  *      BCM_E_XXX
  27969  */
  27970 STATIC int
  27971 _bcm_xgs3_l3_tnl_dscp_get(int unit, int idx,
  27972                           bcm_tunnel_dscp_map_t *tnl_info)
  27973 {
  27974    soc_mem_t mem;                             /* Tunnel dscp table memory.*/
  27975    uint32 tnl_entry[SOC_MAX_MEM_WORDS]; /* Buffer to read hw entry. */
  27976    soc_field_t fld;                           /* DSCP field index.        */
  27977 
  27978     /* Get table memory. */
  27979     mem = BCM_XGS3_L3_MEM(unit, tnl_dscp);
  27980 
  27981     /* Read buffer from hw. */
  27982     BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, tnl_entry));
  27983 
  27984     /* Get dscp field id based on unit type. */
  27985 #if defined(BCM_FIREBOLT_SUPPORT)
  27986     if (SOC_IS_TRIDENT3X(unit)) {
  27987         fld = QOSf;
  27988     } else if (SOC_IS_FBX(unit)) {
  27989         fld = DSCPf;
  27990     } else
  27991 #endif /* BCM_FIREBOLT_SUPPORT */
  27992     {
  27993         return (BCM_E_UNAVAIL);
  27994     }
  27995 
  27996     /* Parse hw buffer. */
  27997     tnl_info->dscp = soc_mem_field32_get(unit, mem, tnl_entry, fld);
  27998 
  27999     return (BCM_E_NONE);
  28000 }
  28001 
  28002 /*
  28003  * Function:
  28004  *      _bcm_xgs3_l3_tnl_dscp_add
  28005  * Purpose:
  28006  *      Add tunnel dscp entry to hw.
  28007  * Parameters:
  28008  *      unit     - (IN)SOC unit number.
  28009  *      idx      - (IN)Index to insert tunnel initiator index.
  28010  *      buf      - (IN)Tunnel dscp entry info.
  28011  * Returns:
  28012  *      BCM_E_XXX
  28013  */
  28014 STATIC int
  28015 _bcm_xgs3_l3_tnl_dscp_set(int unit, int idx, void *buf)
  28016 {
  28017     soc_mem_t mem;                      /* Tunnel dscp table memory.*/
  28018     bcm_tunnel_dscp_map_t *tnl_info;    /* Tunnel dscp information. */
  28019 
  28020     /* Input parameters check. */
  28021     if (NULL == buf) {
  28022         return (BCM_E_PARAM);
  28023     }
  28024 
  28025     /* Get table memory. */
  28026     mem = BCM_XGS3_L3_MEM(unit, tnl_dscp);
  28027 
  28028     tnl_info = (bcm_tunnel_dscp_map_t *) buf;
  28029 
  28030 #ifdef BCM_FIREBOLT_SUPPORT
  28031     if(SOC_IS_FBX(unit)) {
  28032         soc_field_t fld;
  28033         uint32 buf_p[SOC_MAX_MEM_WORDS];   /* HW buffer address.       */
  28034 
  28035         /* Zero write buffer. */
  28036         sal_memset(buf_p, 0, sizeof(buf_p));
  28037 
  28038         if (SOC_IS_TRIDENT3X(unit)) {
  28039             fld = QOSf;
  28040         } else {
  28041             fld = DSCPf;
  28042         }
  28043         soc_mem_field32_set(unit, mem, buf_p, fld, tnl_info->dscp);
  28044 
  28045         /* Write buffer to hw. */
  28046         return BCM_XGS3_MEM_WRITE(unit, mem, idx, buf_p);
  28047     }
  28048 #endif /* BCM_FIREBOLT_SUPPORT */
  28049 
  28050     return (BCM_E_NONE);
  28051 }
  28052 
  28053 /*
  28054  * Function:
  28055  *      _bcm_xgs3_l3_default_mtu_set
  28056  * Purpose:
  28057  *      Set default L3 MTU.
  28058  * Parameters:
  28059  *      unit     - (IN)SOC unit number.
  28060  * Returns:
  28061  *      BCM_E_XXX
  28062  */
  28063 STATIC int
  28064 _bcm_xgs3_l3_default_mtu_set(int unit)
  28065 {
  28066     uint8 *l3_mtu_val_buf = NULL;
  28067     mtu_values_entry_t *l3_mtu_entry = NULL;
  28068     int rv, idx, idx_min, idx_max;
  28069     int max_mtu = 0;
  28070 
  28071     /* l3_mtu_values table*/
  28072     l3_mtu_val_buf = soc_cm_salloc(unit,
  28073             SOC_MEM_TABLE_BYTES(unit,L3_MTU_VALUESm),
  28074             "l3_mtu_values");
  28075 
  28076     if (l3_mtu_val_buf == NULL) {
  28077         return BCM_E_MEMORY;
  28078     }
  28079 
  28080     idx_min = soc_mem_index_min(unit, L3_MTU_VALUESm);
  28081     idx_max = soc_mem_index_max(unit, L3_MTU_VALUESm);
  28082     rv = soc_mem_read_range(unit, L3_MTU_VALUESm,
  28083             MEM_BLOCK_ANY, idx_min, idx_max,
  28084             l3_mtu_val_buf);
  28085 
  28086     if (BCM_FAILURE(rv)) {
  28087         soc_cm_sfree(unit, l3_mtu_val_buf);
  28088         return rv;
  28089     }
  28090 
  28091     max_mtu = (1 << soc_mem_field_length(unit, L3_MTU_VALUESm, MTU_SIZEf)) - 1;
  28092     for (idx = idx_min; idx<= idx_max; idx++) {
  28093         l3_mtu_entry =
  28094             soc_mem_table_idx_to_pointer(unit, L3_MTU_VALUESm,
  28095                     mtu_values_entry_t *,
  28096                     l3_mtu_val_buf,
  28097                     idx);
  28098 
  28099         soc_L3_MTU_VALUESm_field32_set(unit,
  28100                 l3_mtu_entry,
  28101                 MTU_SIZEf, max_mtu);
  28102     }
  28103 
  28104     rv = soc_mem_write_range(unit, L3_MTU_VALUESm, MEM_BLOCK_ALL,
  28105             idx_min, idx_max, l3_mtu_val_buf);
  28106 
  28107     if (BCM_FAILURE(rv)) {
  28108         soc_cm_sfree(unit, l3_mtu_val_buf);
  28109         return rv;
  28110     }
  28111 
  28112     soc_cm_sfree(unit, l3_mtu_val_buf);
  28113     return BCM_E_NONE;
  28114 }
  28115 
  28116 /*
  28117  * Function:
  28118  *      _bcm_xgs3_l3_clear_all
  28119  * Purpose:
  28120  *      Flush all l3 tables on the chip
  28121  * Parameters:
  28122  *      unit      - (IN)SOC unit number.
  28123  * Returns:
  28124  *      BCM_E_XXX
  28125  */
  28126 STATIC int
  28127 _bcm_xgs3_l3_clear_all(int unit)
  28128 {
  28129     if (SOC_WARM_BOOT(unit)) {
  28130         return BCM_E_NONE;
  28131     }
  28132 #if defined(BCM_TRIUMPH_SUPPORT)
  28133     if (SOC_MEM_IS_VALID(unit, L3_MTU_VALUESm)) {
  28134         /* reset L3 mtu values. */
  28135         _bcm_xgs3_l3_default_mtu_set(unit);
  28136     }
  28137 #endif /* BCM_TRIUMPH_SUPPORT */
  28138 #ifdef BCM_TRIDENT2PLUS_SUPPORT 
  28139         if (soc_feature(unit, soc_feature_egr_modport_to_nhi)) {
  28140             BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_CLEAR(unit,EGR_DGPP_TO_NHI_MODBASEm));
  28141             BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_CLEAR(unit,EGR_DGPP_TO_NHIm));   
  28142         }
  28143 #endif  
  28144     /*
  28145      * Enabling clear all for TD2+ on bcmsim
  28146      */
  28147     if (((SAL_BOOT_BCMSIM || SAL_BOOT_XGSSIM) && !SOC_IS_TRIDENT2PLUS(unit) &&
  28148           !SOC_IS_TOMAHAWK3(unit) && !SOC_IS_TOMAHAWK2(unit) && !SOC_IS_APACHE(unit))
  28149           || SAL_BOOT_QUICKTURN)  {
  28150         return BCM_E_NONE;
  28151     }
  28152     /* Clear next hop table. */
  28153     BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, intf)));
  28154 
  28155     /* Clear next hop table. */
  28156     BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, nh)));
  28157 
  28158     /* Clear L3 ipv4 table. */
  28159     BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, v4)));
  28160 
  28161     /* Clear L3 ipv6 table. */
  28162     BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, v6)));
  28163 
  28164     /* Clear tunnel terminator table. */
  28165     BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit,
  28166                                                                     tnl_term)));
  28167 
  28168     /* Clear IPv4 tunnel initiator table. */
  28169     BCM_IF_ERROR_RETURN
  28170         (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, tnl_init_v4)));
  28171 
  28172     /* Clear MPLS tunnel initiator table. */
  28173     BCM_IF_ERROR_RETURN
  28174         (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, tnl_init_mpls)));
  28175 
  28176     /* Clear IPv6 tunnel initiator table. */
  28177     BCM_IF_ERROR_RETURN
  28178         (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, tnl_init_v6)));
  28179     /* Clear tunnel dscp table. */
  28180     BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit,
  28181                                                                     tnl_dscp)));
  28182 
  28183     /* Clear ECMP groups table. */
  28184     BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit,
  28185                                                                     ecmp)));
  28186 
  28187     /* Clear route table. */
  28188     BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit,
  28189                                                                     defip)));
  28190     if (SOC_MEM_IS_VALID(unit, L3_DEFIP_128m)) {
  28191         BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, L3_DEFIP_128m));
  28192     }
  28193 
  28194     if (SOC_MEM_IS_VALID(unit, L3_DEFIP_PAIR_128m)) {
  28195         BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, L3_DEFIP_PAIR_128m));
  28196     }
  28197 
  28198     if (SOC_MEM_IS_VALID(unit, L3_DEFIP_ALPM_IPV4m)) {
  28199         BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, L3_DEFIP_ALPM_IPV4m));
  28200     }
  28201 
  28202     if (SOC_MEM_IS_VALID(unit, L3_DEFIP_AUX_TABLEm)) {
  28203         BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, L3_DEFIP_AUX_TABLEm));
  28204     }
  28205 
  28206     /* Clear IPv6 prefix map table. */
  28207     BCM_IF_ERROR_RETURN
  28208         (BCM_XGS3_MEM_CLEAR (unit, BCM_XGS3_L3_MEM (unit, v6_prefix_map)));
  28209 
  28210 #if defined(BCM_FIREBOLT_SUPPORT)
  28211     if (SOC_IS_FBX(unit)) {
  28212         /* Clear egress next hop table. */
  28213         BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, EGR_L3_NEXT_HOPm));
  28214 
  28215 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \
  28216         defined(BCM_TRX_SUPPORT)
  28217         /* Clear initial ecmp groups table. */
  28218         BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, INITIAL_L3_ECMPm));
  28219 
  28220         /* Clear initial ingress next hop table. */
  28221         BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit,
  28222                                                  INITIAL_ING_L3_NEXT_HOPm));
  28223 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */
  28224     }
  28225 #endif /* BCM_FIREBOLT_SUPPORT */
  28226 
  28227 #if defined(BCM_TRX_SUPPORT)
  28228     if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) {
  28229         /* Clear ecmp groups count table. */
  28230         BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, L3_ECMP_COUNTm));
  28231     }
  28232 
  28233     if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMP_COUNTm)) {
  28234         /* Clear initial ecmp groups count table. */
  28235         BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, INITIAL_L3_ECMP_COUNTm));
  28236     }
  28237 
  28238     if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMP_GROUPm)) {
  28239         /* Clear initial ecmp groups count table. */
  28240         BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, INITIAL_L3_ECMP_GROUPm));
  28241     }
  28242 
  28243     if (SOC_MEM_IS_VALID(unit, INITIAL_L3_ECMPm)) {
  28244         /* Clear initial ecmp groups count table. */
  28245         BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, INITIAL_L3_ECMPm));
  28246     }
  28247 #endif  /* BCM_TRX_SUPPORT */
  28248 
  28249 #if defined(BCM_TRIUMPH_SUPPORT)
  28250     if (SOC_MEM_IS_VALID(unit, L3_IIFm)) {
  28251         /* Clear initial ecmp groups count table. */
  28252         BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, L3_IIFm));
  28253     }
  28254 
  28255     if (!SOC_IS_TRIUMPH3(unit)) {
  28256         /* Skip clearing ESM route tables for TR3 as it results in
  28257          * marking the entry as valid */
  28258         if (soc_feature(unit, soc_feature_esm_support)) {
  28259             if (SOC_MEM_IS_VALID(unit, EXT_IPV4_DEFIPm)) {
  28260                 /* Clear External V4 table. */
  28261                 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, EXT_IPV4_DEFIPm));
  28262             }
  28263 
  28264             if (SOC_MEM_IS_VALID(unit, EXT_IPV6_64_DEFIPm)) {
  28265                 /* Clear External V6 upper 64 table. */
  28266                 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, EXT_IPV6_64_DEFIPm));
  28267             }
  28268 
  28269             if (SOC_MEM_IS_VALID(unit, EXT_IPV6_128_DEFIPm)) {
  28270                 /* Clear External V6 full prefix length table. */
  28271                 BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, EXT_IPV6_128_DEFIPm));
  28272             }
  28273         }
  28274     }
  28275 #endif /* BCM_TRIUMPH_SUPPORT */
  28276 
  28277 #ifdef BCM_TRIUMPH2_SUPPORT
  28278     if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) ||
  28279            SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) ||
  28280            SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) ||
  28281            SOC_IS_KATANAX(unit)) {
  28282         /* Clear VRF counter index table. */
  28283         BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_CLEAR (unit, VRFm));
  28284     }
  28285 #endif /* BCM_TRIUMPH2_SUPPORT */
  28286 
  28287     return (BCM_E_NONE);
  28288 }
  28289 
  28290 
  28291 /*
  28292  * Function:
  28293  *      _bcm_xgs3_l3_intf_get
  28294  * Purpose:
  28295  *      Get an entry from L3 interface table.
  28296  * Parameters:
  28297  *      unit      - (IN)SOC unit number.
  28298  *      intf_info - (IN/OUT)Pointer to memory for interface information.
  28299  * Returns:
  28300  *      BCM_E_XXX
  28301  */
  28302 STATIC int
  28303 _bcm_xgs3_l3_intf_get(int unit, _bcm_l3_intf_cfg_t *intf_info)
  28304 {
  28305     l3_max_entry_t l3_if_entry;    /* Buffer to read interface info. */
  28306     _bcm_l3_intf_fields_t *fld;    /* Interface table common fields. */
  28307     uint32  *l3_if_entry_p;        /* Interface read buffer address. */
  28308     soc_mem_t mem;                 /* Interface table memory.        */
  28309 #ifdef BCM_TRIDENT3_SUPPORT
  28310     uint8 ent_type=0;
  28311 #endif
  28312 #ifdef BCM_RIOT_SUPPORT
  28313     egr_mac_da_profile_entry_t macda;
  28314     int svp = -1;
  28315     int profiled_mac = 0;
  28316     int macda_index = -1;
  28317 #endif
  28318 
  28319     /* Input parameters check */
  28320     if (NULL == intf_info) {
  28321         return (BCM_E_PARAM);
  28322     }
  28323 
  28324     /* Get interface table memory. */
  28325     mem = BCM_XGS3_L3_MEM(unit,  intf);
  28326 
  28327     /* Zero read buffer. */
  28328     l3_if_entry_p = (uint32 *)&l3_if_entry;
  28329     sal_memset(l3_if_entry_p, 0, sizeof(l3_max_entry_t));
  28330 
  28331     /* Read interface table entry by index. */
  28332     BCM_IF_ERROR_RETURN
  28333         (BCM_XGS3_MEM_READ (unit, mem, intf_info->l3i_index, l3_if_entry_p));
  28334 
  28335 #ifdef BCM_TRIDENT3_SUPPORT
  28336     if (SOC_MEM_FIELD_VALID(unit, mem, DATA_TYPEf)) {
  28337         ent_type = soc_mem_field32_get(unit, mem, l3_if_entry_p, DATA_TYPEf);
  28338     }
  28339     if (soc_feature(unit, soc_feature_flex_flow) &&
  28340         (ent_type > 0)) {
  28341         BCM_IF_ERROR_RETURN(
  28342          _bcm_td3_l3_flex_intf_get(unit, intf_info, l3_if_entry_p));
  28343     }
  28344     else
  28345 #endif
  28346     {
  28347         /* Extract interface information. */
  28348         fld = (_bcm_l3_intf_fields_t *)BCM_XGS3_L3_MEM_FIELDS(unit, intf);
  28349 
  28350 
  28351 #ifdef BCM_RIOT_SUPPORT
  28352     if (soc_feature(unit, soc_feature_riot)) {
  28353         svp = soc_mem_field32_get(unit, mem, l3_if_entry_p, SVPf);
  28354 
  28355         if (_bcm_vp_used_get(unit, svp, _bcmVpTypeVxlan)) {
  28356             BCM_GPORT_VXLAN_PORT_ID_SET(intf_info->l3i_source_vp, svp);
  28357         } else if (_bcm_vp_used_get(unit, svp, _bcmVpTypeL2Gre)) {
  28358             BCM_GPORT_L2GRE_PORT_ID_SET(intf_info->l3i_source_vp, svp);
  28359         } else if (_bcm_vp_used_get(unit, svp, _bcmVpTypeMim)) {
  28360             BCM_GPORT_MIM_PORT_ID_SET(intf_info->l3i_source_vp, svp);
  28361         } else if (_bcm_vp_used_get(unit, svp, _bcmVpTypeMpls)) {
  28362             BCM_GPORT_MPLS_PORT_ID_SET(intf_info->l3i_source_vp, svp);
  28363         }
  28364 
  28365         /*VLAN_VFI_OVERLAY_TYPE is not required in TD3 */
  28366         if (soc_feature(unit,soc_feature_egr_intf_vlan_vfi_deoverlay)) {
  28367            profiled_mac = soc_mem_field32_get(unit, mem, l3_if_entry_p,
  28368                               MAC_ADDRESS_OVERLAY_TYPEf);
  28369            macda_index = soc_mem_field32_get(unit, mem, l3_if_entry_p,
  28370                              MAC_ADDRESS_PROFILE_IDXf);
  28371         }
  28372         if (profiled_mac) {
  28373             /* Read entry from MAC-DA-PROFILEm */
  28374             BCM_IF_ERROR_RETURN (soc_mem_read(unit, EGR_MAC_DA_PROFILEm,
  28375                 MEM_BLOCK_ANY, macda_index, &macda));
  28376             /* Get mac address from EGR_MACDA_PROFILE. */
  28377             soc_mem_mac_addr_get(unit, EGR_MAC_DA_PROFILEm, &macda,
  28378                 MAC_ADDRESSf, intf_info->l3i_mac_addr);
  28379         } else {
  28380             /* Get mac address from EGR_L3_INTF. */
  28381             soc_mem_mac_addr_get(unit, mem, l3_if_entry_p,
  28382                     fld->mac_addr, intf_info->l3i_mac_addr);
  28383         }
  28384         if (soc_feature(unit,soc_feature_egr_intf_vlan_vfi_deoverlay)) {
  28385             if (profiled_mac) {
  28386                 /* Use profiled_mac indicator to also confirm presence of VFI and read the same */
  28387             _BCM_VPN_SET(intf_info->l3i_vid, _BCM_VPN_TYPE_VFI,
  28388                 soc_mem_field32_get(unit, mem, l3_if_entry_p, VFIf));
  28389             } else {
  28390                 intf_info->l3i_vid =
  28391                     soc_mem_field32_get(unit, mem, l3_if_entry_p,
  28392                          fld->vlan_id);
  28393             }
  28394         } else if (soc_mem_field32_get(unit, mem, l3_if_entry_p, 
  28395             VLAN_VFI_OVERLAY_TYPEf)) {
  28396 
  28397                 _BCM_VPN_SET(intf_info->l3i_vid, _BCM_VPN_TYPE_VFI,
  28398                     soc_mem_field32_get(unit, mem, l3_if_entry_p, VFIf));
  28399             } else {
  28400                 intf_info->l3i_vid =
  28401                     soc_mem_field32_get(unit, mem, l3_if_entry_p,
  28402                          fld->vlan_id);
  28403             }
  28404 
  28405         } else
  28406     #endif
  28407         {
  28408         /* Get vlan id. */
  28409         intf_info->l3i_vid =
  28410             soc_mem_field32_get(unit, mem, l3_if_entry_p, fld->vlan_id);
  28411         /* Get mac address. */
  28412         soc_mem_mac_addr_get(unit, mem, l3_if_entry_p,
  28413                              fld->mac_addr, intf_info->l3i_mac_addr);
  28414         }
  28415         /* Get Time To Live. */
  28416         if (SOC_MEM_FIELD_VALID(unit, mem, fld->ttl)) {
  28417             intf_info->l3i_ttl =
  28418                 soc_mem_field32_get(unit, mem, l3_if_entry_p, fld->ttl);
  28419         }
  28420 
  28421         /* Get tunnel index. */
  28422         if (SOC_MEM_FIELD_VALID(unit, mem, fld->tnl_id)) {
  28423             intf_info->l3i_tunnel_idx =
  28424                 soc_mem_field32_get(unit, mem, l3_if_entry_p, fld->tnl_id);
  28425         }
  28426 
  28427         /* Set L2 bridging only flag. */
  28428         if (soc_mem_field32_get(unit, mem, l3_if_entry_p, fld->l2_switch)) {
  28429             intf_info->l3i_flags |= BCM_L3_L2ONLY;
  28430         }
  28431 
  28432 #ifdef BCM_TRIDENT_SUPPORT
  28433         if (SOC_MEM_FIELD_VALID(unit, mem, OPRI_OCFI_SELf)) {
  28434              BCM_IF_ERROR_RETURN
  28435                 (_bcm_td_l3_intf_qos_get(unit, l3_if_entry_p, intf_info));
  28436         }
  28437 #endif /* BCM_TRIDENT_SUPPORT */
  28438 
  28439 #ifdef BCM_GREYHOUND2_SUPPORT
  28440         if (soc_feature(unit, soc_feature_vxlan_lite_riot)) {
  28441             BCM_IF_ERROR_RETURN(
  28442                 bcmi_gh2_l3_intf_qos_get(unit, l3_if_entry_p, intf_info));
  28443         }
  28444 #endif /* BCM_GREYHOUND2_SUPPORT */
  28445 
  28446 #ifdef BCM_TRX_SUPPORT
  28447         if (SOC_MEM_FIELD_VALID(unit, mem, IVID_VALIDf)) {
  28448             if (soc_mem_field32_get(unit, mem, l3_if_entry_p, IVID_VALIDf)) {
  28449                 intf_info->l3i_inner_vlan =
  28450                     soc_mem_field32_get(unit, mem, l3_if_entry_p, IVIDf);
  28451             }
  28452         }
  28453 #endif /* BCM_TRX_SUPPORT */
  28454 
  28455 #ifdef BCM_TRIUMPH3_SUPPORT
  28456         if (SOC_MEM_FIELD_VALID(unit, mem, CLASS_IDf)) {
  28457             intf_info->l3i_class =
  28458                 soc_mem_field32_get(unit, mem, l3_if_entry_p, fld->class_id);
  28459         }
  28460 #endif
  28461 
  28462 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)
  28463         /*Program Inner VLAN handling actions */
  28464         if (SOC_MEM_FIELD_VALID(unit, mem, IVID_PRESENT_ACTIONf)) {
  28465             int action;
  28466             action = soc_mem_field32_get(unit, mem, l3_if_entry_p,
  28467                                          IVID_PRESENT_ACTIONf);
  28468             switch (action) {
  28469                 case 0:
  28470                     intf_info->l3i_intf_flags |=
  28471                         BCM_L3_INTF_INNER_VLAN_DO_NOT_MODIFY;
  28472                     break;
  28473                 case 1:
  28474 #if defined(BCM_GREYHOUND2_SUPPORT)
  28475                     if (soc_feature(unit, soc_feature_vxlan_lite_riot)) {
  28476                         intf_info->l3i_intf_flags |=
  28477                             BCM_L3_INTF_INNER_VLAN_DELETE;
  28478                     } else
  28479 #endif /* BCM_GREYHOUND2_SUPPORT */
  28480                     {
  28481                         intf_info->l3i_intf_flags |=
  28482                             BCM_L3_INTF_INNER_VLAN_REPLACE;
  28483                     }
  28484                     break;
  28485                 case 2:
  28486 #if defined(BCM_GREYHOUND2_SUPPORT)
  28487                     if (soc_feature(unit, soc_feature_vxlan_lite_riot)) {
  28488                         intf_info->l3i_intf_flags |=
  28489                             BCM_L3_INTF_INNER_VLAN_REPLACE;
  28490                     } else
  28491 #endif /* BCM_GREYHOUND2_SUPPORT */
  28492                     {
  28493                         intf_info->l3i_intf_flags |=
  28494                             BCM_L3_INTF_INNER_VLAN_DELETE;
  28495                     }
  28496                     break;
  28497                 default:
  28498                     intf_info->l3i_intf_flags |=
  28499                         BCM_L3_INTF_INNER_VLAN_DO_NOT_MODIFY;
  28500             }
  28501             action = soc_mem_field32_get(unit, mem, l3_if_entry_p,
  28502                                          IVID_ABSENT_ACTIONf);
  28503             if (action == 1) {
  28504                 intf_info->l3i_intf_flags |= BCM_L3_INTF_INNER_VLAN_ADD;
  28505                 intf_info->l3i_intf_flags &=
  28506                     ~(BCM_L3_INTF_INNER_VLAN_DO_NOT_MODIFY);
  28507             }
  28508             intf_info->l3i_inner_vlan =
  28509                 soc_mem_field32_get(unit, mem, l3_if_entry_p, IVIDf);
  28510         }
  28511 #endif /* BCM_TRIDENT2_SUPPORT || BCM_GREYHOUND2_SUPPORT */
  28512     }
  28513 
  28514 #ifdef BCM_TRIDENT2_SUPPORT
  28515     if (soc_feature(unit, soc_feature_nat)
  28516 #ifdef BCM_RIOT_SUPPORT
  28517         && (!( BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)))
  28518 #endif 
  28519     ) { 
  28520 
  28521         BCM_IF_ERROR_RETURN(_bcm_fb_l3_intf_nat_realm_id_get(unit, intf_info));
  28522     }
  28523 
  28524     if (soc_feature(unit, soc_feature_l3_ip4_options_profile) 
  28525 #ifdef BCM_RIOT_SUPPORT
  28526         && (!( BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)))
  28527 #endif 
  28528     ) { 
  28529         BCM_IF_ERROR_RETURN(
  28530             _bcm_td2_l3_iif_ip4_options_profile_index_get(unit, intf_info));
  28531     }
  28532 #endif /* BCM_TRIDENT2_SUPPORT */
  28533 
  28534 #if defined(BCM_TRIUMPH_SUPPORT)
  28535     /* Read L3 mtu value for the interface. */
  28536     if (SOC_MEM_IS_VALID(unit, L3_MTU_VALUESm)) {
  28537 #if defined(BCM_HURRICANE_SUPPORT)||defined(BCM_GREYHOUND_SUPPORT)
  28538         if(SOC_IS_HURRICANEX(unit)||SOC_IS_GREYHOUND(unit)||
  28539             SOC_IS_GREYHOUND2(unit)) {
  28540             BCM_IF_ERROR_RETURN(_bcm_hu_l3_intf_mtu_get(unit, intf_info));
  28541         } else
  28542 #endif /* BCM_HURRICANE_SUPPORT*/
  28543         {
  28544             BCM_IF_ERROR_RETURN(_bcm_tr_l3_intf_mtu_get(unit, intf_info));
  28545         }
  28546     }
  28547 #endif /* BCM_TRIUMPH_SUPPORT */
  28548 
  28549 #if defined(BCM_TRIUMPH3_SUPPORT)
  28550     if (SOC_IS_TRIUMPH3(unit)) {
  28551         BCM_IF_ERROR_RETURN(_bcm_tr3_l3_intf_mtu_get(unit, intf_info));
  28552     }
  28553 #endif /* BCM_TRIUMPH3_SUPPORT */
  28554 
  28555     return (BCM_E_NONE);
  28556 }
  28557 /*
  28558  * Function:
  28559  *      _bcm_xgs3_l3_intf_add
  28560  * Purpose:
  28561  *      Add an entry to L3 interface table.
  28562  * Parameters:
  28563  *      unit      - (IN)SOC unit number.
  28564  *      intf_info - (IN)Interface information.
  28565  * Returns:
  28566  *      BCM_E_XXX
  28567  */
  28568 STATIC int
  28569 _bcm_xgs3_l3_intf_add(int unit, _bcm_l3_intf_cfg_t *intf_info)
  28570 {
  28571     l3_max_entry_t l3_if_entry;    /* Buffer to write interface info. */
  28572     _bcm_l3_intf_fields_t *fld;    /* Interface table common fields.  */
  28573     uint32  *l3_if_entry_p;        /* Write buffer address.           */
  28574     soc_mem_t mem;                 /* Interface table memory.         */
  28575 #ifdef BCM_RIOT_SUPPORT
  28576     egr_mac_da_profile_entry_t macda;
  28577     uint32 macda_index = -1;
  28578     void *entries[1];
  28579 #endif
  28580 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)
  28581     int ivid_action_replace = 0, ivid_action_delete = 0;
  28582 #endif /* BCM_TRIDENT2_SUPPORT || BCM_GREYHOUND2_SUPPORT */
  28583 
  28584     /* Input parameters check */
  28585     if (NULL == intf_info) {
  28586         return (BCM_E_PARAM);
  28587     }
  28588 
  28589     /* Get interface table memory. */
  28590     mem = BCM_XGS3_L3_MEM(unit,  intf);
  28591 
  28592     /* Get memory fields information. */
  28593     fld = (_bcm_l3_intf_fields_t *)BCM_XGS3_L3_MEM_FIELDS(unit, intf);
  28594 
  28595     /* Zero the buffer. */
  28596     l3_if_entry_p = (uint32 *)&l3_if_entry;
  28597     sal_memset(l3_if_entry_p, 0, BCM_XGS3_L3_ENT_SZ(unit, intf));
  28598     BCM_IF_ERROR_RETURN(
  28599         BCM_XGS3_MEM_READ(unit, mem, intf_info->l3i_index, l3_if_entry_p));
  28600 
  28601 #ifdef BCM_TOMAHAWK3_SUPPORT
  28602     if (SOC_IS_TOMAHAWK3(unit) &&
  28603         (intf_info->l3i_intf_flags & (BCM_L3_INTF_INNER_VLAN_DO_NOT_MODIFY |
  28604                                      BCM_L3_INTF_INNER_VLAN_REPLACE |
  28605                                      BCM_L3_INTF_INNER_VLAN_ADD |
  28606                                      BCM_L3_INTF_INNER_VLAN_DELETE))) {
  28607         return (BCM_E_UNAVAIL);
  28608     }
  28609 #endif
  28610 #ifdef BCM_TRIDENT3_SUPPORT
  28611     if (soc_feature(unit, soc_feature_flex_flow) &&
  28612         (intf_info->flow_handle != 0)) {
  28613 
  28614         BCM_IF_ERROR_RETURN(
  28615             _bcm_td3_l3_flex_intf_add(unit, intf_info, l3_if_entry_p));
  28616     }
  28617     else
  28618 #endif
  28619     {
  28620 
  28621 #ifdef BCM_RIOT_SUPPORT
  28622         if (BCMI_L3_INTF_OVERLAY_VALID(unit)) {
  28623             int svp = intf_info->l3i_source_vp;
  28624             if (BCM_GPORT_IS_VXLAN_PORT(svp)) {
  28625                 svp = BCM_GPORT_VXLAN_PORT_ID_GET(svp);
  28626             } else if (BCM_GPORT_IS_L2GRE_PORT(svp)) {
  28627                 svp = BCM_GPORT_L2GRE_PORT_ID_GET(svp);
  28628             } else if (BCM_GPORT_IS_MIM_PORT(svp)) {
  28629                 svp = BCM_GPORT_MIM_PORT_ID_GET(svp);
  28630             } else if (BCM_GPORT_IS_MPLS_PORT(svp)) {
  28631                 svp = BCM_GPORT_MPLS_PORT_ID_GET(svp);
  28632             }
  28633 
  28634             soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28635                                 SVPf, svp);
  28636 
  28637             if (!soc_feature(unit,soc_feature_egr_intf_vlan_vfi_deoverlay)) {
  28638                 /* Set mac address. */
  28639                 soc_mem_mac_addr_set(unit, mem, l3_if_entry_p,
  28640                     fld->mac_addr, intf_info->l3i_mac_addr);
  28641                 if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)) {
  28642                     int vfi_idx = 0;
  28643                     _BCM_VPN_GET(vfi_idx, _BCM_VPN_TYPE_VFI, intf_info->l3i_vid);
  28644                     soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28645                         VFIf, vfi_idx);
  28646                     soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28647                         VLAN_VFI_OVERLAY_TYPEf, 1);
  28648                 } else {
  28649                     soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28650                         fld->vlan_id, intf_info->l3i_vid);
  28651                     soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28652                         VLAN_VFI_OVERLAY_TYPEf, 0);
  28653             }
  28654             } else {
  28655                 if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)) {
  28656                     int vfi_idx = 0;
  28657                     _BCM_VPN_GET(vfi_idx, _BCM_VPN_TYPE_VFI, intf_info->l3i_vid);
  28658                     soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28659                         VFIf, vfi_idx);
  28660                     /* Profiling of EGR_MAC_SA since it is overlaid*/
  28661                     sal_memset(&macda, 0, sizeof(egr_mac_da_profile_entry_t));
  28662                     soc_mem_mac_addr_set(unit, EGR_MAC_DA_PROFILEm,
  28663                         &macda, MAC_ADDRESSf, intf_info->l3i_mac_addr);
  28664                     entries[0] = &macda;
  28665                     BCM_IF_ERROR_RETURN(_bcm_mac_da_profile_entry_add(unit,
  28666                         entries, 1, &macda_index));
  28667 
  28668                     /* Point to the right profile in egress interface table */
  28669                 soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28670                         MAC_ADDRESS_PROFILE_IDXf, macda_index);
  28671                     soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28672                         MAC_ADDRESS_OVERLAY_TYPEf, 1);
  28673             } else {
  28674                 soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28675                                     fld->vlan_id, intf_info->l3i_vid);
  28676                     soc_mem_mac_addr_set(unit, mem, l3_if_entry_p,
  28677                         fld->mac_addr, intf_info->l3i_mac_addr);
  28678                 }
  28679             }
  28680         } else 
  28681     #endif
  28682         {
  28683             /* Set vlan id. */
  28684             soc_mem_field32_set(unit, mem, l3_if_entry_p, 
  28685                                 fld->vlan_id, intf_info->l3i_vid);
  28686         /* Set mac address. */
  28687            soc_mem_mac_addr_set(unit, mem, l3_if_entry_p,
  28688                              fld->mac_addr, intf_info->l3i_mac_addr);
  28689         }
  28690         /* Set Time To Live. */
  28691         if(SOC_MEM_FIELD_VALID(unit, mem, fld->ttl)) {
  28692             soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28693                                 fld->ttl, intf_info->l3i_ttl);
  28694         }
  28695 
  28696         /* Set tunnel index. */
  28697         if (SOC_MEM_FIELD_VALID(unit, mem, fld->tnl_id)) {
  28698             soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28699                                 fld->tnl_id, intf_info->l3i_tunnel_idx);
  28700         }
  28701 
  28702         /* Set L2 bridging only flag. */
  28703         if (intf_info->l3i_flags & BCM_L3_L2ONLY) {
  28704             soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28705                                 fld->l2_switch, 1);
  28706         } else {
  28707             soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28708                                 fld->l2_switch, 0);
  28709         }
  28710 
  28711 #ifdef BCM_TRX_SUPPORT
  28712         if (SOC_MEM_FIELD_VALID(unit, mem, IVIDf)) {
  28713             if (intf_info->l3i_inner_vlan) {
  28714                 soc_mem_field32_set(unit, mem, l3_if_entry_p, IVIDf,
  28715                                     intf_info->l3i_inner_vlan);
  28716                 if (SOC_MEM_FIELD_VALID(unit, mem, IVID_VALIDf)) {
  28717                     soc_mem_field32_set(unit, mem, l3_if_entry_p, IVID_VALIDf, 0x1);
  28718                 }
  28719             }
  28720         }
  28721 #endif /* BCM_TRX_SUPPORT */
  28722 
  28723 #ifdef BCM_TRIUMPH3_SUPPORT
  28724         if (SOC_MEM_FIELD_VALID(unit, mem, CLASS_IDf)) {
  28725             soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28726                                 fld->class_id, intf_info->l3i_class);
  28727         }
  28728 #endif
  28729 
  28730 #ifdef BCM_TRIDENT_SUPPORT
  28731         if (SOC_MEM_FIELD_VALID(unit, mem, OPRI_OCFI_SELf)) {
  28732             BCM_IF_ERROR_RETURN
  28733                 (_bcm_td_l3_intf_qos_set(unit, l3_if_entry_p, intf_info));
  28734         }
  28735 #endif /* BCM_TRIDENT_SUPPORT */
  28736 
  28737 #ifdef BCM_GREYHOUND2_SUPPORT
  28738         if (soc_feature(unit, soc_feature_vxlan_lite_riot)) {
  28739             BCM_IF_ERROR_RETURN(
  28740                 bcmi_gh2_l3_intf_qos_set(unit, l3_if_entry_p, intf_info));
  28741         }
  28742 #endif /* BCM_GREYHOUND2_SUPPORT */
  28743 
  28744 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)
  28745         /* Program Inner VLAN handling actions */
  28746         if (SOC_MEM_FIELD_VALID(unit, mem, IVID_PRESENT_ACTIONf)) {
  28747             ivid_action_replace =
  28748                 (soc_feature(unit, soc_feature_vxlan_lite_riot)) ? 2 : 1;
  28749             ivid_action_delete =
  28750                 (soc_feature(unit, soc_feature_vxlan_lite_riot)) ? 1 : 2;
  28751 
  28752             if (intf_info->l3i_intf_flags &
  28753                 BCM_L3_INTF_INNER_VLAN_DO_NOT_MODIFY) {
  28754                 soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28755                                     IVID_PRESENT_ACTIONf, 0);
  28756                 soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28757                                     IVID_ABSENT_ACTIONf, 0);
  28758                 soc_mem_field32_set(unit, mem, l3_if_entry_p, IVIDf, 0);
  28759             } else {
  28760                 if (intf_info->l3i_intf_flags & BCM_L3_INTF_INNER_VLAN_ADD) {
  28761                     if (intf_info->l3i_intf_flags &
  28762                         BCM_L3_INTF_INNER_VLAN_REPLACE) {
  28763                         soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28764                                             IVID_PRESENT_ACTIONf,
  28765                                             ivid_action_replace);
  28766                     } else if (intf_info->l3i_intf_flags &
  28767                         BCM_L3_INTF_INNER_VLAN_DELETE) {
  28768                         soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28769                                             IVID_PRESENT_ACTIONf,
  28770                                             ivid_action_delete);
  28771                     } else {
  28772                         soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28773                                             IVID_PRESENT_ACTIONf, 0);
  28774                     }
  28775                     soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28776                                         IVID_ABSENT_ACTIONf, 1);
  28777                     soc_mem_field32_set(unit, mem, l3_if_entry_p, IVIDf,
  28778                                         intf_info->l3i_inner_vlan);
  28779                 } else {
  28780                     if (intf_info->l3i_intf_flags &
  28781                         BCM_L3_INTF_INNER_VLAN_REPLACE) {
  28782                         soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28783                                             IVID_PRESENT_ACTIONf,
  28784                                             ivid_action_replace);
  28785                         soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28786                                             IVID_ABSENT_ACTIONf, 0);
  28787                         soc_mem_field32_set(unit, mem, l3_if_entry_p, IVIDf,
  28788                                             intf_info->l3i_inner_vlan);
  28789                     } else {
  28790                         if (intf_info->l3i_intf_flags &
  28791                             BCM_L3_INTF_INNER_VLAN_DELETE) {
  28792                             soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28793                                                 IVID_PRESENT_ACTIONf,
  28794                                                 ivid_action_delete);
  28795                             soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28796                                                 IVID_ABSENT_ACTIONf, 0);
  28797                             soc_mem_field32_set(unit, mem, l3_if_entry_p,
  28798                                                 IVIDf, 0);
  28799                         }
  28800                     }
  28801                 }
  28802             }
  28803         }
  28804 #endif /* BCM_TRIDENT2_SUPPORT || BCM_GREYHOUND2_SUPPORT */
  28805     }
  28806 
  28807     /* Write entry to the chip. */
  28808     BCM_IF_ERROR_RETURN
  28809         (BCM_XGS3_MEM_WRITE(unit, mem, intf_info->l3i_index, l3_if_entry_p));
  28810 
  28811     /* SDK-33159 : section below to update the usage of L3_IIFm index is 
  28812      *    for fixing urpf strict mode issue on TD device.
  28813      *  - Such design may causes unexpected L3_IIFm entry been reserved 
  28814      *    once the device(like HR3) can't support 4K above L3_IIFm entry.
  28815      *  - For fixing SDK-77744, section below will be ignored for devices 
  28816      *    supports L3_IIFm under 4K entries.
  28817      */
  28818     if (!soc_feature(unit, soc_feature_l3_iif_under_4k)) {
  28819         if (BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit)) {
  28820             /* mark L3_ING_Interface with interface_id as Used */
  28821             SHR_BITSET(BCM_XGS3_L3_ING_IF_INUSE(unit), intf_info->l3i_index);
  28822         }
  28823     }
  28824 
  28825 #ifdef BCM_TRIUMPH_SUPPORT
  28826     if (SOC_MEM_IS_VALID(unit, L3_MTU_VALUESm)) {
  28827 #if defined(BCM_HURRICANE_SUPPORT)||defined(BCM_GREYHOUND_SUPPORT)
  28828         if(SOC_IS_HURRICANEX(unit)||SOC_IS_GREYHOUND(unit)||
  28829             SOC_IS_GREYHOUND2(unit)) {
  28830             BCM_IF_ERROR_RETURN(_bcm_hu_l3_intf_mtu_set(unit, intf_info));
  28831         } else
  28832 #endif /* BCM_HURRICANE_SUPPORT*/
  28833         {
  28834             BCM_IF_ERROR_RETURN(_bcm_tr_l3_intf_mtu_set(unit, intf_info));
  28835         }
  28836     }
  28837 #endif /* BCM_TRIUMPH_SUPPORT */
  28838 
  28839 #if defined(BCM_TRIUMPH3_SUPPORT)
  28840     if (SOC_IS_TRIUMPH3(unit)) {
  28841         BCM_IF_ERROR_RETURN(_bcm_tr3_l3_intf_mtu_set(unit, intf_info));
  28842     }
  28843 #endif /* BCM_TRIUMPH3_SUPPORT */
  28844 
  28845     return (BCM_E_NONE);
  28846 
  28847 }
  28848 
  28849 /*
  28850  * Function:
  28851  *      _bcm_xgs3_l3_intf_del
  28852  * Purpose:
  28853  *      Delete an entry from L3 interface table.
  28854  * Parameters:
  28855  *      unit      - (IN)SOC unit number.
  28856  *      ifindex   - (IN)Interface index.
  28857  * Returns:
  28858  *      BCM_E_XXX
  28859  */
  28860 STATIC int
  28861 _bcm_xgs3_l3_intf_del(int unit, int ifindex)
  28862 {
  28863     l3_max_entry_t l3_if_entry;    /* Buffer to write interface info. */
  28864     soc_mem_t              mem;    /* Interface table memory.        */
  28865 
  28866     /* Get interface table memory. */
  28867     mem = BCM_XGS3_L3_MEM(unit,  intf);
  28868 
  28869     /* Zero the buffer. */
  28870     sal_memset(&l3_if_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, intf));
  28871 
  28872 #ifdef BCM_TRIDENT3_SUPPORT
  28873     if (soc_feature(unit, soc_feature_flex_flow)) {
  28874         BCM_IF_ERROR_RETURN(
  28875             _bcm_td3_l3_flex_intf_profile_delete(unit, ifindex));
  28876     }
  28877 #endif
  28878 
  28879     /* SDK-33159 : section below to update the usage of L3_IIFm index is 
  28880      *    for fixing urpf strict mode issue on TD device.
  28881      *  - Such design may causes unexpected L3_IIFm entry been reserved 
  28882      *    once the device(like HR3) can't support 4K above L3_IIFm entry.
  28883      *  - For fixing SDK-77744, section below will be ignored for devices 
  28884      *    supports L3_IIFm under 4K entries.
  28885      */
  28886     if (!soc_feature(unit, soc_feature_l3_iif_under_4k)) {
  28887         if (BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit)) {
  28888             /* mark L3_ING_Interface with interface_id as Un-used */
  28889             SHR_BITCLR(BCM_XGS3_L3_ING_IF_INUSE(unit), ifindex);
  28890         }
  28891     }
  28892 
  28893 #ifdef BCM_TRIUMPH3_SUPPORT
  28894     /* On Triumph3, MMU replication outputs next hop indices only.
  28895      * Hence, a next hop index is allocated for each L3 interface
  28896      * used in IPMC replication. When deleting a L3 interface,
  28897      * the associated next hop index needs to be freed.
  28898      */
  28899     if (soc_feature(unit, soc_feature_repl_l3_intf_use_next_hop)) {
  28900 #ifdef BCM_TOMAHAWK_SUPPORT
  28901         if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
  28902             BCM_IF_ERROR_RETURN(bcm_th_ipmc_l3_intf_next_hop_free(unit, ifindex));
  28903         } else
  28904 #endif /* BCM_TOMAHAWK_SUPPORT */
  28905         {
  28906             BCM_IF_ERROR_RETURN(bcm_tr3_ipmc_l3_intf_next_hop_free(unit, ifindex));
  28907         }
  28908     }
  28909 #endif /* BCM_TRIUMPH3_SUPPORT */
  28910 
  28911 #ifdef BCM_TRIDENT2_SUPPORT
  28912     if (soc_feature(unit, soc_feature_virtual_port_routing)) {
  28913         BCM_IF_ERROR_RETURN(bcm_td2_multicast_l3_vp_next_hop_free(unit, ifindex));
  28914     }
  28915 #endif /* BCM_TRIDENT2_SUPPORT */
  28916 
  28917     /* Clear flag that indicates if L3 interface is used in Next Hop table. */
  28918     BCM_XGS3_L3_INTF_USED_NH_CLR(unit, ifindex);
  28919 
  28920     /* Write entry to the chip. */
  28921     return BCM_XGS3_MEM_WRITE(unit, mem, ifindex, &l3_if_entry);
  28922 }
  28923 
  28924 /*
  28925  * Function:
  28926  *      _bcm_xgs3_l3_intf_tnl_init_get
  28927  * Purpose:
  28928  *      Get interface tunnel initiator info
  28929  * Parameters:
  28930  *      unit         - (IN)SOC unit number.
  28931  *      ifindex      - (IN)Interface index.
  28932  *      tnl_info     - (OUT)Tunnel initiator buffer to fill.
  28933  * Returns:
  28934  *      BCM_E_XXX
  28935  */
  28936 STATIC int
  28937 _bcm_xgs3_l3_intf_tnl_init_get(int unit, int ifindex,
  28938                                _bcm_tnl_init_data_t *tnl_info)
  28939 {
  28940     l3_max_entry_t l3_if_entry;    /* Buffer to read interface info. */
  28941     _bcm_l3_intf_fields_t *fld;    /* Interface table common fields. */
  28942     uint32  *l3_if_entry_p;        /* Write buffer address.          */
  28943     soc_mem_t mem;                 /* Interface table memory.        */
  28944 
  28945     /* Input parameters check */
  28946     if (NULL == tnl_info) {
  28947         return (BCM_E_PARAM);
  28948     }
  28949 
  28950     /* Get interface table memory. */
  28951     mem = BCM_XGS3_L3_MEM(unit,  intf);
  28952 
  28953     /* Zero the buffer. */
  28954     l3_if_entry_p = (uint32 *)&l3_if_entry;
  28955     sal_memset(l3_if_entry_p, 0, BCM_XGS3_L3_ENT_SZ(unit, intf));
  28956 
  28957     /* Read interface table entry by index. */
  28958     BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ (unit, mem, ifindex, l3_if_entry_p));
  28959 
  28960     /* Extract interface information. */
  28961     fld = (_bcm_l3_intf_fields_t *)BCM_XGS3_L3_MEM_FIELDS(unit, intf);
  28962 
  28963     /* Get tunnel index. */
  28964     if (SOC_MEM_FIELD_VALID(unit, mem, fld->tnl_id)) {
  28965         tnl_info->tnl_idx = soc_mem_field32_get(unit, mem,
  28966                                                 l3_if_entry_p, fld->tnl_id);
  28967     }
  28968 
  28969     return (BCM_E_NONE);
  28970 }
  28971 
  28972 /*
  28973  * Function:
  28974  *      _bcm_xgs3_l3_intf_tnl_init_set
  28975  * Purpose:
  28976  *      Mark interface as tunnel initiator
  28977  * Parameters:
  28978  *      unit         - (IN)SOC unit number.
  28979  *      ifindex      - (IN)Interface index.
  28980  *      tnl_info     - (IN)Tunnel initiator entry params.
  28981  * Returns:
  28982  *      BCM_E_XXX
  28983  */
  28984 STATIC int
  28985 _bcm_xgs3_l3_intf_tnl_init_set(int unit, int ifindex,
  28986                                _bcm_tnl_init_data_t *tnl_info)
  28987 {
  28988     l3_max_entry_t l3_if_entry;    /* Buffer to read interface info. */
  28989     _bcm_l3_intf_fields_t *fld;    /* Interface table common fields. */
  28990     uint32  *l3_if_entry_p;        /* Write buffer address.          */
  28991     soc_mem_t mem;                 /* Interface table memory.        */
  28992 
  28993     /* Input parameters check */
  28994     if (NULL == tnl_info) {
  28995         return (BCM_E_PARAM);
  28996     }
  28997 
  28998     /* Get interface table memory. */
  28999     mem = BCM_XGS3_L3_MEM(unit,  intf);
  29000 
  29001     /* Zero the buffer. */
  29002     l3_if_entry_p = (uint32 *)&l3_if_entry;
  29003     sal_memset(l3_if_entry_p, 0, BCM_XGS3_L3_ENT_SZ(unit, intf));
  29004 
  29005     /* Read interface table entry by index. */
  29006     BCM_IF_ERROR_RETURN (BCM_XGS3_MEM_READ (unit, mem, ifindex, l3_if_entry_p));
  29007 
  29008     /* Extract interface information. */
  29009     fld = (_bcm_l3_intf_fields_t *)BCM_XGS3_L3_MEM_FIELDS(unit, intf);
  29010 
  29011     /* Get tunnel index. */
  29012     if (SOC_MEM_FIELD_VALID(unit, mem, fld->tnl_id)) {
  29013         soc_mem_field32_set(unit, mem, l3_if_entry_p, fld->tnl_id,
  29014                             tnl_info->tnl_idx);
  29015     }
  29016 
  29017     /* Write entry back to hw. */
  29018     BCM_IF_ERROR_RETURN
  29019         (BCM_XGS3_MEM_WRITE(unit, mem, ifindex, l3_if_entry_p));
  29020 
  29021 #ifdef BCM_FIREBOLT_SUPPORT
  29022     if (SOC_MEM_FIELD_VALID(unit, ING_L3_NEXT_HOPm, L3UC_TUNNEL_TYPEf)) {
  29023         BCM_IF_ERROR_RETURN
  29024             (_bcm_fb_nh_intf_is_tnl_update(unit, ifindex, tnl_info->tnl_idx));
  29025     }
  29026 #endif /* BCM_FIREBOLT_SUPPORT */
  29027     return (BCM_E_NONE);
  29028 }
  29029 
  29030 /*
  29031  * Function:
  29032  *      _bcm_xgs3_l3_intf_tnl_init_reset
  29033  * Purpose:
  29034  *      Unmark interface as tunnel initiator
  29035  * Parameters:
  29036  *      unit         - (IN)SOC unit number.
  29037  *      ifindex      - (IN)Interface index.
  29038  * Returns:
  29039  *      BCM_E_XXX
  29040  */
  29041 STATIC int
  29042 _bcm_xgs3_l3_intf_tnl_init_reset(int unit, int ifindex)
  29043 {
  29044     l3_max_entry_t l3_if_entry;    /* Buffer to read interface info. */
  29045     _bcm_l3_intf_fields_t *fld;    /* Interface table common fields. */
  29046     uint32  *l3_if_entry_p;        /* Write buffer address.          */
  29047     soc_mem_t mem;                 /* Interface table memory.        */
  29048 
  29049     /* Get interface table memory. */
  29050     mem = BCM_XGS3_L3_MEM(unit,  intf);
  29051 
  29052     /* Zero the buffer. */
  29053     l3_if_entry_p = (uint32 *)&l3_if_entry;
  29054     sal_memset(l3_if_entry_p, 0, BCM_XGS3_L3_ENT_SZ(unit, intf));
  29055 
  29056     /* Read interface table entry by index. */
  29057     BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ (unit, mem, ifindex, l3_if_entry_p));
  29058 
  29059     /* Extract interface information. */
  29060     fld = (_bcm_l3_intf_fields_t *)BCM_XGS3_L3_MEM_FIELDS(unit, intf);
  29061 
  29062     /* Get tunnel index. */
  29063     if (SOC_MEM_FIELD_VALID(unit, mem, fld->tnl_id)) {
  29064         soc_mem_field32_set(unit, mem, l3_if_entry_p, fld->tnl_id, 0);
  29065     }
  29066 
  29067     /* Write entry back to hw. */
  29068     BCM_IF_ERROR_RETURN
  29069         (BCM_XGS3_MEM_WRITE(unit, mem, ifindex, l3_if_entry_p));
  29070 
  29071 #ifdef BCM_FIREBOLT_SUPPORT
  29072     if (SOC_MEM_FIELD_VALID(unit, ING_L3_NEXT_HOPm, L3UC_TUNNEL_TYPEf)) {
  29073         if (SOC_IS_FBX(unit)) {
  29074             BCM_IF_ERROR_RETURN(_bcm_fb_nh_intf_is_tnl_update(unit, ifindex, 0));
  29075         }
  29076     }
  29077 #endif /* BCM_FIREBOLT_SUPPORT */
  29078 
  29079     return (BCM_E_NONE);
  29080 
  29081 }
  29082 
  29083 #ifdef BCM_TOMAHAWK3_SUPPORT
  29084 int
  29085 _bcm_xgs3_th3_nh_entry_parse(int unit, uint32 *ing_entry_ptr,
  29086         uint32 *egr_entry_ptr, uint32 *egr_entry_2_ptr, uint32 index,
  29087         bcm_l3_egress_t *nh_entry, uint8 *nh_ent_type)
  29088 {
  29089     int mod = 0;                        /* Module id value in hw.           */
  29090     int port = 0;                       /* Port value in hw.                */
  29091     int ent_type = 0;
  29092     _bcm_l3_intf_cfg_t intf_info;
  29093     int ret_val;
  29094     int ing_ent_type = 0;
  29095     int l3mc = 0;
  29096     th3_mem_ING_L3_NEXT_HOP_t *ing_ent;
  29097     th3_mem_EGR_L3_NEXT_HOP_t *egr_ent;
  29098     th3_mem_EGR_L3_NEXT_HOP_2_t *egr2_ent;
  29099     soc_mem_t mem;                      /* Table location memory.           */
  29100 
  29101     ing_ent = (th3_mem_ING_L3_NEXT_HOP_t *)ing_entry_ptr;
  29102     egr_ent = (th3_mem_EGR_L3_NEXT_HOP_t *)egr_entry_ptr;
  29103     egr2_ent = (th3_mem_EGR_L3_NEXT_HOP_2_t *)egr_entry_2_ptr;
  29104 
  29105     /* Zero buffers. */
  29106     bcm_l3_egress_t_init(nh_entry);
  29107 
  29108     /* Check if next hop entry type is L3MC */
  29109     ent_type = egr_ent->ENTRY_TYPE;
  29110     if (3 == ent_type) {
  29111         /* Entry type is L3MC */
  29112         l3mc = 1;
  29113     }
  29114 
  29115     /* Check if next hop entry type is L3MC */
  29116     if (l3mc) {
  29117         if (soc_feature(unit, soc_feature_repl_l3_intf_use_next_hop)) {
  29118             return _bcm_tr3_l3_ipmc_nh_entry_parse(unit, ing_entry_ptr,
  29119                     egr_entry_ptr, egr_entry_2_ptr, nh_entry);
  29120         }
  29121     }
  29122 
  29123     /* Get next hop table memory location. */
  29124 
  29125     /* Extract next hop info. */
  29126     /* Get port trunk information. */
  29127     port = ing_ent->PORT_NUM;
  29128 
  29129     if (ing_ent->T) {
  29130         nh_entry->flags |= BCM_L3_TGID;
  29131         port = ing_ent->PORT_NUM;
  29132     }
  29133     if (port & BCM_TGID_TRUNK_INDICATOR(unit)) {
  29134         nh_entry->flags |= BCM_L3_TGID;
  29135     }
  29136 
  29137     if (ing_ent->COPY_TO_CPU) {
  29138         nh_entry->flags |= BCM_L3_COPY_TO_CPU;
  29139     }
  29140 
  29141     if (ing_ent->DROP) {
  29142         nh_entry->flags |= BCM_L3_DST_DISCARD;
  29143     }
  29144 
  29145     /* Map module/port to next hop entry format. */
  29146     BCM_IF_ERROR_RETURN
  29147         (_bcm_xgs3_nh_map_hw_data_to_api(unit, port, mod, nh_entry));
  29148 
  29149     ing_ent_type = ing_ent->ENTRY_TYPE;
  29150     if (!BCM_XGS3_L3_INTF_VLAN_SPLIT_EGRESS_MODE_ISSET(unit) && (ing_ent_type != 2)) {
  29151         /* Get vlan id. */
  29152         nh_entry->vlan = ing_ent->VLAN_ID;
  29153     }
  29154 
  29155     if (ent_type == 0) { /* L3 Unicast */
  29156         if (egr_ent->L3__L3_UC_VLAN_DISABLE) {
  29157             nh_entry->flags |= BCM_L3_KEEP_VLAN;
  29158         }
  29159         if (egr_ent->L3__L3_UC_TTL_DISABLE) {
  29160             nh_entry->flags |= BCM_L3_KEEP_TTL;
  29161         }
  29162         if (egr_ent->L3__L3_UC_DA_DISABLE) {
  29163             nh_entry->flags |= BCM_L3_KEEP_DSTMAC;
  29164         }
  29165         if (egr_ent->L3__L3_UC_SA_DISABLE) {
  29166             nh_entry->flags |= BCM_L3_KEEP_SRCMAC;
  29167         }
  29168     }
  29169 
  29170     if (soc_feature(unit, soc_feature_nh_for_ifp_actions) &&
  29171         0x2 == ent_type && _BCM_L3_FIELD_ONLY ==
  29172         BCM_XGS3_L3_ENT_FLAG(BCM_XGS3_L3_TBL_PTR(unit, next_hop), index)) {
  29173 
  29174         nh_entry->flags2 |= BCM_L3_FLAGS2_FIELD_ONLY;
  29175 
  29176         if (egr_ent->IFP_ACTIONS__L3_UC_VLAN_DISABLE) {
  29177             nh_entry->flags |= BCM_L3_KEEP_VLAN;
  29178         }
  29179 
  29180         if (egr_ent->IFP_ACTIONS__L3_UC_TTL_DISABLE) {
  29181             nh_entry->flags |= BCM_L3_KEEP_TTL;
  29182         }
  29183 
  29184         if (egr_ent->IFP_ACTIONS__L3_UC_DA_DISABLE) {
  29185             nh_entry->flags |= BCM_L3_KEEP_DSTMAC;
  29186         }
  29187 
  29188         if (egr_ent->IFP_ACTIONS__L3_UC_SA_DISABLE) {
  29189             nh_entry->flags |= BCM_L3_KEEP_SRCMAC;
  29190         }
  29191     }
  29192 
  29193     /* Get interface index. */
  29194     if (egr_entry_2_ptr) {
  29195         nh_entry->intf = egr2_ent->INTF_NUM;
  29196     }
  29197 
  29198     if (nh_entry->intf == BCM_XGS3_L3_L2CPU_INTF_IDX(unit)) {
  29199         nh_entry->flags |= BCM_L3_L2TOCPU;
  29200     }
  29201 
  29202     if (BCM_XGS3_L3_INTF_VLAN_SPLIT_EGRESS_MODE_ISSET(unit) || (ing_ent_type == 2)) {
  29203         /* Now get the vlan */
  29204         sal_memset(&intf_info, 0x0, sizeof(intf_info));
  29205         intf_info.l3i_index = nh_entry->intf;
  29206 
  29207         if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_get)) {
  29208             BCM_XGS3_L3_MODULE_LOCK(unit);
  29209             ret_val = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit,
  29210                                                              &intf_info);
  29211             BCM_XGS3_L3_MODULE_UNLOCK(unit);
  29212             BCM_IF_ERROR_RETURN(ret_val);
  29213             nh_entry->vlan = intf_info.l3i_vid;
  29214         }
  29215     }
  29216 
  29217     /* Get mac address. */
  29218     soc_mem_mac_addr_get(unit, EGR_L3_NEXT_HOPm, egr_entry_ptr,
  29219                          MAC_ADDRESSf, nh_entry->mac_addr);
  29220 
  29221     if (nh_ent_type) {
  29222         *nh_ent_type = (uint8)ent_type;
  29223     }
  29224     if (ent_type == 0x1) { /* == MPLS_MACDA_PROFILE */
  29225         int macda_idx = 0;
  29226         egr_mac_da_profile_entry_t macda;
  29227         egr_mpls_vc_and_swap_label_table_entry_t vc_swap_entry;
  29228         int vc_swap_idx = -1;
  29229 
  29230         if (soc_feature(unit, soc_feature_redirect_nh_to_ecmp_for_mpls_php) &&
  29231             (_BCM_L3_MPLS_PHP ==
  29232             BCM_XGS3_L3_ENT_FLAG(BCM_XGS3_L3_TBL_PTR(unit, next_hop), index))) {
  29233             nh_entry->flags2 |= BCM_L3_FLAGS2_MPLS_PHP;
  29234         }
  29235 
  29236         /* Get Index to MAC-DA-PROFILEm */
  29237         if (soc_feature(unit, soc_feature_mpls_enhanced)) {
  29238             macda_idx = egr_ent->MPLS__MAC_DA_PROFILE_INDEX;
  29239         }
  29240 
  29241         /* Read entry from MAC-DA-PROFILEm */
  29242         BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_MAC_DA_PROFILEm,
  29243                             MEM_BLOCK_ANY, macda_idx, &macda));
  29244 
  29245         /* Obtain Mac-Address */
  29246         soc_mem_mac_addr_get(unit, EGR_MAC_DA_PROFILEm,
  29247                              &macda, MAC_ADDRESSf, nh_entry->mac_addr);
  29248 
  29249         if ((vc_swap_idx > 0) &&
  29250             !soc_feature(unit, soc_feature_th3_style_simple_mpls)) { /* 0th entry is the default */
  29251             /* Read entry from EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm */
  29252             BCM_IF_ERROR_RETURN (soc_mem_read(unit,
  29253                           EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm,
  29254                           MEM_BLOCK_ANY, vc_swap_idx, &vc_swap_entry));
  29255             nh_entry->mpls_label =
  29256             soc_EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm_field32_get(unit,
  29257                                          &vc_swap_entry,
  29258                                          MPLS_LABELf);
  29259         } else {
  29260             nh_entry->mpls_label =
  29261                 (egr_ent->MPLS__MPLS_LABEL_2_19 << 2) |
  29262                 (egr_ent->MPLS__MPLS_LABEL_0_1);
  29263         }
  29264     }
  29265 
  29266     nh_entry->intf_class = egr_ent->L3__CLASS_ID;
  29267 
  29268     /* Get next hop table memory location. */
  29269     mem = BCM_XGS3_L3_MEM(unit, nh);
  29270 
  29271     if (soc_feature(unit, soc_feature_nh_for_ifp_actions) &&
  29272         (0x2 == ent_type) && _BCM_L3_FIELD_ONLY ==
  29273         BCM_XGS3_L3_ENT_FLAG(BCM_XGS3_L3_TBL_PTR(unit, next_hop), index)) {
  29274 
  29275         /* Get mac address. */
  29276         soc_mem_mac_addr_get(unit, EGR_L3_NEXT_HOPm, egr_entry_ptr,
  29277                              IFP_ACTIONS__MAC_ADDRESSf, nh_entry->mac_addr);
  29278 
  29279 
  29280         nh_entry->flags2 |= BCM_L3_FLAGS2_FIELD_ONLY;
  29281 
  29282         if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_VLAN_DISABLEf)) {
  29283             if (soc_mem_field32_get(unit, mem, egr_entry_ptr,
  29284                                     IFP_ACTIONS__L3_UC_VLAN_DISABLEf)) {
  29285                 nh_entry->flags |= BCM_L3_KEEP_VLAN;
  29286             }
  29287         }
  29288 
  29289         if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_TTL_DISABLEf)) {
  29290             if (soc_mem_field32_get(unit, mem, egr_entry_ptr,
  29291                                     IFP_ACTIONS__L3_UC_TTL_DISABLEf)) {
  29292                 nh_entry->flags |= BCM_L3_KEEP_TTL;
  29293             }
  29294         }
  29295 
  29296         if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_DA_DISABLEf)) {
  29297             if (soc_mem_field32_get(unit, mem, egr_entry_ptr,
  29298                                     IFP_ACTIONS__L3_UC_DA_DISABLEf)) {
  29299                 nh_entry->flags |= BCM_L3_KEEP_DSTMAC;
  29300             }
  29301         }
  29302         if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_SA_DISABLEf)) {
  29303             if (soc_mem_field32_get(unit, mem, egr_entry_ptr,
  29304                                     IFP_ACTIONS__L3_UC_SA_DISABLEf)) {
  29305                 nh_entry->flags |= BCM_L3_KEEP_SRCMAC;
  29306             }
  29307         }
  29308     }
  29309     return (BCM_E_NONE);
  29310 }
  29311 
  29312 #endif
  29313 
  29314 /*
  29315  * Function:
  29316  *      _bcm_xgs3_nh_entry_parse
  29317  * Purpose:
  29318  *      Parse the NextHop table entry info.
  29319  * Parameters:
  29320  *      unit          - (IN) SOC unit number.
  29321  *      ing_entry_ptr - (IN) Ingress next hop table entry.
  29322  *      egr_entry_ptr - (IN) Egress next hop table entry.
  29323  *      index         - (IN) Next hop index.
  29324  *      nh_entry      - (OUT) Next hop entry info.
  29325  * Returns:
  29326  *      BCM_E_XXX
  29327  */
  29328 int
  29329 _bcm_xgs3_nh_entry_parse(int unit, uint32 *ing_entry_ptr,
  29330         uint32 *egr_entry_ptr, uint32 *egr_entry_2_ptr, uint32 index, bcm_l3_egress_t *nh_entry, uint8 *nh_ent_type)
  29331 {
  29332     _bcm_l3_nh_fields_t *fld;           /* Next hop table common fields.    */
  29333     uint32 *hw_entry_p;                 /* HW entry buffer pointer.         */
  29334     soc_mem_t mem;                      /* Table location memory.           */
  29335 #ifdef BCM_TOMAHAWK3_SUPPORT
  29336     soc_mem_t mem2;                      /* Table location memory.           */
  29337 #endif
  29338     int mod = 0;                            /* Module id value in hw.           */
  29339     int port = 0;                           /* Port value in hw.                */
  29340     int ent_type = 0;
  29341 #ifdef BCM_KATANA_SUPPORT
  29342     int eh_tag_type = 0;
  29343     int queue_id = 0;
  29344     ing_queue_map_entry_t ing_queue_entry;
  29345 #endif
  29346     _bcm_l3_intf_cfg_t intf_info;
  29347     int ret_val;
  29348 #ifdef BCM_RIOT_SUPPORT
  29349     uint32 nh_dest = 0;
  29350 #endif
  29351     int ing_ent_type = 0;
  29352 
  29353     int l3mc = 0;
  29354 #ifdef BCM_TRIDENT3_SUPPORT
  29355     uint32 dest_type = SOC_MEM_FIF_DEST_INVALID, dest = 0;
  29356     int dvp_gport=0;
  29357 #endif
  29358     soc_field_t entry_type_field = 0;
  29359 
  29360 #ifdef BCM_TOMAHAWK3_SUPPORT
  29361     /* It's ok to use even alpm is off */
  29362     if (SOC_IS_TOMAHAWK3(unit)) {
  29363         return _bcm_xgs3_th3_nh_entry_parse(unit, ing_entry_ptr, egr_entry_ptr,
  29364                     egr_entry_2_ptr, index, nh_entry, nh_ent_type);
  29365     }
  29366 #endif
  29367 
  29368     if (SOC_IS_TRIDENT3X(unit)) {
  29369         entry_type_field = DATA_TYPEf;
  29370     } else {
  29371         entry_type_field = ENTRY_TYPEf;
  29372     }
  29373 
  29374     hw_entry_p = ing_entry_ptr;
  29375 
  29376     /* Zero buffers. */
  29377     bcm_l3_egress_t_init(nh_entry);
  29378 
  29379 
  29380     /* Check if next hop entry type is L3MC */
  29381     if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm, entry_type_field)) {
  29382         if (SOC_IS_TOMAHAWK3(unit)) {
  29383                 if (3 == soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
  29384                         egr_entry_ptr, nh_entry_type_field[unit])) {
  29385                     /* Entry type is L3MC */
  29386                     l3mc = 1;
  29387                 }
  29388         } else if (7 == soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_entry_ptr,
  29389                     nh_entry_type_field[unit])) { /* Entry type is L3MC */
  29390                 l3mc = 1;
  29391         }
  29392     }
  29393 
  29394     /* Check if next hop entry type is L3MC */
  29395     if (l3mc) {
  29396 #ifdef BCM_TRIUMPH3_SUPPORT
  29397             if (soc_feature(unit, soc_feature_repl_l3_intf_use_next_hop)) {
  29398                 return _bcm_tr3_l3_ipmc_nh_entry_parse(unit, ing_entry_ptr,
  29399                         egr_entry_ptr, egr_entry_2_ptr, nh_entry);
  29400             } else
  29401 #endif /* BCM_TRIUMPH3_SUPPORT */
  29402             {
  29403                 /* GH support entry type=7 through the feature at
  29404                  * 'soc_feature_l3mc_use_egress_next_hop' and the flow will
  29405                  * be proceeded later.
  29406                  */
  29407                 if (!soc_feature(unit, soc_feature_l3mc_use_egress_next_hop)) {
  29408                     return BCM_E_UNAVAIL;
  29409                 }
  29410             }
  29411     }
  29412 
  29413     /* Get next hop table memory location. */
  29414     mem = BCM_XGS3_L3_MEM(unit, nh);
  29415 
  29416     /* Extract next hop fields information. */
  29417     fld = (_bcm_l3_nh_fields_t *)BCM_XGS3_L3_MEM_FIELDS(unit, nh);
  29418 
  29419     /* Extract next hop info. */
  29420 
  29421 #ifdef BCM_RIOT_SUPPORT
  29422     if (soc_feature(unit, soc_feature_ing_l3_next_hop_encoded_dest)) {
  29423 
  29424         nh_dest = soc_mem_field32_get(unit, mem, hw_entry_p, DESTINATIONf);
  29425         bcmi_get_port_from_destination(unit, nh_dest, nh_entry);
  29426         if (!(_bcm_vp_is_vfi_type(unit, nh_entry->port)) && 
  29427             (!(nh_entry->flags & BCM_L3_TGID))) {
  29428 
  29429             mod  = BCM_L3_DGLP_MODULE_ID_GET(nh_entry->port);
  29430             port = BCM_L3_DGLP_PORT_GET(nh_entry->port);
  29431         } else {
  29432             mod = 0;
  29433             port = nh_entry->port;
  29434         } 
  29435         nh_entry->port = 0;
  29436     } else 
  29437 #endif
  29438     {
  29439 #ifdef BCM_TRIDENT3_SUPPORT
  29440      if (SOC_IS_TRIDENT3X(unit)) {
  29441          dest = soc_mem_field32_dest_get(unit, mem, hw_entry_p, 
  29442                                          fld->dest, &dest_type);
  29443          if (dest_type == SOC_MEM_FIF_DEST_LAG) {
  29444                 nh_entry->flags |= BCM_L3_TGID;
  29445                 port = (dest & SOC_MEM_FIF_DGPP_TGID_MASK);
  29446          } else if (dest_type == SOC_MEM_FIF_DEST_DGPP) {
  29447                 port = (dest & SOC_MEM_FIF_DGPP_PORT_MASK);
  29448                 mod = (dest & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >>
  29449                          SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS;
  29450          } else if (dest_type == SOC_MEM_FIF_DEST_DVP) {
  29451              _bcm_vp_encode_gport(unit, dest, &dvp_gport);
  29452              nh_entry->port = dvp_gport;
  29453              port  = dvp_gport;
  29454          } else if (dest_type == SOC_MEM_FIF_DEST_IPMC) {
  29455              _BCM_MULTICAST_GROUP_SET(nh_entry->mc_group,
  29456                                       _BCM_MULTICAST_TYPE_L3, dest);
  29457              nh_entry->flags2 |= BCM_L3_FLAGS2_MC_GROUP;
  29458          }
  29459      } else
  29460 #endif
  29461      {
  29462         /* Get port trunk information. */
  29463         if (!SOC_IS_TOMAHAWK3(unit)) {
  29464             mod = soc_mem_field32_get(unit, mem, hw_entry_p, fld->module);
  29465         }
  29466         port = soc_mem_field32_get(unit, mem, hw_entry_p,  fld->port_tgid);
  29467 
  29468     #ifdef BCM_TRX_SUPPORT
  29469         if (soc_feature(unit, soc_feature_trunk_group_overlay)) {
  29470             if (soc_mem_field32_get(unit, mem, hw_entry_p, Tf)) {
  29471                 nh_entry->flags |= BCM_L3_TGID;
  29472                 port = soc_mem_field32_get(unit, mem, hw_entry_p, TGIDf);
  29473             }
  29474         }
  29475     #endif /* BCM_TRX_SUPPORT */
  29476         if (port & BCM_TGID_TRUNK_INDICATOR(unit)) {
  29477             nh_entry->flags |= BCM_L3_TGID;
  29478         }
  29479     }
  29480     }
  29481 
  29482 #ifdef BCM_TRX_SUPPORT
  29483     if (SOC_MEM_FIELD_VALID(unit, mem, COPY_TO_CPUf)) {
  29484         if (soc_mem_field32_get(unit, mem, hw_entry_p, COPY_TO_CPUf)) {
  29485             nh_entry->flags |= BCM_L3_COPY_TO_CPU;
  29486         }
  29487     }
  29488 
  29489     if (SOC_MEM_FIELD_VALID(unit, mem, DROPf)) {
  29490         if (soc_mem_field32_get(unit, mem, hw_entry_p, DROPf)) {
  29491             nh_entry->flags |= BCM_L3_DST_DISCARD;
  29492         }
  29493     }
  29494 
  29495 #endif /* BCM_TRX_SUPPORT */
  29496 
  29497     /* Map module/port to next hop entry format. */
  29498     BCM_IF_ERROR_RETURN
  29499         (_bcm_xgs3_nh_map_hw_data_to_api(unit, port, mod, nh_entry));
  29500 
  29501     if (SOC_MEM_FIELD_VALID(unit, mem, ENTRY_TYPEf)) {
  29502         ing_ent_type = soc_mem_field32_get(unit, mem, hw_entry_p, ENTRY_TYPEf);
  29503     }
  29504     if (!BCM_XGS3_L3_INTF_VLAN_SPLIT_EGRESS_MODE_ISSET(unit) && (ing_ent_type != 2)) {
  29505 #ifdef BCM_FIREBOLT_SUPPORT
  29506         if (SOC_IS_FBX(unit)) {
  29507             /* Get vlan id. */
  29508             nh_entry->vlan = soc_mem_field32_get(unit, mem, hw_entry_p, VLAN_IDf);
  29509         }
  29510 #endif /* BCM_FIREBOLT_SUPPORT */
  29511     }
  29512 
  29513     hw_entry_p = egr_entry_ptr;
  29514     mem = EGR_L3_NEXT_HOPm;
  29515 #ifdef BCM_TOMAHAWK3_SUPPORT
  29516     mem2 = EGR_L3_NEXT_HOP_2m;
  29517 #endif
  29518 
  29519     if (SOC_MEM_FIELD_VALID(unit, mem, nh_entry_type_field[unit])) {
  29520         ent_type = soc_mem_field32_get(unit, mem, hw_entry_p, nh_entry_type_field[unit]);
  29521     }
  29522 #ifdef BCM_TRIDENT3_SUPPORT
  29523     if (soc_feature(unit, soc_feature_flex_flow) &&
  29524         (BCMI_L3_NH_FLEX_VIEW(ent_type))) {
  29525 
  29526         return _bcm_td3_l3_flex_nh_entry_parse(unit, egr_entry_ptr,
  29527                                                index, nh_entry);
  29528     }
  29529 #endif
  29530 
  29531     if (ent_type == 0) { /* L3 Unicast */
  29532 #ifdef BCM_TRIUMPH2_SUPPORT
  29533         if (SOC_MEM_FIELD_VALID(unit, mem, L3__L3_UC_VLAN_DISABLEf)) {
  29534             if (soc_mem_field32_get(unit, mem, hw_entry_p,
  29535                                     L3__L3_UC_VLAN_DISABLEf)) {
  29536                 nh_entry->flags |= BCM_L3_KEEP_VLAN;
  29537             }
  29538         }
  29539 
  29540         if (SOC_MEM_FIELD_VALID(unit, mem, L3__L3_UC_TTL_DISABLEf)) {
  29541             if (soc_mem_field32_get(unit, mem, hw_entry_p,
  29542                                     L3__L3_UC_TTL_DISABLEf)) {
  29543                 nh_entry->flags |= BCM_L3_KEEP_TTL;
  29544             }
  29545         }
  29546 
  29547         if (SOC_MEM_FIELD_VALID(unit, mem, L3__L3_UC_DA_DISABLEf)) {
  29548             if (soc_mem_field32_get(unit, mem, hw_entry_p,
  29549                                     L3__L3_UC_DA_DISABLEf)) {
  29550                 nh_entry->flags |= BCM_L3_KEEP_DSTMAC;
  29551             }
  29552         }
  29553         if (SOC_MEM_FIELD_VALID(unit, mem, L3__L3_UC_SA_DISABLEf)) {
  29554             if (soc_mem_field32_get(unit, mem, hw_entry_p,
  29555                                     L3__L3_UC_SA_DISABLEf)) {
  29556                 nh_entry->flags |= BCM_L3_KEEP_SRCMAC;
  29557             }
  29558         }
  29559 #endif /* BCM_TRIUMPH2_SUPPORT */
  29560     }
  29561 
  29562 #ifdef BCM_TRIDENT_SUPPORT
  29563     if (soc_feature(unit, soc_feature_nh_for_ifp_actions) && 
  29564         (((SOC_IS_TOMAHAWK3(unit)) && (0x2 == ent_type)) || (0x6 == ent_type)) && _BCM_L3_FIELD_ONLY ==
  29565         BCM_XGS3_L3_ENT_FLAG(BCM_XGS3_L3_TBL_PTR(unit, next_hop), index)) {
  29566         uint8  tag_action = 0;
  29567         uint32 tag_buffer = 0;
  29568 
  29569         nh_entry->flags2 |= BCM_L3_FLAGS2_FIELD_ONLY;
  29570 
  29571         if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_VLAN_DISABLEf)) {
  29572             if (soc_mem_field32_get(unit, mem, hw_entry_p,
  29573                                     IFP_ACTIONS__L3_UC_VLAN_DISABLEf)) {
  29574                 nh_entry->flags |= BCM_L3_KEEP_VLAN;
  29575             }
  29576         }
  29577 
  29578         if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_TTL_DISABLEf)) {
  29579             if (soc_mem_field32_get(unit, mem, hw_entry_p,
  29580                                     IFP_ACTIONS__L3_UC_TTL_DISABLEf)) {
  29581                 nh_entry->flags |= BCM_L3_KEEP_TTL;
  29582             }
  29583         }
  29584 
  29585         if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_DA_DISABLEf)) {
  29586             if (soc_mem_field32_get(unit, mem, hw_entry_p,
  29587                                     IFP_ACTIONS__L3_UC_DA_DISABLEf)) {
  29588                 nh_entry->flags |= BCM_L3_KEEP_DSTMAC;
  29589             }
  29590         }
  29591         if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_SA_DISABLEf)) {
  29592             if (soc_mem_field32_get(unit, mem, hw_entry_p,
  29593                                     IFP_ACTIONS__L3_UC_SA_DISABLEf)) {
  29594                 nh_entry->flags |= BCM_L3_KEEP_SRCMAC;
  29595             }
  29596         }            
  29597 
  29598         if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__VNTAGf)) {
  29599             tag_buffer = soc_mem_field32_get(unit, mem, hw_entry_p,
  29600                                              IFP_ACTIONS__VNTAGf);
  29601         }
  29602 
  29603         if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__VNTAG_ACTIONf)) {
  29604             tag_action = soc_mem_field32_get(unit, mem, hw_entry_p,
  29605                                              IFP_ACTIONS__VNTAG_ACTIONf);
  29606             if (tag_action == 1) {
  29607                 nh_entry->vntag.direction = (tag_buffer >> 31) & 0x1;
  29608                 nh_entry->vntag.pointer   = (tag_buffer >> 30) & 0x1;
  29609                 nh_entry->vntag.dst_vif   = (tag_buffer >> 16) & 0x3fff;
  29610                 nh_entry->vntag.loop      = (tag_buffer >> 15) & 0x1;
  29611                 nh_entry->vntag.src_vif   = tag_buffer & 0xfff;
  29612                 nh_entry->vntag_action    = bcmVnTagActionChange;
  29613             } else if (tag_action == 2) {
  29614                 nh_entry->etag.pcp        = (tag_buffer >> 29) & 0x7;
  29615                 nh_entry->etag.de         = (tag_buffer >> 28) & 0x1;
  29616                 nh_entry->etag.src_vid    = (tag_buffer >> 16) & 0xfff;
  29617                 nh_entry->etag.vid        = tag_buffer & 0x3fff;
  29618                 nh_entry->etag_action     = bcmETagActionChange;
  29619             } else if (tag_action == 3) {
  29620                 if (tag_buffer == 0) {
  29621                     nh_entry->vntag_action = bcmVnTagActionDelete;
  29622                 } else {
  29623                     nh_entry->etag_action = bcmETagActionDelete;
  29624                 }
  29625             }
  29626         }
  29627 
  29628 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
  29629         if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__SWAP_MAC_DA_SAf)) {
  29630             if (soc_mem_field32_get(unit, mem, hw_entry_p,
  29631                                     IFP_ACTIONS__SWAP_MAC_DA_SAf)) {
  29632                 nh_entry->flags2 |= BCM_L3_FLAGS2_SRC_DST_MAC_SWAP;
  29633                 nh_entry->flags &= ~BCM_L3_KEEP_DSTMAC;
  29634                 nh_entry->flags &= ~BCM_L3_KEEP_SRCMAC;
  29635             }
  29636         }
  29637 #endif /* BCM_TRIDENT2PLUS_SUPPORT */
  29638     }
  29639 #endif    
  29640 
  29641     /* Get interface index. */
  29642 #ifdef BCM_TOMAHAWK3_SUPPORT
  29643     if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m) && egr_entry_2_ptr) {
  29644         nh_entry->intf =
  29645            soc_mem_field32_get(unit, mem2, egr_entry_2_ptr, fld->ifindex);
  29646     } else
  29647 #endif
  29648     {
  29649         nh_entry->intf =
  29650            soc_mem_field32_get(unit, mem, hw_entry_p, fld->ifindex);
  29651     }
  29652     if (SOC_MEM_FIELD_VALID(unit, mem, MPLS__MEPIDf)) {
  29653         nh_entry->oam_global_context_id =
  29654             soc_mem_field32_get(unit, mem, hw_entry_p,
  29655                     MPLS__MEPIDf);
  29656     }
  29657     if (nh_entry->intf == BCM_XGS3_L3_L2CPU_INTF_IDX(unit)) {
  29658         nh_entry->flags |= BCM_L3_L2TOCPU;
  29659     }
  29660 
  29661 #ifdef BCM_TRX_SUPPORT
  29662     if (SOC_MEM_FIELD_VALID(unit, mem, entry_type_field)) {
  29663         /*
  29664          * Entry type is SD TAG actions.
  29665          * no interface is associated with it.
  29666          * Mark the interface as 0.
  29667          * else it picks up some random value and tries to look for it.
  29668          */
  29669         if (soc_mem_field32_get(unit, mem, hw_entry_p, entry_type_field) == 2) {
  29670             nh_entry->intf = 0;
  29671         }
  29672     }
  29673 #endif
  29674 
  29675     if (BCM_XGS3_L3_INTF_VLAN_SPLIT_EGRESS_MODE_ISSET(unit) || (ing_ent_type == 2)) {
  29676         /* Now get the vlan */
  29677         sal_memset(&intf_info, 0x0, sizeof(intf_info));
  29678         intf_info.l3i_index = nh_entry->intf;
  29679 
  29680         if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_get)) {
  29681             BCM_XGS3_L3_MODULE_LOCK(unit);
  29682             ret_val = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit,
  29683                                                              &intf_info);
  29684             BCM_XGS3_L3_MODULE_UNLOCK(unit);
  29685             BCM_IF_ERROR_RETURN(ret_val);
  29686             nh_entry->vlan = intf_info.l3i_vid;
  29687         }
  29688     }
  29689 
  29690     /* Get mac address. */
  29691     soc_mem_mac_addr_get(unit, mem, hw_entry_p,
  29692                          fld->mac_addr, nh_entry->mac_addr);
  29693 
  29694 #ifdef BCM_TRX_SUPPORT
  29695     if (SOC_MEM_FIELD_VALID(unit, mem, entry_type_field)) {
  29696          int macda_idx;
  29697          egr_mac_da_profile_entry_t macda;
  29698          egr_mpls_vc_and_swap_label_table_entry_t vc_swap_entry;
  29699          int entry_type;
  29700          int vc_swap_idx = -1;
  29701 
  29702          entry_type = soc_mem_field32_get(unit, mem, hw_entry_p, entry_type_field);
  29703          if (nh_ent_type) {
  29704              *nh_ent_type = (uint8)entry_type;
  29705          }
  29706          if (entry_type == 0) { /* L3 unicast */
  29707 #ifdef BCM_TRIDENT2_SUPPORT
  29708              if (soc_feature(unit, soc_feature_virtual_port_routing)) {
  29709                  bcm_if_t encap_id = soc_mem_field32_get(unit, mem,
  29710                                             hw_entry_p, L3__DVPf);
  29711                  if (soc_mem_field_valid(unit, mem, L3__DVP_VALIDf)) {
  29712                      if (soc_mem_field32_get(unit, mem, hw_entry_p, L3__DVP_VALIDf)) {
  29713                          nh_entry->encap_id = encap_id;
  29714                      }
  29715                  } else {
  29716                     /* TD2+ onwards, the DVP_VALID bit is implicit to DVP..
  29717                        Zero = invalid, Non-Zero = valid */
  29718                     nh_entry->encap_id = encap_id;
  29719                  }
  29720 
  29721                  if (soc_mem_field_valid(unit, mem, L3__HG_HDR_SELf)) {
  29722                      if (!_bcm_vp_used_get(unit, nh_entry->encap_id, _bcmVpTypeNiv) &&
  29723                          !_bcm_vp_used_get(unit, nh_entry->encap_id, _bcmVpTypeExtender) &&
  29724                          !_bcm_vp_used_get(unit, nh_entry->encap_id, _bcmVpTypeVlan) &&
  29725                          !_bcm_vp_used_get(unit, nh_entry->encap_id, _bcmVpTypeMpls) &&
  29726                          soc_mem_field32_get(unit, mem, hw_entry_p, L3__HG_HDR_SELf)) {
  29727                          nh_entry->flags2 |= BCM_L3_FLAGS2_NON_PROXY_MODE;
  29728                      }
  29729                  }
  29730              }
  29731 #endif /* BCM_TRIDENT2_SUPPORT */
  29732          } else if (entry_type == 0x1) { /* == MPLS_MACDA_PROFILE */
  29733 
  29734              if (soc_feature(unit, soc_feature_redirect_nh_to_ecmp_for_mpls_php) &&
  29735                  (_BCM_L3_MPLS_PHP ==
  29736                   BCM_XGS3_L3_ENT_FLAG(BCM_XGS3_L3_TBL_PTR(unit, next_hop), index))) {
  29737                   nh_entry->flags2 |= BCM_L3_FLAGS2_MPLS_PHP;
  29738              }
  29739 
  29740               /* Get Index to MAC-DA-PROFILEm */
  29741              if (soc_feature(unit, soc_feature_mpls_enhanced)) {
  29742                  macda_idx = soc_mem_field32_get(unit, mem, hw_entry_p,
  29743                                   MPLS__MAC_DA_PROFILE_INDEXf);
  29744                  if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm, MPLS__VC_AND_SWAP_INDEXf)) {
  29745                      vc_swap_idx = soc_mem_field32_get(unit, mem, hw_entry_p,
  29746                                       MPLS__VC_AND_SWAP_INDEXf);
  29747                  }
  29748              } else {
  29749                  macda_idx = soc_mem_field32_get(unit, mem, hw_entry_p,
  29750                                   MAC_DA_PROFILE_INDEXf);
  29751                  vc_swap_idx = soc_mem_field32_get(unit, mem, hw_entry_p,
  29752                                   VC_AND_SWAP_INDEXf);
  29753              }
  29754 
  29755               /* Read entry from MAC-DA-PROFILEm */
  29756              BCM_IF_ERROR_RETURN (soc_mem_read(unit, EGR_MAC_DA_PROFILEm,
  29757                                   MEM_BLOCK_ANY, macda_idx, &macda));
  29758 
  29759               /* Obtain Mac-Address */
  29760               soc_mem_mac_addr_get(unit, EGR_MAC_DA_PROFILEm,
  29761                                   &macda, MAC_ADDRESSf, nh_entry->mac_addr);
  29762 
  29763              if ((vc_swap_idx > 0) &&
  29764                  !soc_feature(unit, soc_feature_th3_style_simple_mpls)) { /* 0th entry is the default */
  29765                  /* Read entry from EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm */
  29766                  BCM_IF_ERROR_RETURN (soc_mem_read(unit,
  29767                                   EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm,
  29768                                   MEM_BLOCK_ANY, vc_swap_idx, &vc_swap_entry));
  29769                  nh_entry->mpls_label =
  29770                   soc_EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm_field32_get(unit,
  29771                                                  &vc_swap_entry,
  29772                                                  MPLS_LABELf);
  29773              } else if (soc_feature(unit, soc_feature_th3_style_simple_mpls)) {
  29774                  nh_entry->mpls_label =
  29775                   soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
  29776                                                  egr_entry_ptr,
  29777                                                  MPLS__MPLS_LABELf);
  29778              }
  29779 
  29780 
  29781          } else if (entry_type == 0x4) { /* == WLAN PROFILE */
  29782 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
  29783              if (soc_feature(unit, soc_feature_wlan)) {
  29784                  nh_entry->encap_id = soc_mem_field32_get(unit, mem,
  29785                          hw_entry_p, WLAN__DVPf);
  29786              }
  29787 #endif /* TRIUMPH2_SUPPORT || TRIUMPH3_SUPPORT */
  29788         }
  29789 #ifdef BCM_GREYHOUND2_SUPPORT
  29790         if (soc_feature(unit, soc_feature_vxlan_lite)) {
  29791             if (entry_type == 0xa) {
  29792                 /* Get Index to MAC-DA-PROFILEm */
  29793                 macda_idx = soc_mem_field32_get(unit, mem, hw_entry_p,
  29794                                                 VXLAN__MAC_DA_PROFILE_INDEXf);
  29795                 /* Read entry from MAC-DA-PROFILEm */
  29796                 BCM_IF_ERROR_RETURN (soc_mem_read(unit, EGR_MAC_DA_PROFILEm,
  29797                                      MEM_BLOCK_ANY, macda_idx, &macda));
  29798                 /* Obtain Mac-Address */
  29799                 soc_mem_mac_addr_get(unit, EGR_MAC_DA_PROFILEm,
  29800                                      &macda, MAC_ADDRESSf, nh_entry->mac_addr);
  29801             }
  29802         }
  29803 #endif /* BCM_GREYHOUND2_SUPPORT */
  29804 
  29805 #ifdef BCM_GREYHOUND_SUPPORT
  29806         if (soc_feature(unit, soc_feature_l3mc_use_egress_next_hop)) {
  29807             if (entry_type == 0x7) { /* == L3MC */
  29808                 nh_entry->flags |= BCM_L3_IPMC;
  29809 
  29810                 if (!(soc_mem_field32_get(unit, mem, hw_entry_p,
  29811                         L3MC__L3MC_USE_CONFIGURED_MACf))) {
  29812                     nh_entry->flags |= BCM_L3_KEEP_DSTMAC;
  29813                 }
  29814 
  29815                 /* MAC Addr field need be re-programmed for L3MC entry type.
  29816                 *
  29817                 * Note : the reason for MAC Addr re-program
  29818                 *   MAC Addr field in GH's EGR_L3_NEXT_HOP entry at L3MC view
  29819                 *   is not compatiable with toher entry type.
  29820                 */
  29821                 soc_mem_mac_addr_get(unit, mem, hw_entry_p,
  29822                         L3MC__MAC_ADDRESSf, nh_entry->mac_addr);
  29823             }
  29824         }
  29825 #endif /* BCM_GREYHOUND_SUPPORT */
  29826     }
  29827 
  29828 #ifdef BCM_TRIUMPH3_SUPPORT
  29829     if (SOC_MEM_FIELD_VALID(unit, mem, L3__CLASS_IDf)) {
  29830         nh_entry->intf_class =
  29831                  soc_mem_field32_get(unit, mem, hw_entry_p, L3__CLASS_IDf);
  29832     }
  29833 #endif /* BCM_TRIUMPH3_SUPPORT */
  29834 
  29835 #endif /* BCM_TRX_SUPPORT */
  29836 
  29837 #ifdef BCM_TOMAHAWK_SUPPORT
  29838     if (soc_feature(unit, soc_feature_virtual_port_routing)) {
  29839         if (nh_entry->encap_id > 0 &&
  29840             nh_entry->encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit)) {
  29841             if (_bcm_vp_used_get(unit, nh_entry->encap_id, _bcmVpTypeNiv) ||
  29842                 _bcm_vp_used_get(unit, nh_entry->encap_id,
  29843                 _bcmVpTypeExtender)) {
  29844                 if (SOC_MEM_FIELD_VALID(unit, mem, L3__HG_VNTAG_MODIFY_ENABLEf)) {
  29845                     if (soc_mem_field32_get(unit, mem, hw_entry_p,
  29846                         L3__HG_VNTAG_MODIFY_ENABLEf)) {
  29847                         nh_entry->flags2 |= BCM_L3_FLAGS2_NIV_ENCAP_LOCAL;
  29848                     }
  29849                 }
  29850             }
  29851         }
  29852     }
  29853 #endif /* BCM_TOMAHAWK_SUPPORT */
  29854 
  29855 #ifdef BCM_KATANA_SUPPORT
  29856     if (soc_feature(unit, soc_feature_extended_queueing)) {
  29857         mem = BCM_XGS3_L3_MEM(unit, nh);
  29858         queue_id = soc_mem_field32_get(unit, mem, ing_entry_ptr,
  29859                                                           EH_QUEUE_TAGf);
  29860         if (SOC_MEM_FIELD_VALID(unit, mem, EH_TAG_TYPEf)) {
  29861             eh_tag_type = soc_mem_field32_get(unit, mem, ing_entry_ptr,
  29862                                                              EH_TAG_TYPEf);
  29863             if (eh_tag_type == EH_TAG_TYPE_ING_QUEUE_MAP) {
  29864                 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, ING_QUEUE_MAPm,
  29865                                              queue_id, &ing_queue_entry));
  29866                 nh_entry->qos_map_id =
  29867                              soc_mem_field32_get(unit, ING_QUEUE_MAPm,
  29868                                  &ing_queue_entry, QUEUE_OFFSET_PROFILE_INDEXf);
  29869                 nh_entry->flags |= BCM_L3_QUEUE_MAP;
  29870 
  29871                 queue_id = soc_mem_field32_get(unit, ING_QUEUE_MAPm,
  29872                                  &ing_queue_entry, QUEUE_SET_BASEf);
  29873             }
  29874             if ((eh_tag_type == EH_TAG_TYPE_EXPLICT_QUEUE) ||
  29875                 (eh_tag_type == EH_TAG_TYPE_ING_QUEUE_MAP)) {
  29876                 nh_entry->qos_map_id |= (5 << 10);
  29877             }
  29878         }
  29879     }
  29880 #endif /* BCM_KATANA_SUPPORT */
  29881 
  29882 #ifdef BCM_TRIDENT2_SUPPORT
  29883         if (soc_feature(unit, soc_feature_fcoe) &&
  29884             (ent_type == 0x8) && (_BCM_L3_FCOE_ONLY ==
  29885             BCM_XGS3_L3_ENT_FLAG(BCM_XGS3_L3_TBL_PTR(unit, next_hop), index))) {
  29886             nh_entry->flags2 |= BCM_L3_FLAGS2_FCOE_ONLY;
  29887         }
  29888 #endif
  29889 
  29890     return (BCM_E_NONE);
  29891 }
  29892 /*
  29893  * Function:
  29894  *      _bcm_xgs3_nh_get
  29895  * Purpose:
  29896  *        Read the NextHop table info given index.
  29897  * Parameters:
  29898  *      unit      - (IN) SOC unit number.
  29899  *      idx       - (IN) Table index to read.
  29900  *      nh_entry  - (OUT) Next hop entry info.
  29901  * Returns:
  29902  *      BCM_E_XXX
  29903  */
  29904 STATIC int
  29905 _bcm_xgs3_nh_get(int unit, int idx, bcm_l3_egress_t *nh_entry)
  29906 {
  29907     uint32 hw_entry[SOC_MAX_MEM_WORDS];  /* Buffer to fill nh entry.   */
  29908     uint32 hw_entry_null[SOC_MAX_MEM_WORDS];  /* Buffer to fill nh entry.   */
  29909     egr_l3_next_hop_entry_t  egr_entry;        /* Egress next hop entry.     */
  29910     egr_l3_next_hop_entry_t  egr_entry_null;        /* Egress next hop entry.     */
  29911     int found_null_entry = 0;
  29912     egr_l3_next_hop_2_entry_t egr_entry_2;
  29913 
  29914     /* Input parameters check */
  29915     if (NULL == nh_entry) {
  29916         return (BCM_E_PARAM);
  29917     }
  29918 
  29919     /* Zero buffers. */
  29920     sal_memset(hw_entry, 0, WORDS2BYTES(SOC_MAX_MEM_WORDS));
  29921     sal_memset(hw_entry_null, 0, WORDS2BYTES(SOC_MAX_MEM_WORDS));
  29922     sal_memset(&egr_entry_null, 0, sizeof(egr_entry_null));
  29923 
  29924     /* Read ingress next hop entry. */
  29925     BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, BCM_XGS3_L3_MEM(unit, nh),
  29926                                           idx, &hw_entry));
  29927 
  29928 #ifdef BCM_FIREBOLT_SUPPORT
  29929     if (SOC_IS_FBX(unit)) {
  29930         sal_memset(&egr_entry, 0, sizeof(egr_l3_next_hop_entry_t));
  29931 
  29932         /*  Read egress next hop entry. */
  29933         BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, EGR_L3_NEXT_HOPm,
  29934                                               idx, &egr_entry));
  29935 
  29936 #ifdef BCM_TOMAHAWK3_SUPPORT
  29937     if (SOC_IS_TOMAHAWK3(unit)) {
  29938         sal_memset(&egr_entry_2, 0, sizeof(egr_l3_next_hop_2_entry_t));
  29939         BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, EGR_L3_NEXT_HOP_2m,
  29940                                               idx, &egr_entry_2));
  29941     }
  29942 #endif
  29943        /* Now compare whether both the entries are null */
  29944        if (!sal_memcmp(hw_entry, hw_entry_null, BCM_XGS3_L3_ENT_SZ(unit, nh)) &&
  29945            !sal_memcmp(&egr_entry, &egr_entry_null, sizeof(egr_entry))) {
  29946            found_null_entry = 1;
  29947        }
  29948     }
  29949 #endif /* BCM_FIREBOLT_SUPPORT */
  29950     if (found_null_entry == 0) {
  29951         BCM_IF_ERROR_RETURN(
  29952             _bcm_xgs3_nh_entry_parse(unit, (uint32 *)&hw_entry,
  29953                                      (uint32 *)&egr_entry, (uint32 *)&egr_entry_2, idx, nh_entry, NULL));
  29954     } else {
  29955         bcm_l3_egress_t_init(nh_entry);
  29956     }
  29957     return (BCM_E_NONE);
  29958 }
  29959 
  29960 /*
  29961  * Function:
  29962  *      _bcm_xgs3_nh_del
  29963  * Purpose:
  29964  *      Delete next hop entry from the chip.
  29965  * Parameters:
  29966  *      unit      - (IN)SOC unit number.
  29967  *      idx       - (IN)Deleted entry index.
  29968  * Returns:
  29969  *    BCM_E_XXX
  29970  */
  29971 STATIC int
  29972 _bcm_xgs3_nh_del(int unit, int idx, void *info)
  29973 {
  29974     uint32 hw_entry[SOC_MAX_MEM_WORDS];/* Buffer to fill nh entry.   */
  29975     soc_mem_t mem;                           /* Table memory.              */
  29976     int rv;                                  /* Operation return status.   */
  29977     int first_error = BCM_E_NONE;            /* First error occured.       */
  29978 
  29979     /* Get table memory. */
  29980     mem = BCM_XGS3_L3_MEM(unit, nh);
  29981 #ifdef BCM_RIOT_SUPPORT
  29982     if (BCMI_RIOT_IS_ENABLED(unit)) {
  29983             BCM_IF_ERROR_RETURN(bcmi_l3_nh_assoc_ol_ul_link_delete(unit, idx));
  29984         }
  29985 #endif
  29986 #if defined(BCM_TOMAHAWK_SUPPORT)
  29987     if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
  29988         BCM_IF_ERROR_RETURN(_bcm_th_ipmc_l3_intf_next_hop_l3_egress_clear(unit, idx));
  29989     }
  29990 #endif
  29991 #if defined(BCM_TOMAHAWK_SUPPORT)
  29992     if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
  29993         BCM_IF_ERROR_RETURN(_bcm_th_ipmc_l3_intf_next_hop_l3_egress_clear(unit, idx));
  29994     }
  29995 #endif
  29996 #if defined(BCM_TRIDENT3_SUPPORT)
  29997     /* Release MAC_DA_PROFILE if used */
  29998     if (soc_feature(unit, soc_feature_large_scale_nat)) {
  29999         BCM_IF_ERROR_RETURN(
  30000             bcm_td3_ipmc_egr_nh_mac_da_profile_entry_delete(unit, idx));
  30001     }
  30002 #endif /* BCM_TRIDENT3_SUPPORT */
  30003 
  30004     /* Zero write buffer. */
  30005     sal_memset(&hw_entry, 0, SOC_MAX_MEM_WORDS *sizeof(uint32));
  30006 
  30007     /* Write next hop entry. */
  30008     rv = BCM_XGS3_MEM_WRITE(unit, mem, idx, &hw_entry);
  30009     if (rv < 0) {
  30010         first_error = rv;
  30011     }
  30012 
  30013 #ifdef BCM_FIREBOLT_SUPPORT
  30014     if (SOC_IS_FBX(unit)) {
  30015         /* Write egress next hop entry. */
  30016         mem = EGR_L3_NEXT_HOPm;
  30017         rv = BCM_XGS3_MEM_WRITE(unit, mem, idx, &hw_entry);
  30018         if ((rv < 0) && (first_error == BCM_E_NONE)) {
  30019             first_error = rv;
  30020         }
  30021 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \
  30022         defined(BCM_TRX_SUPPORT)
  30023         /* Write initial next hop table. */
  30024         mem = INITIAL_ING_L3_NEXT_HOPm;
  30025         if (!SOC_MEM_IS_VALID(unit, mem) || !soc_mem_index_max(unit, mem)) {
  30026             return (first_error);
  30027         }
  30028 
  30029         /* Write buffer to hw. */
  30030         rv = BCM_XGS3_MEM_WRITE(unit, mem, idx, &hw_entry);
  30031         if ((rv < 0) && (first_error == BCM_E_NONE)) {
  30032             first_error = rv;
  30033         }
  30034 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */
  30035     }
  30036 #endif /* BCM_FIREBOLT_SUPPORT */
  30037 
  30038     return first_error;
  30039 }
  30040 
  30041 /*
  30042  * Function:
  30043  *      _bcm_xgs3_nh_update_match
  30044  * Purpose:
  30045  *      Update/Show/Delete all entries in nh table matching a certain rule.
  30046  * Parameters:
  30047  *      unit     - (IN)SOC unit number.
  30048  *      trv_data - (IN)Delete pattern + compare,act,notify routines.
  30049  * Returns:
  30050  *      BCM_E_XXX
  30051  */
  30052 STATIC int
  30053 _bcm_xgs3_nh_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data)
  30054 {
  30055     bcm_l3_egress_t nh_entry;     /* Next hop entry info.           */
  30056     uint32 *ing_entry_ptr;        /* Ingress next hop entry pointer.*/
  30057     char *ing_tbl_ptr;            /* Dma table pointer.             */
  30058     int cmp_result;               /* Test routine result.           */
  30059     soc_mem_t mem, nhmem;         /* Next hop memory.               */
  30060     int idx;                      /* Iteration index.               */
  30061 #ifdef BCM_FIREBOLT_SUPPORT
  30062     char *egr_tbl_ptr = NULL;            /* Dma egress nh table pointer.   */
  30063 #ifdef BCM_TOMAHAWK3_SUPPORT
  30064     char *egr_tbl_2_ptr = NULL;            /* Dma egress nh table pointer.   */
  30065 #endif
  30066 #endif /* BCM_FIREBOLT_SUPPORT */
  30067     uint32 *egr_entry_ptr = NULL; /* Egress next hop entry pinter.  */
  30068     uint32 *egr_entry_2_ptr = NULL; /* Egress next hop entry pinter.  */
  30069     int rv = BCM_E_NONE;          /* Operation return status.       */
  30070 
  30071     /* Get next table memory. */
  30072     mem = BCM_XGS3_L3_MEM(unit, nh);
  30073     nhmem = EGR_L3_NEXT_HOPm;
  30074 
  30075     /* Table DMA the nhtable to software copy */
  30076     BCM_IF_ERROR_RETURN
  30077         (bcm_xgs3_l3_tbl_dma(unit, mem, BCM_XGS3_L3_ENT_SZ(unit, nh), "nh_tbl",
  30078                              &ing_tbl_ptr, NULL));
  30079 
  30080 #ifdef BCM_FIREBOLT_SUPPORT
  30081     if (SOC_IS_FBX(unit)) {
  30082         /*  Read egress next hop entry. */
  30083         rv = bcm_xgs3_l3_tbl_dma(unit, nhmem,
  30084                                  sizeof(egr_l3_next_hop_entry_t), "egr_nh_tbl",
  30085                                  &egr_tbl_ptr, NULL);
  30086         if (rv < 0) {
  30087             soc_cm_sfree(unit, egr_tbl_ptr);
  30088             return rv;
  30089         }
  30090 
  30091 #ifdef BCM_TOMAHAWK3_SUPPORT
  30092         if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) {
  30093             /*  Read egress next hop entry. */
  30094             rv = bcm_xgs3_l3_tbl_dma(unit, EGR_L3_NEXT_HOP_2m,
  30095                                      sizeof(egr_l3_next_hop_2_entry_t), "egr_nh_tbl",
  30096                                      &egr_tbl_2_ptr, NULL);
  30097 
  30098             if (rv < 0) {
  30099                 soc_cm_sfree(unit, egr_tbl_2_ptr);
  30100                 return rv;
  30101             }
  30102         }
  30103 #endif
  30104 
  30105     }
  30106 #endif /* BCM_FIREBOLT_SUPPORT */
  30107 
  30108     for (idx = 0; idx < BCM_XGS3_L3_NH_TBL_SIZE(unit); idx++) {
  30109         /* Skip unused entries. */
  30110         if (!BCM_XGS3_L3_ENT_REF_CNT (BCM_XGS3_L3_TBL_PTR(unit, next_hop),
  30111                                       idx)) {
  30112             continue;
  30113         }
  30114 
  30115         /* Skip trap to CPU entry internally installed entry. */
  30116         if (BCM_XGS3_L3_L2CPU_NH_IDX(unit) == idx) {
  30117             continue;
  30118         }
  30119 
  30120         /* Skip BLACK_HOLE entry internally installed entry. */
  30121         if (BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit) == idx) {
  30122             continue;
  30123         }
  30124 
  30125         /* Calculate entry ofset. */
  30126         ing_entry_ptr =
  30127             soc_mem_table_idx_to_pointer(unit, mem, uint32 *, ing_tbl_ptr, idx);
  30128 
  30129 #ifdef BCM_FIREBOLT_SUPPORT
  30130         if (SOC_IS_FBX(unit)) {
  30131             int entry_type;
  30132 
  30133             /*  Read egress next hop entry. */
  30134             egr_entry_ptr =
  30135                 soc_mem_table_idx_to_pointer(unit, nhmem,
  30136                                              uint32 *, egr_tbl_ptr, idx);
  30137 #ifdef BCM_TOMAHAWK3_SUPPORT
  30138             if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) {
  30139                 egr_entry_2_ptr =
  30140                     soc_mem_table_idx_to_pointer(unit, EGR_L3_NEXT_HOP_2m,
  30141                                                  uint32 *, egr_tbl_2_ptr, idx);
  30142             }
  30143 #endif
  30144              if (SOC_MEM_FIELD_VALID(unit, nhmem, nh_entry_type_field[unit])) {
  30145                 entry_type = soc_mem_field32_get(unit, nhmem,
  30146                         egr_entry_ptr, nh_entry_type_field[unit]);
  30147                 if (entry_type == 0 || entry_type == 1 || entry_type == 7 ||
  30148                     (entry_type == 4 && soc_feature(unit, soc_feature_wlan)) ||
  30149 #ifdef BCM_TRIDENT3_SUPPORT
  30150                     (BCMI_L3_NH_FLEX_VIEW(entry_type) &&
  30151                      soc_feature(unit, soc_feature_flex_flow)) ||
  30152 #endif
  30153 #ifdef BCM_TOMAHAWK3_SUPPORT
  30154                     ((SOC_IS_TOMAHAWK3(unit)) && ((entry_type == 3) ||
  30155                                                 (entry_type == 2))) ||
  30156 #endif
  30157                     (entry_type == 6 && _BCM_L3_FIELD_ONLY ==
  30158                      BCM_XGS3_L3_ENT_FLAG(
  30159                          BCM_XGS3_L3_TBL_PTR(unit, next_hop), idx)) ||
  30160                     (entry_type == 8 && _BCM_L3_FCOE_ONLY ==
  30161                      BCM_XGS3_L3_ENT_FLAG(
  30162                          BCM_XGS3_L3_TBL_PTR(unit, next_hop), idx)) ||
  30163                      entry_type == 10) {
  30164                     /* Valid entry types for L3 egress object are L3UC, MPLS,
  30165                      * WLAN, and L3MC.
  30166                      */
  30167                     if (entry_type == 7
  30168                         && SOC_MEM_FIELD_VALID(unit, nhmem,
  30169                                                L3MC__VNTAG_ACTIONSf)
  30170                         && soc_mem_field32_get(unit, nhmem,
  30171                                 egr_entry_ptr, L3MC__VNTAG_ACTIONSf) == 1) {
  30172                         int share_vp = 0;
  30173                         soc_field_t rsvd_fld = L3MC__RSVD_DVPf;
  30174                         if (SOC_IS_TRIDENT3X(unit)) {
  30175                             rsvd_fld = L3MC__RESERVED_1f;
  30176                         }
  30177 
  30178                         /* Exclude the case: L3 NIV multicast egress object on
  30179                          * a shared VP. Use a useless field for NIV to indicate
  30180                          * those egress objects on a shared VP.
  30181                          */
  30182                         if (SOC_MEM_FIELD_VALID(unit, nhmem, rsvd_fld) &&
  30183                             soc_mem_field32_get(unit, nhmem, egr_entry_ptr,
  30184                                                 rsvd_fld)) {
  30185                             share_vp = 1;
  30186                         }
  30187 
  30188                         if (share_vp) {
  30189                             continue;
  30190                         }
  30191                     }
  30192                 } else {
  30193                     continue;
  30194                 }
  30195             }
  30196         }
  30197 #endif /* BCM_FIREBOLT_SUPPORT */
  30198         /* coverity[var_deref_model : FALSE] */
  30199         _bcm_xgs3_nh_entry_parse(unit, ing_entry_ptr, egr_entry_ptr, egr_entry_2_ptr, idx, 
  30200                                  &nh_entry, NULL);
  30201 
  30202 #ifdef BCM_TRIUMPH3_SUPPORT
  30203 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  30204         if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
  30205             if (!BCM_GPORT_IS_SET(nh_entry.port)) {
  30206             BCM_IF_ERROR_RETURN
  30207                 (bcm_th2_l3_egress_dlb_attr_get(unit, idx, &nh_entry));
  30208             }
  30209         } else
  30210 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/
  30211         {
  30212             if (soc_feature(unit, soc_feature_ecmp_dlb)) {
  30213                 bcm_tr3_l3_egress_dlb_attr_get(unit, idx, &nh_entry);
  30214             }
  30215         }
  30216 #endif /* BCM_TRIUMPH3_SUPPORT */
  30217 
  30218         /* Execute operation routine if any. */
  30219         if (trv_data->op_cb) {
  30220             rv = (*trv_data->op_cb)(unit, (void *)trv_data,
  30221                                     (void *)&nh_entry,(void *)&idx, &cmp_result);
  30222 
  30223             if (rv < 0) {
  30224 #ifdef BCM_CB_ABORT_ON_ERR
  30225                 if (SOC_CB_ABORT_ON_ERR(unit)) {
  30226                     break;
  30227                 }
  30228 #endif
  30229             }
  30230         }
  30231     }
  30232     soc_cm_sfree(unit, ing_tbl_ptr);
  30233 #ifdef BCM_FIREBOLT_SUPPORT
  30234     if (SOC_IS_FBX(unit)) {
  30235         soc_cm_sfree(unit, egr_tbl_ptr);
  30236     }
  30237 #ifdef BCM_TOMAHAWK3_SUPPORT
  30238     if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) {
  30239         soc_cm_sfree(unit, egr_tbl_2_ptr);
  30240     }
  30241 #endif
  30242 
  30243 #endif /* BCM_FIREBOLT_SUPPORT */
  30244     return (rv);
  30245 }
  30246 
  30247 /*
  30248  * Function:
  30249  *      _bcm_xgs3_l3_ent_init
  30250  * Purpose:
  30251  *      Service routine used to init hw l3 entry
  30252  * Parameters:
  30253  *      unit      - (IN)SOC unit number.
  30254  *      mem       - (IN)L3 table memory.
  30255  *      l3cfg     - (IN/OUT)l3 entry  lookup key & search result.
  30256  *      l3x_entry - (IN)hw buffer.
  30257  * Returns:
  30258  *      void
  30259  */
  30260 STATIC void
  30261 _bcm_xgs3_l3_ent_init(int unit, soc_mem_t mem,
  30262                       _bcm_l3_cfg_t *l3cfg, void *l3x_entry)
  30263 {
  30264     _bcm_l3_fields_t *fld;        /* L3 table common fields.     */
  30265     uint32 *buf_p;                /* HW buffer address.          */
  30266     int ipv6;                     /* Entry is IPv6 flag.         */
  30267 
  30268     /* Get entry type. */
  30269     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
  30270 
  30271     /* Zero destination buffer. */
  30272     buf_p = (uint32 *)l3x_entry;
  30273     sal_memset(buf_p, 0, (ipv6) ?  BCM_XGS3_L3_ENT_SZ(unit, v6) : \
  30274                                    BCM_XGS3_L3_ENT_SZ(unit, v4));
  30275 
  30276     /* Extract l3 ipv6/4 fields information. */
  30277     fld = (_bcm_l3_fields_t *)((ipv6) ? BCM_XGS3_L3_MEM_FIELDS(unit, v6) : \
  30278                                         BCM_XGS3_L3_MEM_FIELDS(unit, v4));
  30279 
  30280 #ifdef BCM_TRIUMPH_SUPPORT
  30281     if (soc_feature(unit, soc_feature_l3_entry_key_type) && ipv6) {
  30282         /* Set address lower part (64-127). */
  30283         soc_mem_ip6_addr_set(unit, mem, buf_p, IP_ADDR_LWR_64f,
  30284                              l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY);
  30285 
  30286         /* Set address upper part (0-63). */
  30287         soc_mem_ip6_addr_set(unit, mem, buf_p, IP_ADDR_UPR_64f,
  30288                              l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY);
  30289 
  30290         /* Mark entry as ipv6. */
  30291 #ifdef BCM_TRIDENT2_SUPPORT
  30292         if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
  30293             soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_0f,
  30294                                 TD2_L3_HASH_KEY_TYPE_V6UC);
  30295             soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_1f,
  30296                                 TD2_L3_HASH_KEY_TYPE_V6UC);
  30297         } else
  30298 #endif /* BCM_TRIDENT2_SUPPORT */
  30299         {
  30300             soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_0f,
  30301                                 TR_L3_HASH_KEY_TYPE_V6UC);
  30302             soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_1f,
  30303                                 TR_L3_HASH_KEY_TYPE_V6UC);
  30304         }
  30305 
  30306         /* Set valid bit. */
  30307         soc_mem_field32_set(unit, mem, buf_p, VALID_1f, 1);
  30308     } else
  30309 #endif /* BCM_TRIUMPH_SUPPORT*/
  30310     if (SOC_IS_FBX(unit) && ipv6) {
  30311         /* Set address lower part (64-127). */
  30312         soc_mem_ip6_addr_set(unit, mem, buf_p, IP_ADDR_LWR_64f,
  30313                              l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY);
  30314 
  30315         /* Set address upper part (0-63). */
  30316         soc_mem_ip6_addr_set(unit, mem, buf_p, IP_ADDR_UPR_64f,
  30317                              l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY);
  30318 
  30319         /* Mark entry as ipv6. */
  30320         soc_mem_field32_set(unit, mem, buf_p, V6_0f, 1);
  30321         soc_mem_field32_set(unit, mem, buf_p, V6_1f, 1);
  30322 
  30323         /* Set valid bit. */
  30324         soc_mem_field32_set(unit, mem, buf_p, VALID_1f, 1);
  30325     } else {
  30326 #ifdef BCM_TRIUMPH_SUPPORT
  30327         if (soc_feature(unit, soc_feature_l3_entry_key_type)) {
  30328             /* Mark entry as ipv4. */
  30329 #ifdef BCM_TRIDENT2_SUPPORT
  30330             if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
  30331                 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf,
  30332                                     TD2_L3_HASH_KEY_TYPE_V4UC);
  30333             } else
  30334 #endif /* BCM_TRIDENT2_SUPPORT */
  30335             {
  30336                 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf,
  30337                                     TR_L3_HASH_KEY_TYPE_V4UC);
  30338             }
  30339         }
  30340 #endif /* BCM_TRIUMPH_SUPPORT */
  30341 
  30342         /* Set ip address. */
  30343         soc_mem_field32_set(unit, mem, buf_p, IP_ADDRf, l3cfg->l3c_ip_addr);
  30344     }
  30345 
  30346     /* Set virtual router id. */
  30347     if (SOC_MEM_FIELD_VALID(unit, mem, fld->vrf)) {
  30348         soc_mem_field32_set(unit, mem, buf_p, fld->vrf, l3cfg->l3c_vrf);
  30349     }
  30350 
  30351 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \
  30352     defined(BCM_SCORPION_SUPPORT)
  30353     if (SOC_MEM_FIELD_VALID(unit, mem, VRF_ID_1f) && ipv6) {
  30354         soc_mem_field32_set(unit, mem, buf_p, VRF_ID_1f, l3cfg->l3c_vrf);
  30355     }
  30356 #endif /* BCM_FIREBOLT2_SUPPORT  || BCM_RAVEN_SUPPORT || BCM_SCORPION_SUPPORT */
  30357 
  30358     /* Set entry valid bit. */
  30359     soc_mem_field32_set(unit, mem, buf_p, fld->valid, 1);
  30360 
  30361 }
  30362 
  30363 
  30364 /*
  30365  * Function:
  30366  *      _bcm_xgs3_l3_ent_parse
  30367  * Purpose:
  30368  *      Service routine used to parse hw l3 entry to api format.
  30369  * Parameters:
  30370  *      unit      - (IN)SOC unit number.
  30371  *      mem       - (IN)L3 table memory.
  30372  *      l3cfg     - (IN/OUT)l3 entry key & parse result.
  30373  *      nh_idx    - (IN/OUT)Next hop index.
  30374  *      l3x_entry - (IN)hw buffer.
  30375  * Returns:
  30376  *      void
  30377  */
  30378 STATIC void
  30379 _bcm_xgs3_l3_ent_parse(int unit, soc_mem_t mem,
  30380                        _bcm_l3_cfg_t *l3cfg, int *nh_idx, void *l3x_entry)
  30381 {
  30382     _bcm_l3_fields_t *fld;        /* L3 table common fields.     */
  30383     uint32 *buf_p;                /* HW buffer address.          */
  30384     int ipv6;                     /* Entry is IPv6 flag.         */
  30385 
  30386     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
  30387     buf_p = (uint32 *)l3x_entry;
  30388 
  30389     /* Extract l3 ipv6/4 fields information. */
  30390     fld = (_bcm_l3_fields_t *)((ipv6) ? BCM_XGS3_L3_MEM_FIELDS(unit, v6) : \
  30391                                BCM_XGS3_L3_MEM_FIELDS(unit, v4));
  30392 
  30393     /* Reset entry flags first. */
  30394     l3cfg->l3c_flags = (ipv6) ? BCM_L3_IP6 : 0;
  30395 
  30396 
  30397     /* Get info from L3 and next hop table */
  30398     if (soc_mem_field32_get(unit, mem, buf_p, fld->hit) ||
  30399         BCM_XGS3_V6_FLD32_GET_IF_FBX(unit, ipv6, mem, buf_p, HIT_1f)) {
  30400         l3cfg->l3c_flags |= BCM_L3_HIT;
  30401     }
  30402 
  30403     /* Get priority override flag. */
  30404     if (soc_mem_field32_get(unit, mem, buf_p, fld->rpe)) {
  30405         l3cfg->l3c_flags |= BCM_L3_RPE;
  30406     }
  30407 
  30408     /* Get destination discard flag. */
  30409     if (SOC_MEM_FIELD_VALID(unit, mem, fld->dst_discard)) {
  30410        if (soc_mem_field32_get(unit, mem, buf_p, fld->dst_discard)) {
  30411            l3cfg->l3c_flags |= BCM_L3_DST_DISCARD;
  30412        }
  30413     }
  30414 
  30415 #if defined(BCM_TRX_SUPPORT)
  30416     /* Get classification group id. */
  30417     if (SOC_MEM_FIELD_VALID(unit, mem, fld->class_id)) {
  30418         l3cfg->l3c_lookup_class =
  30419             soc_mem_field32_get(unit, mem, buf_p, fld->class_id);
  30420     }
  30421 #endif /* BCM_TRX_SUPPORT */
  30422 
  30423     /* Get priority. */
  30424     l3cfg->l3c_prio = soc_mem_field32_get(unit, mem, buf_p, fld->priority);
  30425 
  30426     /* Get virtual router id. */
  30427     if (SOC_MEM_FIELD_VALID(unit, mem, fld->vrf)) {
  30428         l3cfg->l3c_vrf = soc_mem_field32_get(unit, mem, buf_p, fld->vrf);
  30429     } else {
  30430         l3cfg->l3c_vrf = BCM_L3_VRF_DEFAULT;
  30431     }
  30432 
  30433     /* Get next hop info. */
  30434     if (nh_idx) {
  30435         *nh_idx = soc_mem_field32_get(unit, mem, buf_p, fld->nh_idx);
  30436     }
  30437 
  30438     return;
  30439 }
  30440 
  30441 /*
  30442  * Function:
  30443  *      _bcm_xgs3_l3_clear_hit
  30444  * Purpose:
  30445  *      Clear hit bit on l3 entry
  30446  * Parameters:
  30447  *      unit      - (IN)SOC unit number.
  30448  *      mem       - (IN)L3 table memory.
  30449  *      l3cfg     - (IN)l3 entry info.
  30450  *      l3x_entry - (IN)l3 entry filled hw buffer.
  30451  * Returns:
  30452  *      BCM_E_XXX
  30453  */
  30454 STATIC int
  30455 _bcm_xgs3_l3_clear_hit(int unit, soc_mem_t mem,
  30456                        _bcm_l3_cfg_t *l3cfg, void *l3x_entry)
  30457 {
  30458     _bcm_l3_fields_t *fld;        /* L3 table common fields.  */
  30459     uint32 *buf_p;                /* HW buffer address.       */
  30460     int mcast;                    /* Entry is multicast flag. */
  30461     int ipv6;                     /* Entry is IPv6 flag.      */
  30462 #ifdef BCM_FIREBOLT_SUPPORT
  30463     int idx;                      /* Iterator index.          */
  30464     soc_field_t hitf[] = { HIT_0f, HIT_1f, HIT_2f, HIT_3f };
  30465 #endif /* BCM_FIREBOLT_SUPPORT */
  30466 
  30467     /* Input parameters check */
  30468     if ((NULL == l3cfg) || (NULL == l3x_entry)) {
  30469         return (BCM_E_PARAM);
  30470     }
  30471 
  30472     /* Get entry type. */
  30473     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
  30474     mcast = (l3cfg->l3c_flags & BCM_L3_IPMC);
  30475 
  30476     /* Extract l3 ipv6/4 fields information. */
  30477     fld = (_bcm_l3_fields_t *)((ipv6) ? BCM_XGS3_L3_MEM_FIELDS(unit, v6) : \
  30478                                BCM_XGS3_L3_MEM_FIELDS(unit, v4));
  30479 
  30480     /* Init memory pointers. */
  30481     buf_p = (uint32 *)l3x_entry;
  30482 
  30483     /* If entry was not hit  there is nothing to clear */
  30484     if (!(l3cfg->l3c_flags & BCM_L3_HIT)) {
  30485         return (BCM_E_NONE);
  30486     }
  30487 
  30488 #ifdef BCM_FIREBOLT_SUPPORT
  30489     /* Reset entry hit bit in hw. */
  30490     if (ipv6 && mcast) {
  30491         /* IPV6 multicast entry hit reset. */
  30492         if (SOC_IS_FBX(unit)) {
  30493             for (idx = 1; idx < 4; idx++) {
  30494                 soc_mem_field32_set(unit, mem, buf_p, hitf[idx], 0);
  30495             }
  30496         }
  30497     } else if (ipv6) {
  30498         /* Reset IPV6 unicast  hit bit. */
  30499         if (SOC_IS_FBX(unit)) {
  30500             for (idx = 1; idx < 2; idx++) {
  30501                 soc_mem_field32_set(unit, mem, buf_p, hitf[idx], 0);
  30502             }
  30503         }
  30504     }
  30505 #endif /* BCM_FIREBOLT_SUPPORT */
  30506 
  30507     /* Reset hit bit. */
  30508     soc_mem_field32_set(unit, mem, buf_p, fld->hit, 0);
  30509 
  30510     /* Write entry back to hw. */
  30511     return BCM_XGS3_MEM_WRITE(unit, mem, l3cfg->l3c_hw_index, buf_p);
  30512 }
  30513 
  30514 /*
  30515  * Function:
  30516  *      _bcm_xgs3_l3_get
  30517  * Purpose:
  30518  *      Get an entry from L3 table.
  30519  * Parameters:
  30520  *      unit     - (IN)SOC unit number.
  30521  *      l3cfg    - (IN/OUT)l3 entry  lookup key & search result.
  30522  *      nh_index - (IN/OUT)Next hop index.
  30523  * Returns:
  30524  *      BCM_E_XXX
  30525  */
  30526 STATIC int
  30527 _bcm_xgs3_l3_get(int unit, _bcm_l3_cfg_t *l3cfg, int *nh_idx)
  30528 {
  30529     l3_entry_ipv6_unicast_entry_t l3x_key;      /* Lookup entry buffer.     */
  30530     l3_entry_ipv6_unicast_entry_t l3x_entry;    /* Search result buffer.    */
  30531     soc_mem_t mem;                              /* L3 table memory.         */
  30532     int clear_hit;                              /* Clear hit bit.           */
  30533     int ipv6;                                   /* IPv6 entry indicator.    */
  30534     int rv = BCM_E_NONE;                        /* Operation return status. */
  30535 
  30536     /* Get entry type. */
  30537     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
  30538 
  30539     /* Preserve clear_hit value. */
  30540     clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR;
  30541 
  30542     /* Get table memory. */
  30543     mem = (ipv6) ? BCM_XGS3_L3_MEM(unit, v6) : BCM_XGS3_L3_MEM(unit, v4);
  30544     if (INVALIDm == mem) {
  30545         return (BCM_E_NOT_FOUND);
  30546     }
  30547 
  30548     /* Prepare lookup key. */
  30549     /* coverity[overrun-buffer-val : FALSE]    */
  30550     _bcm_xgs3_l3_ent_init(unit, mem, l3cfg, &l3x_key);
  30551 
  30552     /* Perform lookup hw. */
  30553 #ifdef BCM_TRX_SUPPORT
  30554     if (soc_feature(unit, soc_feature_generic_table_ops)) {
  30555         /* coverity[overrun-buffer-val : FALSE] */
  30556         rv = soc_mem_search(unit, mem, MEM_BLOCK_ANY, &l3cfg->l3c_hw_index,
  30557                             &l3x_key, &l3x_entry, 0);
  30558     } else
  30559 #endif /*  BCM_TRX_SUPPORT */
  30560 #ifdef BCM_FIREBOLT_SUPPORT
  30561     if (SOC_IS_FBX(unit)) {
  30562         rv = soc_fb_l3x_lookup(unit, (void *)&l3x_key,
  30563                                (void *)&l3x_entry, &l3cfg->l3c_hw_index);
  30564     }
  30565 #endif /*  BCM_FIREBOLT_SUPPORT */
  30566     BCM_XGS3_LKUP_IF_ERROR_RETURN(rv, BCM_E_NOT_FOUND);
  30567 
  30568 #ifdef BCM_TRIDENT_SUPPORT
  30569     if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit)) {
  30570         soc_mem_t mem_y;
  30571         l3_entry_ipv6_unicast_entry_t l3x_entry_y;
  30572         uint32 hit;
  30573         mem_y = ipv6 ? L3_ENTRY_IPV6_UNICAST_Ym : L3_ENTRY_IPV4_UNICAST_Ym;
  30574         BCM_IF_ERROR_RETURN
  30575             (BCM_XGS3_MEM_READ(unit, mem_y, l3cfg->l3c_hw_index,
  30576                                &l3x_entry_y));
  30577         if (ipv6) {
  30578             hit = soc_mem_field32_get(unit, mem, &l3x_entry, HIT_0f);
  30579             hit |= soc_mem_field32_get(unit, mem_y, &l3x_entry_y, HIT_0f);
  30580             soc_mem_field32_set(unit, mem, &l3x_entry, HIT_0f, hit);
  30581             hit = soc_mem_field32_get(unit, mem, &l3x_entry, HIT_1f);
  30582             hit |= soc_mem_field32_get(unit, mem_y, &l3x_entry_y, HIT_1f);
  30583             soc_mem_field32_set(unit, mem, &l3x_entry, HIT_1f, hit);
  30584         } else {
  30585             hit = soc_mem_field32_get(unit, mem, &l3x_entry, HITf);
  30586             hit |= soc_mem_field32_get(unit, mem_y, &l3x_entry_y, HITf);
  30587             soc_mem_field32_set(unit, mem, &l3x_entry, HITf, hit);
  30588         }
  30589     }
  30590 #endif /* BCM_TRIDENT_SUPPORT */
  30591 
  30592     /* Extract entry info. */
  30593     _bcm_xgs3_l3_ent_parse(unit, mem, l3cfg, nh_idx, &l3x_entry);
  30594 
  30595     /* Clear the HIT bit */
  30596     if (clear_hit) {
  30597         BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_clear_hit(unit, mem,
  30598                                                    l3cfg, &l3x_entry));
  30599     }
  30600     return (BCM_E_NONE);
  30601 }
  30602 
  30603 /*
  30604  * Function:
  30605  *      _bcm_xgs3_l3_add
  30606  * Purpose:
  30607  *      Add an entry to L3 table.
  30608  * Parameters:
  30609  *      unit     - (IN)SOC unit number.
  30610  *      l3cfg    - (IN)l3 entry information.
  30611  *      nh_idx   - (IN)Next hop index.
  30612  * Returns:
  30613  *      BCM_E_XXX
  30614  */
  30615 STATIC int
  30616 _bcm_xgs3_l3_add(int unit, _bcm_l3_cfg_t *l3cfg, int nh_idx)
  30617 {
  30618     l3_entry_ipv6_unicast_entry_t l3x_entry;    /* Buffer for write        */
  30619     _bcm_l3_fields_t *fld;                      /* L3 table common fields. */
  30620     uint32 *buf_p;                              /* Hardware buffer address.*/
  30621     soc_mem_t mem;                              /* L3 table memory.        */
  30622     int ipv6;                                   /* IPv6 entry indicator.   */
  30623     int rv = BCM_E_NONE;                        /* Operation status.       */
  30624 
  30625     buf_p = (uint32 *)&l3x_entry;
  30626 
  30627     /* Get entry type. */
  30628     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
  30629 
  30630     /* Extract l3 ipv6/4 fields information. */
  30631     fld = (_bcm_l3_fields_t *)((ipv6) ? BCM_XGS3_L3_MEM_FIELDS(unit, v6) : \
  30632                                BCM_XGS3_L3_MEM_FIELDS(unit, v4));
  30633 
  30634     /* Get table memory. */
  30635     mem = (ipv6) ? BCM_XGS3_L3_MEM(unit, v6) : BCM_XGS3_L3_MEM(unit, v4);
  30636     if (INVALIDm == mem) {
  30637         return (BCM_E_DISABLED);
  30638     }
  30639 
  30640     /* Prepare hw entry for addition. */
  30641     _bcm_xgs3_l3_ent_init(unit, mem, l3cfg, buf_p);
  30642 
  30643     /* Set hit bit. */
  30644     if ((!SOC_IS_TOMAHAWK3(unit)) && (l3cfg->l3c_flags & BCM_L3_HIT)) {
  30645         soc_mem_field32_set(unit, mem, buf_p, fld->hit, 1);
  30646         BCM_XGS3_V6_FLD32_SET_IF_FBX(unit, ipv6, mem, buf_p, HIT_1f, 1);
  30647      }
  30648 
  30649     /* Set priority override bit. */
  30650     if (l3cfg->l3c_flags & BCM_L3_RPE) {
  30651         soc_mem_field32_set(unit, mem, buf_p, fld->rpe, 1);
  30652         BCM_XGS3_V6_FLD32_SET_IF_FBX(unit, ipv6, mem, buf_p, RPE_1f, 1);
  30653     }
  30654 
  30655     /* Set destination discard bit. */
  30656     if (SOC_MEM_FIELD_VALID(unit, mem, fld->dst_discard)) {
  30657         if (l3cfg->l3c_flags & BCM_L3_DST_DISCARD) {
  30658             soc_mem_field32_set(unit, mem, buf_p, fld->dst_discard, 1);
  30659             BCM_XGS3_V6_FLD32_SET_IF_FBX(unit, ipv6, mem, buf_p,
  30660                                          DST_DISCARD_1f, 1);
  30661         }
  30662     }
  30663 
  30664 #if defined(BCM_TRX_SUPPORT)
  30665     /* Get classification group id. */
  30666     if (SOC_MEM_FIELD_VALID(unit, mem, fld->class_id)) {
  30667         soc_mem_field32_set(unit, mem, buf_p, fld->class_id,
  30668                             l3cfg->l3c_lookup_class);
  30669         BCM_XGS3_V6_FLD32_SET_IF_FBX(unit, ipv6, mem, buf_p,
  30670                                      CLASS_ID_1f, l3cfg->l3c_lookup_class);
  30671     }
  30672 #endif /* BCM_TRX_SUPPORT */
  30673 
  30674     /*  Set priority. */
  30675     if (SOC_MEM_FIELD_VALID(unit, mem, fld->priority)) {
  30676         int pri_field_len;
  30677         int max_pri;
  30678 
  30679         pri_field_len = soc_mem_field_length(unit, mem, fld->priority);
  30680         max_pri = (1 << pri_field_len) - 1;
  30681 
  30682         /*
  30683          * to validate the assigning priority :
  30684          *  - Different device may support different max priority.
  30685          */
  30686         if (l3cfg->l3c_prio > max_pri) {
  30687             return BCM_E_PARAM;
  30688         }
  30689         soc_mem_field32_set(unit, mem, buf_p, fld->priority, l3cfg->l3c_prio);
  30690         BCM_XGS3_V6_FLD32_SET_IF_FBX(unit, ipv6, mem, buf_p,
  30691                                             PRI_1f, l3cfg->l3c_prio);
  30692     }
  30693 
  30694     /* Set next hop index. */
  30695     soc_mem_field32_set(unit, mem, buf_p, fld->nh_idx, nh_idx);
  30696     BCM_XGS3_V6_FLD32_SET_IF_FBX(unit, ipv6, mem, buf_p,
  30697                                          NEXT_HOP_INDEX_1f, nh_idx);
  30698     /* Write entry to hw. */
  30699     /* Handle replacement if hw index already known, write directly. */
  30700     if (BCM_XGS3_L3_INVALID_INDEX != l3cfg->l3c_hw_index) {
  30701         rv = BCM_XGS3_MEM_WRITE(unit, mem, l3cfg->l3c_hw_index, buf_p);
  30702     } else {
  30703 #ifdef BCM_TRX_SUPPORT
  30704         if (soc_feature(unit, soc_feature_generic_table_ops)) {
  30705             /* coverity[overrun-buffer-val : FALSE] */
  30706             rv = soc_mem_insert(unit, mem, MEM_BLOCK_ANY, (void *)&l3x_entry);
  30707         } else
  30708 #endif /*  BCM_TRX_SUPPORT */
  30709 #ifdef BCM_FIREBOLT_SUPPORT
  30710         if (SOC_IS_FBX(unit)) {
  30711             rv = soc_fb_l3x_insert(unit, (void *)&l3x_entry);
  30712         }
  30713 #endif /* BCM_FIREBOLT_SUPPORT */
  30714     }
  30715 
  30716     /* Write status check. */
  30717     if ((rv >= 0) && (BCM_XGS3_L3_INVALID_INDEX == l3cfg->l3c_hw_index)) {
  30718         (ipv6) ?  BCM_XGS3_L3_IP6_CNT(unit)++ : BCM_XGS3_L3_IP4_CNT(unit)++;
  30719     }
  30720     return rv;
  30721 }
  30722 
  30723 
  30724 /*
  30725  * Function:
  30726  *      _bcm_xgs3_l3_bucket_get
  30727  * Purpose:
  30728  *      Get l3 entry bucket start index.
  30729  * Parameters:
  30730  *      unit          - (IN)SOC unit number.
  30731  *      l3cfg         - (IN)l3 entry information.
  30732  *      idx_primary   - (OUT)Primary bank bucket start index.
  30733  *      idx_secondary - (OUT)Secondary bank bucket start index.
  30734  * Returns:
  30735  *      BCM_E_XXX
  30736  * NOTE:
  30737  *     idx_primary = points to the first half of the bucket.
  30738  *     idx_secondary = points to the second half of the bucket.
  30739  *     If dual hash is not supported idx_primary & idx_secondary
  30740  *     point to the same bucket.
  30741  */
  30742 
  30743 STATIC int
  30744 _bcm_xgs3_l3_bucket_get (int unit, _bcm_l3_cfg_t *l3cfg,
  30745                          int *idx_primary, int *idx_secondary)
  30746 {
  30747     l3_entry_ipv6_multicast_entry_t l3x_entry;  /* Buffer for hw  write    */
  30748     uint32 *buf_p;                              /* Hardware buffer address.*/
  30749     soc_mem_t mem;                              /* L3 table memory.        */
  30750     uint8 ipv6;                                 /* IPv6 entry indicator.   */
  30751     uint8 ipmc;                                 /* IPMC entry indicator.   */
  30752     int prim_idx;                               /* Primary bucket.         */
  30753     int sec_idx;                                /* Secondary bucket.       */
  30754 
  30755     if ((NULL == idx_primary) || (NULL == idx_secondary)) {
  30756         return (BCM_E_PARAM);
  30757     }
  30758 
  30759     sal_memset(&l3x_entry, 0, sizeof(l3x_entry)); 
  30760     buf_p = (uint32 *)&l3x_entry;
  30761 
  30762     /* Get entry type. */
  30763     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6) ? 1 : 0;
  30764     ipmc = (l3cfg->l3c_flags & BCM_L3_IPMC) ? 1 : 0;
  30765 
  30766     /* Get table memory. */
  30767     mem = (ipv6) ? BCM_XGS3_L3_MEM(unit, v6) : BCM_XGS3_L3_MEM(unit, v4);
  30768     if (INVALIDm == mem) {
  30769         return (BCM_E_DISABLED);
  30770     }
  30771 
  30772     /* Prepare hw entry for addition. */
  30773 
  30774     if (ipmc) {
  30775 #if defined(BCM_TRIUMPH_SUPPORT)
  30776         if (SOC_IS_TR_VL(unit)) {
  30777             _bcm_tr_l3_ipmc_ent_init(unit, buf_p, l3cfg);
  30778         } else
  30779 #endif /* BCM_TRIUMPH_SUPPORT */
  30780         {
  30781 #ifdef BCM_FIREBOLT_SUPPORT
  30782             _bcm_fb_l3_ipmc_ent_init(unit, buf_p, l3cfg);
  30783 #endif /* BCM_FIREBOLT_SUPPORT */
  30784         }
  30785     } else {
  30786         _bcm_xgs3_l3_ent_init(unit, mem, l3cfg, buf_p);
  30787     }
  30788 
  30789 #ifdef BCM_FIREBOLT_SUPPORT
  30790     if (SOC_IS_FBX(unit)) {
  30791 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) ||\
  30792     defined(BCM_TRX_SUPPORT)
  30793         if (soc_feature(unit, soc_feature_dual_hash)) {
  30794 
  30795             prim_idx =
  30796                 soc_fb_l3x_bank_entry_hash(unit, 0, (uint32 *)&l3x_entry);
  30797                 if (prim_idx < 0) {
  30798                     return prim_idx;
  30799                 }
  30800             /* coverity[overrun-buffer-val : FALSE]    */
  30801             sec_idx =
  30802                 soc_fb_l3x_bank_entry_hash(unit, 1, (uint32 *)&l3x_entry);
  30803                 if (sec_idx < 0) {
  30804                     return sec_idx;
  30805                 }
  30806         } else
  30807 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */
  30808         {
  30809            sec_idx = prim_idx = soc_fb_l3x2_entry_hash(unit, (uint32 *)&l3x_entry);
  30810         }
  30811     } else
  30812 #endif /* BCM_FIREBOLT_SUPPORT */
  30813     {
  30814         *idx_primary = *idx_secondary = -1;
  30815         return (BCM_E_UNAVAIL);
  30816     }
  30817 
  30818     /* First half of primary bucket. */
  30819     *idx_primary = prim_idx * SOC_L3X_BUCKET_SIZE(unit);
  30820 
  30821     /* Second half of secondary bucket */
  30822     *idx_secondary = sec_idx * SOC_L3X_BUCKET_SIZE(unit) +
  30823         SOC_L3X_BUCKET_SIZE(unit)/2;
  30824 
  30825     return (BCM_E_NONE);
  30826 }
  30827 
  30828 
  30829 /*
  30830  * Function:
  30831  *      _bcm_xgs3_l3_del
  30832  * Purpose:
  30833  *      Delete an entry to L3 table.
  30834  * Parameters:
  30835  *      unit     - (IN)SOC unit number.
  30836  *      l3cfg    - (IN/OUT)l3 entry deletion key.
  30837  * Returns:
  30838  *      BCM_E_XXX
  30839  */
  30840 STATIC int
  30841 _bcm_xgs3_l3_del(int unit, _bcm_l3_cfg_t *l3cfg)
  30842 {
  30843     l3_entry_ipv6_unicast_entry_t l3x_entry;    /* Buffer for write        */
  30844     soc_mem_t mem;                              /* L3 table memory.        */
  30845     int ipv6;                                   /* IPv6 entry indicator.   */
  30846     int rv = BCM_E_NONE;                        /* Operation status.       */
  30847 
  30848     /* Get entry type. */
  30849     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
  30850 
  30851     /* Get table memory. */
  30852     mem = (ipv6) ? BCM_XGS3_L3_MEM(unit, v6) : BCM_XGS3_L3_MEM(unit, v4);
  30853     if (INVALIDm == mem) {
  30854         return (BCM_E_DISABLED);
  30855     }
  30856 
  30857     /* Prepare hw entry for addition. */
  30858     _bcm_xgs3_l3_ent_init(unit, mem, l3cfg, &l3x_entry);
  30859 
  30860     /* Write entry to hw. */
  30861 #ifdef BCM_TRX_SUPPORT
  30862     if (soc_feature(unit, soc_feature_generic_table_ops)) {
  30863         rv = soc_mem_delete(unit, mem, MEM_BLOCK_ANY, (void *)&l3x_entry);
  30864     } else
  30865 #endif /*  BCM_TRX_SUPPORT */
  30866 #ifdef BCM_FIREBOLT_SUPPORT
  30867     if (SOC_IS_FBX(unit)) {
  30868         rv = soc_fb_l3x_delete(unit, (void *)&l3x_entry);
  30869     }
  30870 #endif /* BCM_FIREBOLT_SUPPORT */
  30871 
  30872     /* Write status check. */
  30873     if (rv >= 0) {
  30874         (ipv6) ?  BCM_XGS3_L3_IP6_CNT(unit)-- : BCM_XGS3_L3_IP4_CNT(unit)--;
  30875     }
  30876     return rv;
  30877 }
  30878 
  30879 /*
  30880  * Function:
  30881  *      _bcm_xgs3_l3_get_by_idx
  30882  * Purpose:
  30883  *      Get an entry from L3 table by index.
  30884  * Parameters:
  30885  *      unit     - (IN)SOC unit number.
  30886  *      dma_ptr  - (IN)Table pointer in dma.
  30887  *      idx      - (IN)Index to read.
  30888  *      l3cfg    - (OUT)l3 entry search result.
  30889  *      nh_index - (OUT)Next hop index.
  30890  * Returns:
  30891  *      BCM_E_XXX
  30892  */
  30893 STATIC int
  30894 _bcm_xgs3_l3_get_by_idx(int unit, void *dma_ptr, int idx,
  30895                         _bcm_l3_cfg_t *l3cfg, int *nh_idx)
  30896 {
  30897     l3_entry_ipv6_unicast_entry_t *l3x_entry_p; /* Read buffer address.    */
  30898     l3_entry_ipv6_unicast_entry_t l3x_entry;    /* Read buffer.            */
  30899     _bcm_l3_fields_t *fld;                      /* L3 table common fields. */
  30900     soc_mem_t mem;                              /* L3 table memory.        */
  30901     int clear_hit;                              /* Clear hit bit flag.     */
  30902     uint32 ipv6;                                /* IPv6 entry indicator.   */
  30903 
  30904     /* Get entry type. */
  30905     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
  30906 
  30907     /* Get table memory. */
  30908     mem = (ipv6) ? BCM_XGS3_L3_MEM(unit, v6) : BCM_XGS3_L3_MEM(unit, v4);
  30909 
  30910     /* Extract l3 ipv6/4 fields information. */
  30911     fld = (_bcm_l3_fields_t *)((ipv6) ? BCM_XGS3_L3_MEM_FIELDS(unit, v6) : \
  30912                                BCM_XGS3_L3_MEM_FIELDS(unit, v4));
  30913 
  30914     /* Get clear hit flag. */
  30915     clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR;
  30916 
  30917     if (NULL == dma_ptr) {             /* Read from hardware. */
  30918         l3x_entry_p = &l3x_entry;
  30919         /* Zero buffers. */
  30920         sal_memset(l3x_entry_p, 0, BCM_XGS3_L3_ENT_SZ(unit, v6));
  30921 
  30922         /* Read entry from hw. */
  30923         BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, l3x_entry_p));
  30924 
  30925     } else {                    /* Read from dma. */
  30926         l3x_entry_p =
  30927             soc_mem_table_idx_to_pointer(unit, mem,
  30928                                          l3_entry_ipv6_unicast_entry_t *,
  30929                                          dma_ptr, idx);
  30930     }
  30931 
  30932 #ifdef BCM_TRIDENT_SUPPORT
  30933     if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit)) {
  30934         soc_mem_t mem_y;
  30935         l3_entry_ipv6_unicast_entry_t l3x_entry_y;
  30936         uint32 hit;
  30937         mem_y = ipv6 ? L3_ENTRY_IPV6_UNICAST_Ym : L3_ENTRY_IPV4_UNICAST_Ym;
  30938         BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem_y, idx, &l3x_entry_y));
  30939         if (ipv6) {
  30940             hit = soc_mem_field32_get(unit, mem, l3x_entry_p, HIT_0f);
  30941             hit |= soc_mem_field32_get(unit, mem_y, &l3x_entry_y, HIT_0f);
  30942             soc_mem_field32_set(unit, mem, l3x_entry_p, HIT_0f, hit);
  30943             hit = soc_mem_field32_get(unit, mem, l3x_entry_p, HIT_1f);
  30944             hit |= soc_mem_field32_get(unit, mem_y, &l3x_entry_y, HIT_1f);
  30945             soc_mem_field32_set(unit, mem, l3x_entry_p, HIT_1f, hit);
  30946         } else {
  30947             hit = soc_mem_field32_get(unit, mem, l3x_entry_p, HITf);
  30948             hit |= soc_mem_field32_get(unit, mem_y, &l3x_entry_y, HITf);
  30949             soc_mem_field32_set(unit, mem, l3x_entry_p, HITf, hit);
  30950         }
  30951     }
  30952 #endif /* BCM_TRIDENT_SUPPORT */
  30953 
  30954     /* Ignore invalid entries. */
  30955     if (soc_mem_field_valid(unit, mem, fld->valid)) {
  30956         if (!soc_mem_field32_get(unit, mem, l3x_entry_p, fld->valid)) {
  30957             return (BCM_E_NOT_FOUND);
  30958         }
  30959     }
  30960 #ifdef BCM_TRIUMPH_SUPPORT
  30961     if (soc_feature(unit, soc_feature_l3_entry_key_type)) {
  30962         /* Get protocol. */
  30963         int       key_type;
  30964 
  30965         key_type = soc_mem_field32_get(unit, L3_ENTRY_ONLYm,
  30966                                        l3x_entry_p, KEY_TYPEf);
  30967 
  30968 #ifdef BCM_TRIDENT2_SUPPORT
  30969         if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
  30970             switch (key_type) {
  30971             case TD2_L3_HASH_KEY_TYPE_V4UC:
  30972                 l3cfg->l3c_flags = 0;
  30973                 break;
  30974             case TD2_L3_HASH_KEY_TYPE_V4MC:
  30975                 l3cfg->l3c_flags = BCM_L3_IPMC;
  30976                 break;
  30977             case TD2_L3_HASH_KEY_TYPE_V6UC:
  30978                 l3cfg->l3c_flags = BCM_L3_IP6;
  30979                 break;
  30980             case TD2_L3_HASH_KEY_TYPE_V6MC:
  30981                 l3cfg->l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC;
  30982                 break;
  30983             default:
  30984                 break;
  30985             }
  30986         } else
  30987 #endif /* BCM_TRIDENT2_SUPPORT */
  30988         {
  30989 	    if (key_type == TR_L3_HASH_KEY_TYPE_RMEP ||
  30990                 key_type == TR_L3_HASH_KEY_TYPE_LMEP) {
  30991                 /* Ignore OAM entries.
  30992                  * They handled in OAM, should not changed in L3
  30993 		 */
  30994                 return (BCM_E_NOT_FOUND);
  30995 	    }
  30996             switch (key_type) {
  30997             case TR_L3_HASH_KEY_TYPE_V4UC:
  30998                 l3cfg->l3c_flags = 0;
  30999                 break;
  31000             case TR_L3_HASH_KEY_TYPE_V4MC:
  31001                 l3cfg->l3c_flags = BCM_L3_IPMC;
  31002                 break;
  31003             case TR_L3_HASH_KEY_TYPE_V6UC:
  31004                 l3cfg->l3c_flags = BCM_L3_IP6;
  31005                 break;
  31006             case TR_L3_HASH_KEY_TYPE_V6MC:
  31007                 l3cfg->l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC;
  31008                 break;
  31009             default:
  31010                 break;
  31011             }
  31012         }
  31013 
  31014         /* Ignore protocol mismatch & multicast entries. */
  31015         if ((ipv6  != (l3cfg->l3c_flags & BCM_L3_IP6)) ||
  31016             (l3cfg->l3c_flags & BCM_L3_IPMC)) {
  31017             return (BCM_E_NONE);
  31018         }
  31019 
  31020         /* Get host ip address. */
  31021         if (ipv6) {
  31022             /* Extract host info from the entry. */
  31023             soc_mem_ip6_addr_get(unit, mem, l3x_entry_p,
  31024                                  IP_ADDR_LWR_64f, l3cfg->l3c_ip6,
  31025                                  SOC_MEM_IP6_LOWER_ONLY);
  31026 
  31027             soc_mem_ip6_addr_get(unit, mem, l3x_entry_p,
  31028                                  IP_ADDR_UPR_64f, l3cfg->l3c_ip6,
  31029                                  SOC_MEM_IP6_UPPER_ONLY);
  31030         }
  31031     } else
  31032 #endif /* BCM_TRIUMPH_SUPPORT */
  31033 #ifdef BCM_FIREBOLT_SUPPORT
  31034     if (SOC_IS_FBX(unit)) {
  31035         /* Get protocol. */
  31036         if (soc_mem_field32_get(unit, mem, l3x_entry_p, fld->v6_entry)){
  31037             l3cfg->l3c_flags = BCM_L3_IP6;
  31038         } else {
  31039             l3cfg->l3c_flags = 0;
  31040         }
  31041 
  31042         /* Get ipmc flag . */
  31043         if (soc_mem_field32_get(unit, mem, l3x_entry_p, fld->ipmc_entry)) {
  31044             l3cfg->l3c_flags |= BCM_L3_IPMC;
  31045         }
  31046 
  31047         /* Ignore protocol mismatch & multicast entries. */
  31048         if ((ipv6  != (l3cfg->l3c_flags & BCM_L3_IP6)) ||
  31049             (l3cfg->l3c_flags & BCM_L3_IPMC)) {
  31050             return (BCM_E_NONE);
  31051         }
  31052 
  31053 
  31054         /* Get host ip address. */
  31055         if (ipv6) {
  31056             /* Extract host info from the entry. */
  31057             soc_mem_ip6_addr_get(unit, mem, l3x_entry_p,
  31058                                  IP_ADDR_LWR_64f, l3cfg->l3c_ip6,
  31059                                  SOC_MEM_IP6_LOWER_ONLY);
  31060 
  31061             soc_mem_ip6_addr_get(unit, mem, l3x_entry_p,
  31062                                  IP_ADDR_UPR_64f, l3cfg->l3c_ip6,
  31063                                  SOC_MEM_IP6_UPPER_ONLY);
  31064         }
  31065     }
  31066 #endif /* BCM_FIREBOLT_SUPPORT */
  31067 
  31068     /* Set index to l3cfg. */
  31069     l3cfg->l3c_hw_index = idx;
  31070 
  31071     if (!ipv6) {
  31072         l3cfg->l3c_ip_addr =
  31073             soc_mem_field32_get(unit, mem, l3x_entry_p, IP_ADDRf);
  31074     }
  31075 
  31076     /* Parse entry data. */
  31077     _bcm_xgs3_l3_ent_parse(unit, mem, l3cfg, nh_idx, l3x_entry_p);
  31078 
  31079     /* Clear the HIT bit */
  31080     if (clear_hit) {
  31081         BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_clear_hit(unit, mem,
  31082                                                    l3cfg, (void *)l3x_entry_p));
  31083     }
  31084     return (BCM_E_NONE);
  31085 }
  31086 
  31087 /*
  31088  * Function:
  31089  *      _bcm_xgs3_nh_inc_ref_count
  31090  * Purpose:
  31091  *      Increment Next Hop Reference count
  31092  * Parameters:
  31093  *      unit     - (IN)SOC unit number.
  31094  *      nh_index - (IN)Next hop index.
  31095  */
  31096 
  31097 void
  31098 bcm_xgs3_nh_inc_ref_count(int unit, int nh_index)
  31099 {
  31100     _bcm_l3_tbl_t *nh_tbl_ptr; 			 /* Next hop table ptr. 	 */
  31101 
  31102     /* Get table pointers */
  31103     nh_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop);
  31104 
  31105     BCM_XGS3_L3_ENT_REF_CNT_INC(nh_tbl_ptr, nh_index,
  31106                              _BCM_SINGLE_WIDE);
  31107 }
  31108 
  31109 /*
  31110  * Function:
  31111  *      _bcm_xgs3_nh_dec_ref_count
  31112  * Purpose:
  31113  *      Decrement Next Hop Reference count
  31114  * Parameters:
  31115  *      unit     - (IN)SOC unit number.
  31116  *      nh_index - (IN)Next hop index.
  31117  */
  31118 
  31119 void
  31120 bcm_xgs3_nh_dec_ref_count(int unit, int nh_index)
  31121 {
  31122     _bcm_l3_tbl_t *nh_tbl_ptr; 			 /* Next hop table ptr. 	 */
  31123 
  31124     /* Get table pointers */
  31125     nh_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop);
  31126 
  31127     BCM_XGS3_L3_ENT_REF_CNT_DEC(nh_tbl_ptr, nh_index,
  31128                              _BCM_SINGLE_WIDE);
  31129 
  31130 }
  31131 
  31132 /*
  31133  * Function:
  31134  *      _bcm_xgs3_nh_ref_count_get
  31135  * Purpose:
  31136  *      Get Next Hop Reference count
  31137  * Parameters:
  31138  *      unit     - (IN)SOC unit number.
  31139  *      nh_index - (IN)Next hop index.
  31140  *      ref_count - (OUT)Reference count.
  31141  */
  31142 
  31143 int
  31144 bcm_xgs3_nh_ref_count_get(int unit, int nh_index, int *ref_count)
  31145 {
  31146     _bcm_l3_tbl_t *nh_tbl_ptr;
  31147 
  31148     /* Get table pointers */
  31149     nh_tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop);
  31150 
  31151 
  31152     *ref_count = BCM_XGS3_L3_ENT_REF_CNT(nh_tbl_ptr, nh_index);
  31153 
  31154     return BCM_E_NONE;
  31155 }
  31156 
  31157 #ifdef BCM_FIREBOLT_SUPPORT
  31158 /*
  31159  * Function:
  31160  *      _bcm_fb_l3_intf_vrf_get
  31161  * Purpose:
  31162  *      Get the VRF,flags info for the specified L3 interface
  31163  * Parameters:
  31164  *      unit      - (IN)SOC unit number.
  31165  *      intf_info - (IN/OUT)Interface configuration info.
  31166  * Returns:
  31167  *      BCM_E_XXX.
  31168  */
  31169 STATIC int
  31170 _bcm_fb_l3_intf_vrf_get(int unit, _bcm_l3_intf_cfg_t *intf_info)
  31171 {
  31172     int vrf;
  31173     int ret_val;                           /* Operation return value.       */
  31174     bcm_vlan_control_vlan_t vlan_control;  /* Vlan configuration structure. */
  31175 
  31176 #if defined(BCM_TRIUMPH_SUPPORT)
  31177     int  ingress_map_mode = 0;
  31178     _bcm_l3_ingress_intf_t iif; /* Ingress interface config.*/
  31179 
  31180     if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
  31181         BCM_IF_ERROR_RETURN(
  31182            bcm_xgs3_l3_ingress_intf_map_get(unit, &ingress_map_mode));
  31183     }
  31184 
  31185     if (ingress_map_mode && !soc_feature(unit, soc_feature_l3_iif_under_4k)) {
  31186         iif.intf_id = intf_info->l3i_index;
  31187         ret_val     = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif);
  31188         vrf         = iif.vrf;
  31189     } else
  31190 #endif /* BCM_TRIUMPH_SUPPORT */
  31191     {
  31192         ret_val = _bcm_xgs3_vlan_control_vlan_get(unit, intf_info->l3i_vid,
  31193                                                   BCM_VLAN_CONTROL_VLAN_ALL_MASK,
  31194                                                   &vlan_control);
  31195         vrf = vlan_control.vrf;
  31196     }
  31197 
  31198     if (BCM_SUCCESS(ret_val)) {
  31199         /* Get Virtual Router id */
  31200         intf_info->l3i_vrf = vrf;
  31201     } else {
  31202         intf_info->l3i_vrf = BCM_L3_VRF_DEFAULT;
  31203     }
  31204 
  31205     return (BCM_E_NONE);
  31206 }
  31207 
  31208 /*
  31209  * Function:
  31210  *      _bcm_fb_l3_intf_vrf_bind
  31211  * Purpose:
  31212  *      Bind interface to the VRF & update if info.
  31213  * Parameters:
  31214  *      unit      - (IN) SOC unit number.
  31215  *      intf_info - (IN) Interface configuration info.
  31216  * Returns:
  31217  *      BCM_E_XXX.
  31218  */
  31219 STATIC int
  31220 _bcm_fb_l3_intf_vrf_bind(int unit, _bcm_l3_intf_cfg_t *intf_info)
  31221 {
  31222     int rv;
  31223 #if defined(BCM_TRIUMPH_SUPPORT)
  31224     int ingress_map_mode = 0;
  31225 #endif /* BCM_TRIUMPH_SUPPORT */
  31226 
  31227     if (intf_info->l3i_vrf < 0) {
  31228         return BCM_E_PARAM;
  31229     }
  31230 
  31231     if (SOC_MEM_FIELD_VALID(unit, VLAN_TABm, VRF_IDf)) {
  31232         bcm_vlan_control_vlan_t vlan_control;
  31233 
  31234         sal_memset(&vlan_control, 0, sizeof(vlan_control));
  31235         /*
  31236          * Need to use the ALL mask for _bcm_xgs3_vlan_control_vlan_get()
  31237          * due to the current implementation in
  31238          * _bcm_xgs3_vlan_control_vlan_set().
  31239          * This _set() routine sets other fields besides the ones
  31240          * specified by the "valid_fields" parameter
  31241          */
  31242         rv = _bcm_xgs3_vlan_control_vlan_get(unit, intf_info->l3i_vid,
  31243                                              BCM_VLAN_CONTROL_VLAN_ALL_MASK,
  31244                                              &vlan_control);
  31245         if ((BCM_E_NOT_FOUND == rv) || (BCM_E_UNAVAIL == rv)) {
  31246             /* Assuming application will set vrf id later on
  31247                through vlan commands. */
  31248             return BCM_E_NONE;
  31249         }
  31250 
  31251         /* Return any other error. */
  31252         if (BCM_FAILURE(rv)){
  31253             return (rv);
  31254         }
  31255 
  31256         vlan_control.vrf = intf_info->l3i_vrf;
  31257         BCM_IF_ERROR_RETURN
  31258             (_bcm_xgs3_vlan_control_vlan_set(unit, intf_info->l3i_vid,
  31259                                              BCM_VLAN_CONTROL_VLAN_VRF_MASK,
  31260                                              &vlan_control));
  31261     }
  31262 #if defined(BCM_TRIUMPH_SUPPORT)
  31263     else {
  31264         if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
  31265             BCM_IF_ERROR_RETURN
  31266                 (bcm_xgs3_l3_ingress_intf_map_get(unit, &ingress_map_mode));
  31267         }
  31268         if (!ingress_map_mode) {
  31269             BCM_IF_ERROR_RETURN
  31270                 (_bcm_tr_l3_intf_vrf_bind(unit,
  31271                                           intf_info->l3i_vid,
  31272                                           intf_info->l3i_vrf));
  31273         }
  31274     }
  31275 #endif /* BCM_TRIUMPH_SUPPORT */
  31276 
  31277     return BCM_E_NONE;
  31278 }
  31279 
  31280 /*
  31281  * Function:
  31282  *      _bcm_fb_l3_intf_vrf_unbind
  31283  * Purpose:
  31284  *      Restore VRF value to defaults.
  31285  * Parameters:
  31286  *      unit      - (IN) SOC unit number.
  31287  *      intf_info - (IN) Interface configuration info.
  31288  * Returns:
  31289  *      BCM_E_XXX.
  31290  */
  31291     STATIC int
  31292 _bcm_fb_l3_intf_vrf_unbind(int unit, _bcm_l3_intf_cfg_t *intf_info)
  31293 {
  31294     int rv;
  31295     bcm_vrf_t vrf_temp;
  31296 
  31297     vrf_temp = intf_info->l3i_vrf;
  31298     intf_info->l3i_vrf = BCM_L3_VRF_DEFAULT;
  31299 
  31300     rv = _bcm_fb_l3_intf_vrf_bind(unit, intf_info);
  31301 
  31302     if ((BCM_E_NOT_FOUND == rv) || (BCM_E_PARAM == rv) ||
  31303             (BCM_E_UNAVAIL == rv)) {
  31304         /* Assuming application did not set vrf. */
  31305         return BCM_E_NONE;
  31306     }
  31307 
  31308     /* Restore original value */
  31309     intf_info->l3i_vrf = vrf_temp;
  31310 
  31311     return rv;
  31312 }
  31313 
  31314 #ifdef BCM_TRIDENT2_SUPPORT
  31315 /*
  31316  * Function:
  31317  *      _bcm_fb_l3_intf_nat_realm_id_set
  31318  * Purpose:
  31319  *      Set the NAT realm id for the interface.
  31320  * Parameters:
  31321  *      unit      - (IN) SOC unit number.
  31322  *      intf_info - (IN) Interface configuration info.
  31323  * Returns:
  31324  *      BCM_E_XXX.
  31325  */
  31326 STATIC int
  31327 _bcm_fb_l3_intf_nat_realm_id_set(int unit, _bcm_l3_intf_cfg_t *intf_info)
  31328 {
  31329     bcm_vlan_t vid;
  31330     uint32  buf[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer.     */
  31331     soc_mem_t vlan_attrs_mem = VLAN_MPLSm;
  31332     soc_mem_t vlan_mem = VLAN_TABm;
  31333     
  31334     vid = intf_info->l3i_vid;
  31335     sal_memset (buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
  31336 
  31337 #ifdef BCM_TRIDENT3_SUPPORT
  31338     if (SOC_IS_TRIDENT3X(unit)) {
  31339         vlan_attrs_mem = VLAN_TABm;
  31340         vlan_mem = VLAN_TABm;
  31341     }
  31342 #endif
  31343     if (BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit)) {
  31344         /* Get Vlan mapping */
  31345 
  31346         /* The current logic needs to be duplicated
  31347          * from _bcm_xgs3_vlan_control_vlan_set() in order
  31348          * to avoid deadlock between the L3 and the VLAN modules.
  31349          */
  31350 
  31351         if (SOC_MEM_FIELD_VALID(unit, vlan_attrs_mem, L3_IIFf)) {
  31352 
  31353             /*
  31354              * Check that L3_IIF is valid before using it.
  31355              * Allow case when VLAN has not been created yet.
  31356              * Assuming application will this later on
  31357              * through vlan commands.
  31358              */
  31359             SOC_IF_ERROR_RETURN
  31360                 (soc_mem_read(unit, vlan_mem, MEM_BLOCK_ANY, (int) vid, buf));
  31361             if (!soc_mem_field32_get(unit, vlan_mem, buf, VALIDf)) {
  31362                 return BCM_E_NONE;
  31363             }
  31364 
  31365             sal_memset (buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
  31366             BCM_IF_ERROR_RETURN
  31367                 (soc_mem_read(unit, vlan_attrs_mem, MEM_BLOCK_ANY, vid,
  31368                               buf));
  31369             vid = soc_mem_field32_get(unit, vlan_attrs_mem,
  31370                                       buf, L3_IIFf);
  31371         } else {
  31372             vid = 0;
  31373         }
  31374     }
  31375 
  31376     BCM_IF_ERROR_RETURN
  31377         (_bcm_tr_l3_intf_nat_realm_id_set(unit, vid,
  31378                                           intf_info->l3i_nat_realm_id));
  31379     return BCM_E_NONE;
  31380 }
  31381 
  31382 /*
  31383  * Function:
  31384  *      _bcm_fb_l3_intf_nat_realm_id_get
  31385  * Purpose:
  31386  *      Get the NAT realm id for the specified L3 interface
  31387  * Parameters:
  31388  *      unit      - (IN)SOC unit number.
  31389  *      intf_info - (IN/OUT)Interface configuration info.
  31390  * Returns:
  31391  *      BCM_E_XXX.
  31392  */
  31393 STATIC int
  31394 _bcm_fb_l3_intf_nat_realm_id_get(int unit, _bcm_l3_intf_cfg_t *intf_info)
  31395 {
  31396     int nat_realm_id = 0;
  31397     int ret_val = BCM_E_NONE;               /* Operation return value.       */
  31398 
  31399 #if defined(BCM_TRIUMPH_SUPPORT)
  31400     int  ingress_map_mode = 0;
  31401     _bcm_l3_ingress_intf_t iif; /* Ingress interface config.*/
  31402 
  31403 #ifdef BCM_RIOT_SUPPORT
  31404     if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info->l3i_vid)) { 
  31405         return BCM_E_NONE;
  31406     }
  31407 #endif
  31408 
  31409     if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
  31410         BCM_IF_ERROR_RETURN(
  31411            bcm_xgs3_l3_ingress_intf_map_get(unit, &ingress_map_mode));
  31412     }
  31413 
  31414     if (ingress_map_mode) {
  31415         iif.intf_id = intf_info->l3i_index;
  31416         ret_val     = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif);
  31417         nat_realm_id  = iif.nat_realm_id;
  31418     } else
  31419 #endif /* BCM_TRIUMPH_SUPPORT */
  31420 
  31421     {
  31422         if (SOC_MEM_IS_VALID(unit, L3_IIFm) &&
  31423             SOC_MEM_FIELD_VALID(unit, L3_IIFm, SRC_REALM_IDf)) {
  31424             ret_val = _bcm_tr_l3_intf_nat_realm_id_get(unit,
  31425                                 intf_info->l3i_vid, &nat_realm_id);
  31426         }
  31427     }
  31428 
  31429     if (BCM_SUCCESS(ret_val)) {
  31430         /* Get Virtual Router id */
  31431         intf_info->l3i_nat_realm_id = nat_realm_id;
  31432     }
  31433 
  31434     return (BCM_E_NONE);
  31435 }
  31436 #endif /* BCM_TRIDENT2_SUPPORT */
  31437 
  31438 /*
  31439  * Function:
  31440  *      _bcm_fb_nh_add
  31441  * Purpose:
  31442  *      Routine set next hop entry in the chip.
  31443  * Parameters:
  31444  *      unit      - (IN)SOC unit number.
  31445  *      idx       - (IN)Allocated entry index.
  31446  *      buf       - (IN)Next hop entry data.
  31447  * Returns:
  31448  *    BCM_E_XXX
  31449  */
  31450 STATIC int
  31451 _bcm_fb_nh_add(int unit, int idx, void *buf, void *info)
  31452 {
  31453     ing_l3_next_hop_entry_t in_entry;   /* Buffer to read ingress nh entry. */
  31454     egr_l3_next_hop_entry_t eg_entry;   /* Buffer to read egress nh entry.  */
  31455 #ifdef BCM_TOMAHAWK3_SUPPORT
  31456     egr_l3_next_hop_2_entry_t eg_2_entry;   /* Buffer to read egress nh entry.  */
  31457     soc_mem_t mem2;                      /* Next hop table memory.           */
  31458 #endif
  31459     bcm_l3_egress_t *nh_entry;          /* Next hop entry passed buffer.    */
  31460     int tunnel_id;                      /* Tunnel id attached to interface. */
  31461     soc_mem_t mem;                      /* Next hop table memory.           */
  31462     uint32 entry_type=0;
  31463     int max_intf = 0;
  31464 #ifdef BCM_RIOT_SUPPORT
  31465     uint32 nh_dest = 0;
  31466 #endif
  31467 #ifdef BCM_TRIDENT2_SUPPORT
  31468     _bcm_l3_ingress_intf_t iif;
  31469 #endif
  31470 #if defined(BCM_MONTEREY_SUPPORT)
  31471     soc_field_t field = INVALIDf, field2 = INVALIDf;
  31472 #endif
  31473     bcm_port_t nh_port;
  31474 
  31475     /* Input parameters check */
  31476     if (NULL == buf) {
  31477         return (BCM_E_PARAM);
  31478     }
  31479 
  31480     nh_entry = (bcm_l3_egress_t *) buf;
  31481 
  31482     if ((nh_entry->flags & BCM_L3_IPMC) &&
  31483         !(nh_entry->flags & BCM_L3_L2GRE_ONLY) &&
  31484         !(nh_entry->flags & BCM_L3_VXLAN_ONLY)) {
  31485 #ifdef BCM_TRIUMPH3_SUPPORT
  31486         if (soc_feature(unit, soc_feature_repl_l3_intf_use_next_hop)) {
  31487             /* Triumph3 is the first XGS device in which MMU no longer
  31488              * replicates L3 interfaces directly. Rather, MMU will output
  31489              * next hop indices, and L3 interface will be derived from
  31490              * egress next hop entry having the type L3MC.
  31491              */
  31492             return _bcm_tr3_l3_ipmc_nh_add(unit, idx, nh_entry);
  31493         } else
  31494 #endif /* BCM_TRIUMPH3_SUPPORT */
  31495         {
  31496             /* Greyhound through 'soc_feature_l3mc_use_egress_next_hop' to
  31497              * support new L3MC egress logic. This egress logic for IPMC
  31498              * replication will use egress next hop entry to reference L3
  31499              * interface entry always.
  31500              */
  31501             if (!soc_feature(unit, soc_feature_l3mc_use_egress_next_hop)) {
  31502                 return BCM_E_UNAVAIL;
  31503             }
  31504         }
  31505     }
  31506 
  31507     /* Zero buffers. */
  31508     sal_memset(&in_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, nh));
  31509     sal_memset(&eg_entry, 0, sizeof(egr_l3_next_hop_entry_t));
  31510 #ifdef BCM_TOMAHAWK3_SUPPORT
  31511     if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) {
  31512         sal_memset(&eg_2_entry, 0, sizeof(egr_l3_next_hop_2_entry_t));
  31513     }
  31514 #endif
  31515 
  31516     mem = ING_L3_NEXT_HOPm;
  31517 
  31518     /* Read ingress next hop entry. */
  31519     BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, &in_entry));
  31520    if (nh_entry->intf == BCM_XGS3_L3_L2CPU_INTF_IDX(unit)) {
  31521        soc_mem_field32_set(unit, mem, &in_entry, VLAN_IDf, nh_entry->vlan);
  31522    } else {
  31523        if (SOC_MEM_FIELD_VALID(unit, mem, L3_OIFf) && 
  31524            (BCM_XGS3_L3_INTF_VLAN_SPLIT_EGRESS_MODE_ISSET(unit))) {
  31525             max_intf = (1 << soc_mem_field_length(unit, mem, L3_OIFf)) - 1;
  31526             if (nh_entry->intf > max_intf) {
  31527                 return BCM_E_PARAM;
  31528             }
  31529             soc_mem_field32_set(unit, mem, &in_entry, L3_OIFf, nh_entry->intf);
  31530         } else {
  31531             soc_mem_field32_set(unit, mem, &in_entry, VLAN_IDf, nh_entry->vlan);
  31532         }
  31533     }
  31534 
  31535 
  31536 #if defined(BCM_HURRICANE_SUPPORT) || defined(BCM_HURRICANE2_SUPPORT) || \
  31537     defined(BCM_GREYHOUND_SUPPORT)
  31538     if (SOC_MEM_FIELD_VALID(unit, mem, INTF_NUMf)) {
  31539         soc_mem_field32_set(unit, mem, &in_entry, INTF_NUMf, nh_entry->intf);
  31540     }
  31541 #endif /* BCM_HURRICANE_SUPPORT */
  31542 
  31543 #ifdef BCM_RIOT_SUPPORT
  31544    /*
  31545     * TD2+ has a separate encoding values for different destinations. 
  31546     * If Riot in not enabled then we may need to change this to 
  31547     * modid + port combination.
  31548     */
  31549     if (soc_feature(unit, soc_feature_ing_l3_next_hop_encoded_dest)) { 
  31550         BCM_IF_ERROR_RETURN(
  31551             bcmi_l3_nh_dest_set(unit, nh_entry, &nh_dest));
  31552 
  31553         soc_mem_field32_set(unit, mem, &in_entry, DESTINATIONf, 
  31554             nh_dest);
  31555 
  31556         LOG_INFO(BSL_LS_BCM_L3, (BSL_META_U(unit,
  31557             "Setting up destination = 0x%x for port = 0x%x\n"), nh_dest, 
  31558             nh_entry->port));
  31559     } else 
  31560 #ifdef BCM_TRIDENT3_SUPPORT
  31561     if (soc_feature(unit, soc_feature_generic_dest)) {
  31562 
  31563         BCM_IF_ERROR_RETURN(
  31564             bcmi_td3_l3_nh_dest_set(unit, nh_entry, &nh_dest));
  31565 
  31566         soc_mem_field32_set(unit, mem, &in_entry, DESTINATIONf,
  31567             nh_dest);
  31568     } else
  31569 #endif /* BCM_TRIDENT3_SUPPORT */
  31570 #endif /* BCM_RIOT_SUPPORT */
  31571     {
  31572         if (soc_feature(unit, soc_feature_generic_dest)) {
  31573             /* Set module id. */
  31574             if (soc_feature(unit, soc_feature_trunk_group_overlay)) {
  31575                 if (nh_entry->flags & BCM_L3_TGID) {
  31576                    soc_mem_field32_dest_set(unit, ING_L3_NEXT_HOPm, &in_entry,
  31577                       DESTINATIONf, SOC_MEM_FIF_DEST_LAG, nh_entry->port);
  31578                } else {
  31579                    soc_mem_field32_dest_set(unit, ING_L3_NEXT_HOPm, &in_entry,
  31580                       DESTINATIONf, SOC_MEM_FIF_DEST_DGPP,
  31581                       (nh_entry->module << SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS |
  31582                             nh_entry->port));
  31583                }
  31584             }
  31585         } else {
  31586             nh_port = nh_entry->port;
  31587 #if defined(BCM_MONTEREY_SUPPORT)
  31588             if (soc_feature(unit, soc_feature_xflow_macsec) &&
  31589                 ((nh_entry->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_ENCRYPT) ||
  31590                 (nh_entry->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_DECRYPT))) {
  31591                 nh_port = 66;
  31592             }
  31593 #endif
  31594             if (!SOC_IS_TOMAHAWK3(unit)) {
  31595                 /* Set module id. */
  31596                 soc_mem_field32_set(
  31597                     unit, mem, &in_entry, MODULE_IDf, nh_entry->module);
  31598             }
  31599 #ifdef BCM_TRX_SUPPORT
  31600            if (soc_feature(unit, soc_feature_trunk_group_overlay)) {
  31601 
  31602             if (nh_entry->flags & BCM_L3_TGID) {
  31603                 soc_mem_field32_set(unit, mem, &in_entry, Tf, 1);
  31604                     soc_mem_field32_set(unit, mem, &in_entry, TGIDf, nh_port);
  31605             } else {
  31606                 soc_mem_field32_set(unit, mem, &in_entry, Tf, 0);
  31607                     soc_mem_field32_set(
  31608                             unit, mem, &in_entry, PORT_NUMf, nh_port);
  31609             }
  31610           } else
  31611 #endif /* BCM_TRX_SUPPORT */
  31612         {
  31613             /* Set port/trunk id. */
  31614             if (SOC_IS_TOMAHAWKX(unit)) {
  31615                 /*
  31616                      * implies the switch has a latency mode enabled. trunking
  31617                      * is not supported in any latency mode in TH.
  31618                  */
  31619                 soc_mem_field32_set(unit, mem, &in_entry, Tf, 0);
  31620                     soc_mem_field32_set(
  31621                         unit, mem, &in_entry, PORT_NUMf, nh_port);
  31622             } else {
  31623                     soc_mem_field32_set(
  31624                         unit, mem, &in_entry, PORT_TGIDf, nh_port);
  31625             }
  31626         }
  31627         }
  31628      }
  31629 
  31630     if (nh_entry->flags & BCM_L3_COPY_TO_CPU)  {
  31631         if (SOC_MEM_FIELD_VALID(unit, mem, COPY_TO_CPUf)) {
  31632             soc_mem_field32_set(unit, mem, &in_entry, COPY_TO_CPUf, 1);
  31633         } else {
  31634             return (BCM_E_UNAVAIL);
  31635         }
  31636     } else {
  31637         if (SOC_MEM_FIELD_VALID(unit, mem, COPY_TO_CPUf)) {
  31638             soc_mem_field32_set(unit, mem, &in_entry, COPY_TO_CPUf, 0);
  31639         }
  31640     }
  31641 
  31642     if (nh_entry->flags & BCM_L3_DST_DISCARD) {
  31643         if (SOC_MEM_FIELD_VALID(unit, mem, DROPf)) {
  31644             soc_mem_field32_set(unit, mem, &in_entry, DROPf, 1);
  31645         }
  31646         /*
  31647          * Host or route entry will handle drop
  31648          * condition no else required.
  31649          */
  31650     } else {
  31651         if (SOC_MEM_FIELD_VALID(unit, mem, DROPf)) {
  31652             soc_mem_field32_set(unit, mem, &in_entry, DROPf, 0);
  31653         }
  31654     }
  31655 
  31656     if (idx != BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit)) {
  31657         /* Set interface is tunnel bit. */
  31658         BCM_IF_ERROR_RETURN
  31659             (_bcm_xgs3_l3_get_tunnel_id(unit, nh_entry->intf, &tunnel_id));
  31660 
  31661         /* Set flag that packet going to be tunneled. */
  31662         if (tunnel_id) {
  31663             if (SOC_MEM_FIELD_VALID(unit, mem, L3UC_TUNNEL_TYPEf)) {
  31664                 soc_mem_field32_set(unit, mem, &in_entry, L3UC_TUNNEL_TYPEf, 1);
  31665             }
  31666 #if defined(BCM_TRIUMPH_SUPPORT)
  31667             if (SOC_MEM_FIELD_VALID(unit, mem, ENTRY_TYPEf)) {
  31668                 soc_mem_field32_set(unit, mem, &in_entry, ENTRY_TYPEf, 1);
  31669             }
  31670 #endif /* BCM_TRIUMPH_SUPPORT */
  31671         }
  31672     }
  31673 #ifdef BCM_TRIDENT2_SUPPORT
  31674     if (soc_feature(unit, soc_feature_nat)) {
  31675         uint32  entry_buf[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer.*/
  31676         soc_mem_t vlan_mem = VLAN_MPLSm;
  31677 #ifdef BCM_TRIDENT3_SUPPORT
  31678         if (SOC_IS_TRIDENT3X(unit)) {
  31679             vlan_mem = VLAN_TABm;
  31680         }
  31681 #endif
  31682 
  31683         /* get realm id from the incoming interface */
  31684         if (BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit) &&
  31685             SOC_MEM_FIELD_VALID(unit, vlan_mem, L3_IIFf)) {
  31686             sal_memset(entry_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
  31687             SOC_IF_ERROR_RETURN(
  31688                 soc_mem_read(unit, vlan_mem, MEM_BLOCK_ANY,
  31689                              nh_entry->vlan, entry_buf));
  31690             iif.intf_id = soc_mem_field32_get(unit, vlan_mem,
  31691                                               entry_buf, L3_IIFf);
  31692         } else {
  31693             iif.intf_id = nh_entry->vlan;
  31694         }
  31695         BCM_IF_ERROR_RETURN(_bcm_tr_l3_ingress_interface_get(unit, NULL, &iif));
  31696 
  31697         if (SOC_MEM_FIELD_VALID(unit, mem, DST_REALM_IDf)) {
  31698             soc_mem_field32_set(unit, mem, &in_entry, DST_REALM_IDf,
  31699                                 iif.nat_realm_id);
  31700         }
  31701     }
  31702 #endif
  31703 
  31704     /* Write ingress next hop entry. */
  31705     BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_WRITE(unit, mem, idx, &in_entry));
  31706 
  31707     mem = EGR_L3_NEXT_HOPm;
  31708 #ifdef BCM_TOMAHAWK3_SUPPORT
  31709     mem2 = EGR_L3_NEXT_HOP_2m;
  31710 #endif
  31711 
  31712     /* Read egress next hop entry. */
  31713     BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, &eg_entry));
  31714 #ifdef BCM_TOMAHAWK3_SUPPORT
  31715     if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) {
  31716         BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, EGR_L3_NEXT_HOP_2m, idx, &eg_2_entry));
  31717 
  31718     }
  31719 #endif
  31720 #ifdef BCM_TRIDENT3_SUPPORT
  31721     if (soc_feature(unit, soc_feature_flex_flow) &&
  31722         (nh_entry->flow_handle != 0)) {
  31723 
  31724         BCM_IF_ERROR_RETURN
  31725             (_bcm_td3_l3_flex_nh_add(unit, idx, nh_entry, (uint32 *)&eg_entry, 0));
  31726 
  31727     }
  31728     else
  31729 #endif
  31730     {
  31731 #if defined(BCM_GREYHOUND_SUPPORT)
  31732         if (soc_feature(unit, soc_feature_l3mc_use_egress_next_hop)) {
  31733            if ((nh_entry->flags & BCM_L3_IPMC) &&
  31734                !(nh_entry->flags & BCM_L3_L2GRE_ONLY) &&
  31735                !(nh_entry->flags & BCM_L3_VXLAN_ONLY)) {
  31736                 /* Special process for GH's L3MC entry.
  31737                 *
  31738                 * 1. write to egress nh entry for L3MC view only.
  31739                 * 2. write to a dummy INITIAL_ING_L3_NEXT_HOPm entry.
  31740                 *    - this table and ING_L3_NEXT_HOPm are ignored for
  31741                 *      IPMC logic in GH.
  31742                 */
  31743 
  31744                 /* Set ENTRY_TYPE to L3MC view */
  31745                 soc_mem_field32_set(unit, mem, &eg_entry, nh_entry_type_field[unit], 0x7);
  31746 
  31747                 /* set next hop interface number */
  31748                 soc_mem_field32_set(unit, mem, &eg_entry, L3MC__INTF_NUMf,
  31749                         nh_entry->intf);
  31750 
  31751                 /* set l3mc_use_configured _mac */
  31752                 if (nh_entry->flags & BCM_L3_KEEP_DSTMAC) {
  31753                     soc_mem_field32_set(unit, mem, &eg_entry,
  31754                             L3MC__L3MC_USE_CONFIGURED_MACf, 0);
  31755                 } else {
  31756                     /* Use MAC_ADDRESS configured in this table */
  31757                     soc_mem_field32_set(unit, mem, &eg_entry,
  31758                             L3MC__L3MC_USE_CONFIGURED_MACf, 1);
  31759                 }
  31760 
  31761                 /* set l3mc_mac_address*/
  31762                 soc_mem_mac_addr_set(unit, mem, &eg_entry, L3MC__MAC_ADDRESSf,
  31763                         nh_entry->mac_addr);
  31764 
  31765                 /* goto hw mem write operation */
  31766                 goto l3mc_egr_nh_done;
  31767             }
  31768         }
  31769 #endif  /* BCM_GREYHOUND_SUPPORT */
  31770 
  31771 #if defined(BCM_TRIUMPH_SUPPORT)
  31772         if (SOC_MEM_FIELD_VALID(unit, mem, nh_entry_type_field[unit])) {
  31773             entry_type = soc_mem_field32_get (unit, mem, &eg_entry,
  31774                     nh_entry_type_field[unit]);
  31775         }
  31776         if ((nh_entry->oam_global_context_id) && 
  31777             SOC_MEM_FIELD_VALID(unit, mem, MPLS__MEPIDf)) {
  31778             soc_mem_field32_set(unit, mem, &eg_entry, MPLS__MEPIDf,
  31779                                 nh_entry->oam_global_context_id);
  31780             /* Writing MPLS LM/DM value. it doesnt matter since
  31781                data packets are similar for BHH and MPLS LM/DM */
  31782             soc_mem_field32_set(unit, mem, &eg_entry, MPLS__MPLS_OAM_DOWNMEP_ENABLEf,
  31783                                 2); 
  31784         }
  31785         if ((soc_feature(unit, soc_feature_nh_for_ifp_actions) ||
  31786                     SOC_IS_TOMAHAWK3(unit)) &&
  31787                  (nh_entry->flags2 & BCM_L3_FLAGS2_FIELD_ONLY)) {
  31788             entry_type = 2;
  31789         }
  31790 #endif /* BCM_TRIUMPH_SUPPORT */
  31791 #ifdef BCM_TRIDENT3_SUPPORT
  31792         if (SOC_IS_TRIDENT3X(unit)) {
  31793             if (nh_entry->flags2 & BCM_L3_FLAGS2_FCOE_ONLY) {
  31794                 if (SOC_MEM_FIELD_VALID(unit, mem, DATA_TYPEf)) {
  31795                     soc_mem_field32_set(unit, mem, &eg_entry, DATA_TYPEf, 8);
  31796                 }
  31797             }
  31798         }
  31799 #endif /* BCM_TRIDENT3_SUPPORT */
  31800         if ((entry_type == 0) ||
  31801                 ((soc_feature(unit, soc_feature_nh_for_ifp_actions) ||
  31802                   SOC_IS_TOMAHAWK3(unit)) &&
  31803                  (entry_type == 2))) { /* L3 Unicast */
  31804 #ifdef BCM_TRIUMPH2_SUPPORT
  31805             if (entry_type == 2) {
  31806                 if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_VLAN_DISABLEf)) {
  31807                     soc_mem_field32_set(unit, mem, &eg_entry, IFP_ACTIONS__L3_UC_VLAN_DISABLEf,
  31808                             _SHR_IS_FLAG_SET(nh_entry->flags,
  31809                                 BCM_L3_KEEP_VLAN));
  31810                 }
  31811                 if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_TTL_DISABLEf)) {
  31812                     soc_mem_field32_set(unit, mem, &eg_entry, IFP_ACTIONS__L3_UC_TTL_DISABLEf,
  31813                             _SHR_IS_FLAG_SET(nh_entry->flags,
  31814                                 BCM_L3_KEEP_TTL));
  31815                 }
  31816                 if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_DA_DISABLEf)) {
  31817                     soc_mem_field32_set(unit, mem, &eg_entry, IFP_ACTIONS__L3_UC_DA_DISABLEf,
  31818                             _SHR_IS_FLAG_SET(nh_entry->flags,
  31819                                 BCM_L3_KEEP_DSTMAC));
  31820                 }
  31821                 if (SOC_MEM_FIELD_VALID(unit, mem, IFP_ACTIONS__L3_UC_SA_DISABLEf)) {
  31822                     soc_mem_field32_set(unit, mem, &eg_entry, IFP_ACTIONS__L3_UC_SA_DISABLEf,
  31823                             _SHR_IS_FLAG_SET(nh_entry->flags,
  31824                                 BCM_L3_KEEP_SRCMAC));
  31825                 }
  31826             } else {
  31827                 if (SOC_MEM_FIELD_VALID(unit, mem, L3__L3_UC_VLAN_DISABLEf)) {
  31828                     soc_mem_field32_set(unit, mem, &eg_entry, L3__L3_UC_VLAN_DISABLEf,
  31829                             _SHR_IS_FLAG_SET(nh_entry->flags,
  31830                                 BCM_L3_KEEP_VLAN));
  31831                 }
  31832                 if (SOC_MEM_FIELD_VALID(unit, mem, L3__L3_UC_TTL_DISABLEf)) {
  31833                     soc_mem_field32_set(unit, mem, &eg_entry, L3__L3_UC_TTL_DISABLEf,
  31834                             _SHR_IS_FLAG_SET(nh_entry->flags,
  31835                                 BCM_L3_KEEP_TTL));
  31836                 }
  31837                 if (SOC_MEM_FIELD_VALID(unit, mem, L3__L3_UC_DA_DISABLEf)) {
  31838                     soc_mem_field32_set(unit, mem, &eg_entry, L3__L3_UC_DA_DISABLEf,
  31839                             _SHR_IS_FLAG_SET(nh_entry->flags,
  31840                                 BCM_L3_KEEP_DSTMAC));
  31841                 }
  31842                 if (SOC_MEM_FIELD_VALID(unit, mem, L3__L3_UC_SA_DISABLEf)) {
  31843                     soc_mem_field32_set(unit, mem, &eg_entry, L3__L3_UC_SA_DISABLEf,
  31844                             _SHR_IS_FLAG_SET(nh_entry->flags,
  31845                                 BCM_L3_KEEP_SRCMAC));
  31846                 }
  31847             }
  31848             if (SOC_MEM_FIELD_VALID(unit, mem, L3__CLASS_IDf)) {
  31849                 soc_mem_field32_set(unit, mem, &eg_entry, L3__CLASS_IDf,
  31850                         nh_entry->intf_class);
  31851             }
  31852 #endif /* BCM_TRIUMPH2_SUPPORT */
  31853 #ifdef BCM_TRIDENT3_SUPPORT
  31854             if (soc_feature(unit, soc_feature_flex_flow) &&
  31855                 (nh_entry->flags2 & BCM_L3_FLAGS2_IFA_DST_PORT)) {
  31856                 if (nh_entry->port > (1 << BCMI_TD3_L3_NH_IFA_DST_PORT_SHIFT)) {
  31857                     return BCM_E_PARAM;
  31858                 }
  31859                 if (SOC_MEM_FIELD_VALID(unit, mem, L3__VNTAG_ACTIONSf)) {
  31860                     soc_mem_field32_set(unit, mem, &eg_entry, L3__VNTAG_ACTIONSf, 1);
  31861                 }
  31862                 if (SOC_MEM_FIELD_VALID(unit, mem, L3__VNTAG_Pf)) {
  31863                     uint32 vntag_p =
  31864                         (nh_entry->module >> BCMI_TD3_L3_NH_IFA_DST_PORT_SHIFT) & 0x1;
  31865                     soc_mem_field32_set(unit, mem, &eg_entry, L3__VNTAG_Pf, vntag_p);
  31866                 }
  31867                 if (SOC_MEM_FIELD_VALID(unit, mem, L3__VNTAG_DST_VIFf)) {
  31868                     uint32 vntag_dst_vif =
  31869                         (nh_entry->port & BCMI_TD3_L3_NH_IFA_DST_PORT_MASK) |
  31870                         ((nh_entry->module & BCMI_TD3_L3_NH_IFA_DST_PORT_MASK) <<
  31871                         BCMI_TD3_L3_NH_IFA_DST_PORT_SHIFT);
  31872                     soc_mem_field32_set(unit, mem, &eg_entry,
  31873                         L3__VNTAG_DST_VIFf, vntag_dst_vif);
  31874                 }
  31875             }
  31876 #endif /* BCM_TRIDENT3_SUPPORT */
  31877         }
  31878 
  31879 #ifdef BCM_TRIDENT2_SUPPORT
  31880         if (soc_feature(unit, soc_feature_virtual_port_routing)) {
  31881             if (nh_entry->encap_id > 0 &&
  31882                     nh_entry->encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit)) {
  31883                 /* encap_id contains the virtual port value if it's greater than 0 and
  31884                  * less than the starting value of egress object ID.
  31885                  */
  31886                 bcm_niv_port_t niv_port;
  31887                 int count;
  31888                 bcm_niv_egress_t niv_egress;
  31889                 int virtual_interface_id;
  31890                 bcm_extender_port_t ep;
  31891                 int etag_dot1p_mapping_ptr = 0;
  31892                 bcm_extender_egress_t extender_egress;
  31893                 uint16 extended_port_vid;
  31894                 uint8 pcp, de;
  31895                 uint32 pcp_de_select;
  31896                 int qos_map_id;
  31897 
  31898                 if (_bcm_vp_used_get(unit, nh_entry->encap_id, _bcmVpTypeNiv)) {
  31899                     /* NIV */
  31900                     BCM_GPORT_NIV_PORT_ID_SET(niv_port.niv_port_id, nh_entry->encap_id);
  31901                     BCM_IF_ERROR_RETURN(bcm_esw_niv_port_get(unit, &niv_port));
  31902                     if (niv_port.flags & BCM_NIV_PORT_MATCH_NONE) {
  31903                         BCM_IF_ERROR_RETURN(bcm_esw_niv_egress_get(unit,
  31904                                     niv_port.niv_port_id, 1, &niv_egress, &count));
  31905                         if (count == 0) {
  31906                             /* No NIV egress object has been added to VP yet. */
  31907                             return BCM_E_CONFIG;
  31908                         }
  31909                         if (niv_egress.flags & BCM_NIV_EGRESS_MULTICAST) {
  31910                             return BCM_E_PARAM;
  31911                         }
  31912                         virtual_interface_id = niv_egress.virtual_interface_id;
  31913                     } else {
  31914                         if (niv_port.flags & BCM_NIV_PORT_MULTICAST) {
  31915                             return BCM_E_PARAM;
  31916                         }
  31917                         virtual_interface_id = niv_port.virtual_interface_id;
  31918                     }
  31919                     if (soc_mem_field_valid(unit, mem, L3__DVP_VALIDf)) {
  31920                         soc_mem_field32_set(unit, mem, &eg_entry, L3__DVP_VALIDf,
  31921                                 TRUE);
  31922                     }
  31923                     soc_mem_field32_set(unit, mem, &eg_entry, L3__DVPf,
  31924                             nh_entry->encap_id);
  31925                     soc_mem_field32_set(unit, mem, &eg_entry, L3__HG_HDR_SELf,
  31926                             TRUE); /* PPD-2 header */
  31927                     soc_mem_field32_set(unit, mem, &eg_entry, L3__VNTAG_ACTIONSf,
  31928                             1); /* Add or replace VNTAG */
  31929                     soc_mem_field32_set(unit, mem, &eg_entry, L3__VNTAG_DST_VIFf,
  31930                             virtual_interface_id);
  31931                     soc_mem_field32_set(unit, mem, &eg_entry, L3__VNTAG_Pf,
  31932                             0);
  31933                     soc_mem_field32_set(unit, mem, &eg_entry, L3__VNTAG_FORCE_Lf,
  31934                             (niv_port.flags & BCM_NIV_VNTAG_L_BIT_FORCE_1) ? 1 : 0);
  31935 #ifdef BCM_TOMAHAWK_SUPPORT
  31936                     if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
  31937                         if (nh_entry->flags2 & BCM_L3_FLAGS2_NIV_ENCAP_LOCAL) {
  31938                             soc_mem_field32_set(unit, mem, &eg_entry,
  31939                                                 L3__HG_VNTAG_MODIFY_ENABLEf, 1);
  31940                         } else {
  31941                             soc_mem_field32_set(unit, mem, &eg_entry,
  31942                                                 L3__HG_VNTAG_MODIFY_ENABLEf, 0);
  31943                         }
  31944                     }
  31945 #endif
  31946                 } else if (_bcm_vp_used_get(unit, nh_entry->encap_id, _bcmVpTypeExtender)) {
  31947                     /* Port Extender */
  31948                     BCM_GPORT_EXTENDER_PORT_ID_SET(ep.extender_port_id, nh_entry->encap_id);
  31949                     BCM_IF_ERROR_RETURN(bcm_esw_extender_port_get(unit, &ep));
  31950                     if (ep.flags & BCM_EXTENDER_PORT_MATCH_NONE) {
  31951                         bcm_extender_egress_t_init(&extender_egress);
  31952                         BCM_IF_ERROR_RETURN(bcm_esw_extender_egress_get_all(unit,
  31953                                     ep.extender_port_id, 1, &extender_egress, &count));
  31954                         if (count == 0) {
  31955                             /* No Extender egress object has been added to VP yet. */
  31956                             return BCM_E_CONFIG;
  31957                         }
  31958                         if (extender_egress.flags & BCM_EXTENDER_EGRESS_MULTICAST) {
  31959                             return BCM_E_PARAM;
  31960                         }
  31961                         qos_map_id        = extender_egress.qos_map_id;
  31962                         extended_port_vid = extender_egress.extended_port_vid;
  31963                         pcp_de_select     = extender_egress.pcp_de_select;
  31964                         pcp               = extender_egress.pcp;
  31965                         de                = extender_egress.de;
  31966                     } else {
  31967                         if (ep.flags & BCM_EXTENDER_PORT_MULTICAST) {
  31968                             return BCM_E_PARAM;
  31969                         }
  31970                         qos_map_id        = ep.qos_map_id;
  31971                         extended_port_vid = ep.extended_port_vid;
  31972                         pcp_de_select     = ep.pcp_de_select;
  31973                         pcp               = ep.pcp;
  31974                         de                = ep.de;
  31975                     }
  31976 
  31977                     if (soc_mem_field_valid(unit, mem, L3__DVP_VALIDf)) {
  31978                         soc_mem_field32_set(unit, mem, &eg_entry, L3__DVP_VALIDf,
  31979                                 TRUE);
  31980                     }
  31981                     soc_mem_field32_set(unit, mem, &eg_entry, L3__DVPf,
  31982                             nh_entry->encap_id);
  31983                     soc_mem_field32_set(unit, mem, &eg_entry, L3__HG_HDR_SELf,
  31984                             TRUE); /* PPD-2 header */
  31985                     soc_mem_field32_set(unit, mem, &eg_entry, L3__VNTAG_ACTIONSf,
  31986                             0x2); /* Add or replace ETAG */
  31987                     soc_mem_field32_set(unit, mem, &eg_entry, L3__VNTAG_DST_VIFf,
  31988                             extended_port_vid);
  31989                     if (pcp_de_select == BCM_EXTENDER_PCP_DE_SELECT_DEFAULT) {
  31990                         soc_mem_field32_set(unit, mem, &eg_entry, L3__ETAG_PCP_DE_SOURCEf, 0x2);
  31991                         soc_mem_field32_set(unit, mem, &eg_entry, L3__ETAG_PCPf, pcp);
  31992                         soc_mem_field32_set(unit, mem, &eg_entry, L3__ETAG_DEf, de);
  31993                     } else if (pcp_de_select == BCM_EXTENDER_PCP_DE_SELECT_PHB) {
  31994                         soc_mem_field32_set(unit, mem, &eg_entry, L3__ETAG_PCP_DE_SOURCEf, 0x3);
  31995                         bcm_td2_qos_egr_etag_id2profile(unit, qos_map_id,
  31996                                                         &etag_dot1p_mapping_ptr);
  31997                         soc_mem_field32_set(unit, mem, &eg_entry,
  31998                                             L3__ETAG_DOT1P_MAPPING_PTRf, etag_dot1p_mapping_ptr);
  31999                     }
  32000 #ifdef BCM_TOMAHAWK_SUPPORT
  32001                     if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
  32002                         if (nh_entry->flags2 & BCM_L3_FLAGS2_NIV_ENCAP_LOCAL) {
  32003                             soc_mem_field32_set(unit, mem, &eg_entry, 
  32004                                                 L3__HG_VNTAG_MODIFY_ENABLEf, 1);                   
  32005                         } else {
  32006                             soc_mem_field32_set(unit, mem, &eg_entry,
  32007                                                 L3__HG_VNTAG_MODIFY_ENABLEf, 0);
  32008                         }
  32009                     }
  32010 #endif                
  32011                 } else if (_bcm_vp_used_get(unit, nh_entry->encap_id, _bcmVpTypeVlan) ||
  32012                            _bcm_vp_used_get(unit, nh_entry->encap_id, _bcmVpTypeMpls)) {
  32013                      /* VEPA or MPLS */
  32014                     if (soc_mem_field_valid(unit, mem, L3__DVP_VALIDf)) {
  32015                         soc_mem_field32_set(unit, mem, &eg_entry, L3__DVP_VALIDf,
  32016                                 TRUE);
  32017                     }
  32018                     soc_mem_field32_set(unit, mem, &eg_entry, L3__DVPf,
  32019                             nh_entry->encap_id);
  32020                     soc_mem_field32_set(unit, mem, &eg_entry, L3__HG_HDR_SELf,
  32021                             TRUE); /* PPD-2 header */
  32022                 }
  32023             } else if (nh_entry->encap_id >= BCM_XGS3_EGRESS_IDX_MIN(unit)) {
  32024                 return BCM_E_PARAM;
  32025             } else if (entry_type == 0) {
  32026 
  32027                 /* Zero-out DVP values for regular NH */
  32028                if (SOC_MEM_FIELD_VALID(unit, mem, L3__DVP_VALIDf)) {
  32029                    soc_mem_field32_set(unit, mem, &eg_entry, L3__DVP_VALIDf, FALSE);
  32030                }
  32031 
  32032                if (SOC_MEM_FIELD_VALID(unit, mem, L3__DVPf)) {
  32033                    soc_mem_field32_set(unit, mem, &eg_entry, L3__DVPf, 0x0);
  32034                }
  32035 
  32036                if (SOC_MEM_FIELD_VALID(unit, mem, L3__HG_HDR_SELf)) {
  32037                    soc_mem_field32_set(unit, mem, &eg_entry, L3__HG_HDR_SELf,
  32038                            _SHR_IS_FLAG_SET(nh_entry->flags2,
  32039                                BCM_L3_FLAGS2_NON_PROXY_MODE));
  32040                }
  32041 
  32042             }
  32043         }
  32044 #endif /* BCM_TRIDENT2_SUPPORT */
  32045 
  32046 #ifdef BCM_TRIUMPH2_SUPPORT
  32047         if (soc_feature(unit, soc_feature_wlan) &&
  32048             (nh_entry->encap_id > 0 &&
  32049              nh_entry->encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit)) &&
  32050             _bcm_vp_used_get(unit, nh_entry->encap_id, _bcmVpTypeWlan)) {
  32051             /* Set ENTRY_TYPE to WLAN DVP */
  32052             if (SOC_MEM_FIELD_VALID(unit, mem, nh_entry_type_field[unit])) {
  32053                 soc_mem_field32_set(unit, mem, &eg_entry, nh_entry_type_field[unit], 4);
  32054             }
  32055             /* Set next hop mac address. */
  32056             soc_mem_mac_addr_set(unit, mem, &eg_entry, WLAN__MAC_ADDRESSf,
  32057                     nh_entry->mac_addr);
  32058             /* Set interface id. */
  32059             soc_mem_field32_set(unit, mem, &eg_entry, WLAN__INTF_NUMf,
  32060                     nh_entry->intf);
  32061             /* Set the DVP */
  32062             soc_mem_field32_set(unit, mem, &eg_entry, WLAN__DVPf,
  32063                     nh_entry->encap_id);
  32064 #if defined(BCM_TRIUMPH3_SUPPORT)
  32065             if (SOC_IS_TRIUMPH3(unit)) {
  32066                 soc_mem_field32_set(unit, mem, &eg_entry, WLAN__DGLPf,
  32067                         BCM_L3_DGLP_GET(nh_entry->module, nh_entry->port));
  32068             }
  32069 #endif /* BCM_TRIUMPH3_SUPPORT */
  32070         } else
  32071 #endif /* BCM_TRIUMPH2_SUPPORT */
  32072         {
  32073             soc_field_t mac_addr_field = MAC_ADDRESSf;
  32074             soc_field_t intf_field = INTF_NUMf;
  32075 
  32076             if (SOC_IS_TRIDENT3X(unit)) {
  32077                 mac_addr_field = L3__MAC_ADDRESSf;
  32078                 intf_field = L3__INTF_NUMf;
  32079             }
  32080             if (entry_type == 0) {
  32081                 /* Set next hop mac address. */
  32082                 soc_mem_mac_addr_set(unit, mem, &eg_entry, mac_addr_field,
  32083                         nh_entry->mac_addr);
  32084             } else if ((entry_type == 6) ||
  32085                        ((SOC_IS_TOMAHAWK3(unit)) && (entry_type == 2))) {
  32086                 if (soc_mem_field_valid(unit, mem, IFP_ACTIONS__MAC_ADDRESSf)) {
  32087                     soc_mem_mac_addr_set(unit, mem, &eg_entry,
  32088                                          IFP_ACTIONS__MAC_ADDRESSf,
  32089                                          nh_entry->mac_addr);
  32090                 }
  32091             } else if (entry_type == 7) {
  32092                 if (soc_mem_field_valid(unit, mem, L3MC__MAC_ADDRESSf)) {
  32093                     soc_mem_mac_addr_set(unit, mem, &eg_entry, L3MC__MAC_ADDRESSf,
  32094                           nh_entry->mac_addr);
  32095                 }
  32096 #ifdef BCM_TRIDENT3_SUPPORT
  32097                 if (SOC_IS_TRIDENT3X(unit)) {
  32098                     intf_field = L3MC__INTF_NUMf;
  32099                 }
  32100 #endif
  32101             }
  32102             /* Set interface id. */
  32103 #ifdef BCM_TOMAHAWK3_SUPPORT
  32104             if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) {
  32105                 soc_mem_field32_set(unit, mem2, &eg_2_entry, INTF_NUMf, nh_entry->intf);
  32106             } else
  32107 #endif
  32108             {
  32109             soc_mem_field32_set(unit, mem, &eg_entry, intf_field, nh_entry->intf);
  32110         }
  32111     }
  32112     }
  32113 #if defined(BCM_MONTEREY_SUPPORT)
  32114     if (soc_feature(unit, soc_feature_xflow_macsec) &&
  32115             ((nh_entry->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_ENCRYPT) ||
  32116              (nh_entry->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_DECRYPT))) {
  32117         switch (entry_type) {
  32118             case 0:
  32119                 field = L3__MACSEC_ENCRYPTf;
  32120                 field2 = L3__MACSEC_DECRYPTf;
  32121                 break;
  32122             case 1:
  32123                 field = MPLS__MACSEC_ENCRYPTf;
  32124                 field2 = MPLS__MACSEC_DECRYPTf;
  32125                 break;
  32126             case 2:
  32127                 field = SD_TAG__MACSEC_ENCRYPTf;
  32128                 field2 = SD_TAG__MACSEC_DECRYPTf;
  32129                 break;
  32130             case 6:
  32131                 field = IFP_ACTIONS__MACSEC_ENCRYPTf;
  32132                 field2 = IFP_ACTIONS__MACSEC_DECRYPTf;
  32133                 break;
  32134             case 7:
  32135                 field = L3MC__MACSEC_ENCRYPTf;
  32136                 field2 = L3MC__MACSEC_DECRYPTf;
  32137                 break;
  32138             default:
  32139                 break;
  32140         }
  32141         if ((field != INVALIDf) && (field2 != INVALIDf)) {
  32142             if (nh_entry->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_ENCRYPT) {
  32143                 soc_mem_field32_set(unit, mem, &eg_entry, field, 1);
  32144             } else {
  32145                 soc_mem_field32_set(unit, mem, &eg_entry, field, 0);
  32146             }
  32147 
  32148             if (nh_entry->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_DECRYPT) {
  32149                 soc_mem_field32_set(unit, mem, &eg_entry, field2, 1);
  32150             } else {
  32151                 soc_mem_field32_set(unit, mem, &eg_entry, field2, 0);
  32152             }
  32153         }
  32154 
  32155         if (entry_type == 0) { /* L3 Unicast */
  32156             soc_mem_field32_set(unit, mem, &eg_entry, L3__DST_MOD_IDf, nh_entry->module);
  32157             soc_mem_field32_set(unit, mem, &eg_entry, L3__DST_PORT_NUMf, nh_entry->port);
  32158         } else if (entry_type == 6) { /* IFP Actions */
  32159             soc_mem_field32_set(unit, mem, &eg_entry, IFP_ACTIONS__DST_MOD_IDf, nh_entry->module);
  32160             soc_mem_field32_set(unit, mem, &eg_entry, IFP_ACTIONS__DST_PORT_NUMf, nh_entry->port);
  32161         }
  32162     }
  32163 #endif /* defined(BCM_MONTEREY_SUPPORT) */
  32164 
  32165 #if defined(BCM_GREYHOUND_SUPPORT)
  32166 l3mc_egr_nh_done:
  32167 #endif  /* BCM_GREYHOUND_SUPPORT */
  32168 
  32169     BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_WRITE(unit, mem, idx, &eg_entry));
  32170 #ifdef BCM_TOMAHAWK3_SUPPORT
  32171     if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) {
  32172         BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_WRITE(unit, mem2, idx, &eg_2_entry));
  32173     }
  32174 #endif
  32175 
  32176     /*
  32177      * Set to indicate that L3 interface is used in Next Hop entry.
  32178      * This is used to skip the Next Hop table search in
  32179      * _bcm_fb_nh_intf_is_tnl_update().
  32180      */
  32181     BCM_XGS3_L3_INTF_USED_NH_SET(unit, nh_entry->intf);
  32182 
  32183 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \
  32184         defined(BCM_TRX_SUPPORT)
  32185     /* Write initial ingress next hop entry. */
  32186     mem = INITIAL_ING_L3_NEXT_HOPm;
  32187     if (!SOC_MEM_IS_VALID(unit, mem) || !soc_mem_index_max(unit, mem) ||
  32188         !soc_mem_index_count(unit, mem)) {
  32189         return (BCM_E_NONE);
  32190     }
  32191     /* Reset ingress buffer. */
  32192     sal_memset(&in_entry, 0, sizeof(ing_l3_next_hop_entry_t));
  32193     /* Read initial ingress next hop entry. */
  32194     BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, &in_entry));
  32195 
  32196 
  32197 #ifdef BCM_RIOT_SUPPORT
  32198    /*
  32199     * TD2+ has a separate encoding values for different destinations. 
  32200     * If Riot in not enabled then we may need to change this to 
  32201     * modid + port combination.
  32202     */
  32203     if (soc_feature(unit, soc_feature_ing_l3_next_hop_encoded_dest)) {
  32204         soc_mem_field32_set(unit, mem, &in_entry, DESTINATIONf,
  32205             nh_dest);
  32206         LOG_INFO(BSL_LS_BCM_L3, (BSL_META_U(unit,
  32207             "Setting up destination = 0x%x for port = 0x%x\n"), 
  32208             nh_dest, nh_entry->port));
  32209     } else
  32210 #ifdef BCM_TRIDENT3_SUPPORT
  32211     if (soc_feature(unit, soc_feature_generic_dest)) {
  32212         soc_mem_field32_set(unit, mem, &in_entry, DESTINATIONf,
  32213             nh_dest);
  32214     } else
  32215 #endif /* BCM_TRIDENT3_SUPPORT */
  32216 #endif /* BCM_RIOT_SUPPORT */
  32217     {
  32218         nh_port = nh_entry->port;
  32219 #if defined(BCM_MONTEREY_SUPPORT)
  32220         if (soc_feature(unit, soc_feature_xflow_macsec) &&
  32221             ((nh_entry->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_ENCRYPT) ||
  32222             (nh_entry->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_DECRYPT))) {
  32223             nh_port = 66;
  32224         }
  32225 #endif
  32226         if (!SOC_IS_TOMAHAWK3(unit)) {
  32227         /* Set module id to initial ingress l3 next hop entry. */
  32228         soc_mem_field32_set(unit, mem, &in_entry, MODULE_IDf, 
  32229             nh_entry->module);
  32230         }
  32231 #ifdef BCM_TRX_SUPPORT
  32232         if (soc_feature(unit, soc_feature_trunk_group_overlay)) {
  32233             if (nh_entry->flags & BCM_L3_TGID) {
  32234                 soc_mem_field32_set(unit, mem, &in_entry, Tf, 1);
  32235                 soc_mem_field32_set(unit, mem, &in_entry, TGIDf, 
  32236                     nh_port);
  32237             } else {
  32238                 soc_mem_field32_set(unit, mem, &in_entry, Tf, 0);
  32239                 soc_mem_field32_set(unit, mem, &in_entry, PORT_NUMf,
  32240                     nh_port);
  32241             }
  32242         } else
  32243 #endif /* BCM_TRX_SUPPORT */
  32244         {
  32245         /* Set port/trunk id. */
  32246             if (SOC_IS_TOMAHAWKX(unit)) {
  32247                 /*
  32248                  * implies the switch has a latency mode enabled. trunking is
  32249                  * not supported in any latency mode in TH.
  32250                  */
  32251                 soc_mem_field32_set(unit, mem, &in_entry, Tf, 0);
  32252                 soc_mem_field32_set(unit, mem, &in_entry, PORT_NUMf,
  32253                     nh_port);
  32254             } else {
  32255                 soc_mem_field32_set(unit, mem, &in_entry, PORT_TGIDf,
  32256                     nh_port);
  32257             }
  32258         }
  32259     }
  32260 #ifdef BCM_TRIDENT2_SUPPORT
  32261     if (soc_feature(unit, soc_feature_nat) && SOC_MEM_FIELD_VALID(unit, mem,
  32262                                                             DST_REALM_IDf)) {
  32263         soc_mem_field32_set(unit, mem, &in_entry, DST_REALM_IDf,
  32264                             iif.nat_realm_id);
  32265     }
  32266 #endif
  32267 
  32268     /* Write buffer to hw. */
  32269     return  BCM_XGS3_MEM_WRITE(unit, mem, idx, &in_entry);
  32270 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */
  32271 
  32272     return (BCM_E_NONE);
  32273 }
  32274 
  32275 
  32276 /*
  32277  * Function:
  32278  *      _bcm_fb_nh_intf_is_tnl_update
  32279  * Purpose:
  32280  *      Routine updates next hop interface is tunnel bit.
  32281  *      Routine updates all next hop entries using a certain
  32282  *      interface tunnel bit.
  32283  * Parameters:
  32284  *      unit       - (IN)SOC unit number.
  32285  *      intf       - (IN)Interface index to update.
  32286  *      tunnel_id  - (IN)Tunnel index.
  32287  * Returns:
  32288  *    BCM_E_XXX
  32289  */
  32290 STATIC int
  32291 _bcm_fb_nh_intf_is_tnl_update(int unit, bcm_if_t intf, int tunnel_id)
  32292 {
  32293     uint32 *ing_entry_ptr;        /* Ingress next hop entry pointer.*/
  32294     char *ing_tbl_ptr;            /* Dma table pointer.             */
  32295     int ifindex;                  /* Interface index.               */
  32296     soc_mem_t mem;                /* Next hop memory.               */
  32297     int idx;                      /* Iteration index.               */
  32298     char *egr_tbl_ptr;            /* Dma egress nh table pointer.   */
  32299     uint32 *egr_entry_ptr = NULL; /* Egress next hop entry pointer. */
  32300     int rv = BCM_E_NONE;          /* Operation return status.       */
  32301 #if defined(BCM_TRIUMPH_SUPPORT)
  32302     soc_field_t entry_type_field = 0;
  32303 
  32304     if (SOC_IS_TRIDENT3X(unit)) {
  32305         entry_type_field = DATA_TYPEf;
  32306     } else {
  32307         entry_type_field = ENTRY_TYPEf;
  32308     }
  32309 #endif
  32310     /* Check if L3 interface is used in Next Hop table. */
  32311     if (!BCM_XGS3_L3_INTF_USED_NH_GET(unit, intf)) {
  32312         return BCM_E_NONE;
  32313     }
  32314 
  32315     /* Get next table memory. */
  32316     mem = BCM_XGS3_L3_MEM(unit, nh);
  32317 
  32318     /* Lock ingress next hop table. */
  32319 
  32320     /* Table DMA the nhtable to software copy */
  32321     rv = bcm_xgs3_l3_tbl_dma(unit, mem, BCM_XGS3_L3_ENT_SZ(unit, nh), "nh_tbl",
  32322                              &ing_tbl_ptr, NULL);
  32323     BCM_IF_ERROR_RETURN(rv);
  32324 
  32325     /*  Read egress next hop entry. */
  32326     rv = bcm_xgs3_l3_tbl_dma(unit, EGR_L3_NEXT_HOPm,
  32327                              sizeof(egr_l3_next_hop_entry_t), "egr_nh_tbl",
  32328                              &egr_tbl_ptr, NULL);
  32329     if (rv < 0) {
  32330         soc_cm_sfree(unit, ing_tbl_ptr);
  32331         return rv;
  32332     }
  32333 
  32334     for (idx = 0; idx < BCM_XGS3_L3_NH_TBL_SIZE(unit); idx++) {
  32335         /* Skip unused entries. */
  32336         if (!BCM_XGS3_L3_ENT_REF_CNT
  32337                 (BCM_XGS3_L3_TBL_PTR(unit, next_hop), idx)) {
  32338             continue;
  32339         }
  32340 
  32341         /* Skip trap to CPU entry internally installed entry. */
  32342         if (BCM_XGS3_L3_L2CPU_NH_IDX(unit) == idx) {
  32343             continue;
  32344         }
  32345 
  32346         /*  Read egress next hop entry. */
  32347         egr_entry_ptr =
  32348             soc_mem_table_idx_to_pointer(unit, EGR_L3_NEXT_HOPm,
  32349                                          uint32 *, egr_tbl_ptr, idx);
  32350 
  32351         /* Get interface index. */
  32352         ifindex =  soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
  32353                                        egr_entry_ptr, INTF_NUMf);
  32354         if (ifindex != intf) {
  32355             continue;
  32356         }
  32357 
  32358         /* Calculate entry ofset. */
  32359         ing_entry_ptr =
  32360             soc_mem_table_idx_to_pointer(unit, mem, uint32 *, ing_tbl_ptr, idx);
  32361         if (SOC_MEM_FIELD_VALID(unit, mem, L3UC_TUNNEL_TYPEf)) {
  32362             soc_mem_field32_set(unit, mem, ing_entry_ptr, L3UC_TUNNEL_TYPEf,
  32363                                 (tunnel_id > 0) ? 1 : 0);
  32364         }
  32365 #if defined(BCM_TRIUMPH_SUPPORT)
  32366         if (SOC_MEM_FIELD_VALID(unit, mem, entry_type_field)) {
  32367             soc_mem_field32_set(unit, mem, ing_tbl_ptr, entry_type_field,
  32368                                 (tunnel_id > 0) ? 1 : 0);
  32369         }
  32370 #endif /* BCM_TRIUMPH_SUPPORT */
  32371     }
  32372 
  32373     /* Write the buffer back. */
  32374     rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ALL,
  32375                              soc_mem_index_min(unit, mem),
  32376                              soc_mem_index_max(unit, mem), ing_tbl_ptr);
  32377 
  32378     soc_cm_sfree(unit, ing_tbl_ptr);
  32379     soc_cm_sfree(unit, egr_tbl_ptr);
  32380     return (rv);
  32381 }
  32382 
  32383 /*
  32384  * Function:
  32385  *      _bcm_fb_l3_ipmc_ent_init
  32386  * Purpose:
  32387  *      Set GROUP/SOURCE/VID/IMPC flag in the entry.
  32388  * Parameters:
  32389  *      unit      - (IN)SOC unit number.
  32390  *      l3x_entry - (IN/OUT) IPMC entry to fill.
  32391  *      l3cfg     - (IN) Api IPMC data.
  32392  * Returns:
  32393  *    BCM_E_XXX
  32394  */
  32395 STATIC void
  32396 _bcm_fb_l3_ipmc_ent_init(int unit, uint32 *buf_p, _bcm_l3_cfg_t *l3cfg)
  32397 {
  32398     soc_mem_t mem;                     /* IPMC table memory.    */
  32399     int ipv6;                          /* IPv6 entry indicator. */
  32400     soc_field_t v6f[] = { V6_0f, V6_1f, V6_2f, V6_3f };
  32401     soc_field_t mcf[] = { IPMC_0f, IPMC_1f, IPMC_2f, IPMC_3f };
  32402     soc_field_t vidf[] = { VLAN_ID_0f, VLAN_ID_1f, VLAN_ID_2f, VLAN_ID_3f };
  32403     soc_field_t validf[] = { VALID_0f, VALID_1f, VALID_2f, VALID_3f };
  32404 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \
  32405     defined(BCM_TRX_SUPPORT)
  32406     soc_field_t vrff[] = { VRF_ID_0f, VRF_ID_1f, VRF_ID_2f, VRF_ID_3f };
  32407 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */
  32408     int idx;
  32409 
  32410     /* Get entry type. */
  32411     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
  32412 
  32413     /* Get table memory. */
  32414     mem =  (ipv6) ? L3_ENTRY_IPV6_MULTICASTm : L3_ENTRY_IPV4_MULTICASTm;
  32415     sal_memset(buf_p, 0, (ipv6) ?  BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6) : \
  32416                                    BCM_XGS3_L3_ENT_SZ(unit, ipmc_v4));
  32417     if (ipv6) {
  32418         /* Set group address. */
  32419         soc_mem_ip6_addr_set(unit, mem, buf_p, GROUP_IP_ADDR_LWR_64f,
  32420                              l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY);
  32421         l3cfg->l3c_ip6[0] = 0x0;    /* Don't write ff entry already mcast. */
  32422         soc_mem_ip6_addr_set(unit, mem, buf_p, GROUP_IP_ADDR_UPR_56f,
  32423                              l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY);
  32424         l3cfg->l3c_ip6[0] = 0xff;    /* Restore The entry  */
  32425 
  32426         /* Set source  address. */
  32427         soc_mem_ip6_addr_set(unit, mem, buf_p, SOURCE_IP_ADDR_LWR_64f,
  32428                              l3cfg->l3c_sip6, SOC_MEM_IP6_LOWER_ONLY);
  32429         soc_mem_ip6_addr_set(unit, mem, buf_p, SOURCE_IP_ADDR_UPR_64f,
  32430                              l3cfg->l3c_sip6, SOC_MEM_IP6_UPPER_ONLY);
  32431 
  32432         for (idx = 0; idx < 4; idx++) {
  32433             /* Set address v6 bit. */
  32434             soc_mem_field32_set(unit, mem, buf_p, v6f[idx], 1);
  32435 
  32436             /* Set address is multicast. */
  32437             soc_mem_field32_set(unit, mem, buf_p, mcf[idx], 1);
  32438 
  32439             /* Set vlan id. */
  32440             soc_mem_field32_set(unit, mem, buf_p, vidf[idx], l3cfg->l3c_vid);
  32441 
  32442             /* Set entry valid flag. */
  32443             soc_mem_field32_set(unit, mem, buf_p, validf[idx], 1);
  32444 
  32445 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \
  32446     defined(BCM_TRX_SUPPORT)
  32447             /* Set virtual router id. */
  32448            /*vrf id feild is reserved in hurricane*/
  32449             if ((!(SOC_IS_HURRICANEX(unit) || SOC_IS_GREYHOUND(unit))) && 
  32450                     (SOC_MEM_FIELD_VALID(unit, mem, vrff[idx]))) {
  32451                 soc_mem_field32_set(unit, mem, buf_p,
  32452                                     vrff[idx], l3cfg->l3c_vrf);
  32453             }
  32454 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */
  32455         }
  32456     } else {
  32457         /* Set group id. */
  32458         soc_mem_field32_set(unit, mem, buf_p, GROUP_IP_ADDRf,
  32459                             l3cfg->l3c_ip_addr);
  32460 
  32461         /* Set source address. */
  32462         soc_mem_field32_set(unit, mem, buf_p, SOURCE_IP_ADDRf,
  32463                             l3cfg->l3c_src_ip_addr);
  32464 
  32465         /* Set vlan id. */
  32466         soc_mem_field32_set(unit, mem, buf_p, VLAN_IDf, l3cfg->l3c_vid);
  32467 
  32468         /* Set multicast flag. */
  32469         soc_mem_field32_set(unit, mem, buf_p, IPMCf, 1);
  32470 
  32471         /* Set entry valid flag. */
  32472         soc_mem_field32_set(unit, mem, buf_p, VALIDf, 1);
  32473 
  32474 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \
  32475     defined(BCM_TRX_SUPPORT)
  32476         /* Set virtual router id. */
  32477        /* vrf id is reserved in hurricane*/
  32478         if ((!(SOC_IS_HURRICANEX(unit) || SOC_IS_GREYHOUND(unit) ||
  32479             SOC_IS_GREYHOUND2(unit)))  &&
  32480 	     (SOC_MEM_FIELD_VALID(unit, mem, VRF_IDf))) {
  32481             soc_mem_field32_set(unit, mem, buf_p, VRF_IDf, l3cfg->l3c_vrf);
  32482         }
  32483 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */
  32484     }
  32485 
  32486     return;
  32487 
  32488 }
  32489 
  32490 /*
  32491  * Function:
  32492  *      _bcm_fb_l3_ipmc_ent_parse
  32493  * Purpose:
  32494  *      Service routine used to parse hw l3 ipmc entry to api format.
  32495  * Parameters:
  32496  *      unit      - (IN)SOC unit number.
  32497  *      l3cfg     - (IN/OUT)l3 entry parsing destination buf.
  32498  *      l3x_entry - (IN/OUT)hw buffer.
  32499  * Returns:
  32500  *      void
  32501  */
  32502 STATIC INLINE void
  32503 _bcm_fb_l3_ipmc_ent_parse(int unit, _bcm_l3_cfg_t *l3cfg,
  32504                           l3_entry_ipv6_multicast_entry_t *l3x_entry)
  32505 {
  32506     _bcm_l3_fields_t *fld;             /* IPMC table fields.    */
  32507     soc_mem_t mem;                     /* IPMC table memory.    */
  32508     uint32 *buf_p;                     /* HW buffer address.    */
  32509     int ipv6;                          /* IPv6 entry indicator. */
  32510     int idx;                           /* Iteration index.      */
  32511     soc_field_t hitf[] = {HIT_1f, HIT_2f, HIT_3f };
  32512 
  32513     buf_p = (uint32 *)l3x_entry;
  32514 
  32515     /* Get entry type. */
  32516     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
  32517 
  32518     /* Extract l3 ipv6/4 fields information. */
  32519     fld = (_bcm_l3_fields_t *)((ipv6) ? BCM_XGS3_L3_MEM_FIELDS(unit, ipmc_v6) :\
  32520                                BCM_XGS3_L3_MEM_FIELDS(unit, ipmc_v4));
  32521 
  32522     /* Get table memory. */
  32523     mem =  (ipv6) ? L3_ENTRY_IPV6_MULTICASTm : L3_ENTRY_IPV4_MULTICASTm;
  32524 
  32525     /* Mark entry as multicast & clear rest of the flags. */
  32526     l3cfg->l3c_flags = BCM_L3_IPMC;
  32527     if (ipv6) {
  32528        l3cfg->l3c_flags |= BCM_L3_IP6;
  32529     }
  32530 
  32531     /* Read hit value. */
  32532     if(soc_mem_field32_get(unit, mem, buf_p, fld->hit)) {
  32533         l3cfg->l3c_flags |= BCM_L3_HIT;
  32534     } else if (ipv6) {
  32535         /* Get hit bit. */
  32536         for (idx = 0; idx < 3; idx++) {
  32537             if(soc_mem_field32_get(unit, mem, buf_p, hitf[idx])) {
  32538                 l3cfg->l3c_flags |= BCM_L3_HIT;
  32539                 break;
  32540             }
  32541         }
  32542     }
  32543 
  32544     /* Set ipv6 group address to multicast. */
  32545     if (ipv6) {
  32546         l3cfg->l3c_ip6[0] = 0xff;   /* Set entry ip to mcast address. */
  32547     }
  32548 
  32549     /* Read priority override */
  32550     if(soc_mem_field32_get(unit, mem, buf_p, fld->rpe)) {
  32551         l3cfg->l3c_flags |= BCM_L3_RPE;
  32552     }
  32553 
  32554     /* Read destination discard bit. */
  32555     if (SOC_MEM_FIELD_VALID(unit, mem, fld->dst_discard)) {
  32556         if(soc_mem_field32_get(unit, mem, buf_p, fld->dst_discard)) {
  32557             l3cfg->l3c_flags |= BCM_L3_DST_DISCARD;
  32558         }
  32559     }
  32560 
  32561     /* Read Virtual Router Id. */
  32562     if (SOC_MEM_FIELD_VALID(unit, mem, fld->vrf)) {
  32563         l3cfg->l3c_vrf = soc_mem_field32_get(unit, mem, buf_p, fld->vrf);
  32564     } else {
  32565         l3cfg->l3c_vrf = BCM_L3_VRF_DEFAULT;
  32566     }
  32567 
  32568     /*  */
  32569     l3cfg->l3c_ipmc_ptr =
  32570         soc_mem_field32_get(unit, mem, buf_p, fld->l3mc_index);
  32571 
  32572     /* Read priority value. */
  32573     l3cfg->l3c_prio = soc_mem_field32_get(unit, mem, buf_p, fld->priority);
  32574 
  32575     return;
  32576 }
  32577 
  32578 /*
  32579  * Function:
  32580  *      _bcm_fb_l3_ipmc_get
  32581  * Purpose:
  32582  *      Get l3 multicast entry.
  32583  * Parameters:
  32584  *      unit      - (IN)SOC unit number.
  32585  *      l3cfg     - (IN/OUT)Group/Source key & Get result buffer.
  32586  * Returns:
  32587  *    BCM_E_XXX
  32588  */
  32589 STATIC int
  32590 _bcm_fb_l3_ipmc_get(int unit, _bcm_l3_cfg_t *l3cfg)
  32591 {
  32592     l3_entry_ipv6_multicast_entry_t l3x_key;    /* Lookup key buffer.    */
  32593     l3_entry_ipv6_multicast_entry_t l3x_entry;  /* Search result buffer. */
  32594     int clear_hit;                              /* Clear hit flag.       */
  32595     soc_mem_t mem;                              /* IPMC table memory.    */
  32596     int ipv6;                                   /* IPv6 entry indicator. */
  32597     int rv;                                     /* Return value.         */
  32598 
  32599     /* Get entry type. */
  32600     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
  32601 
  32602     /*  Zero buffers. */
  32603     sal_memset(&l3x_key, 0, BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6));
  32604     sal_memset(&l3x_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6));
  32605 
  32606     /* Get table memory. */
  32607     mem =  (ipv6) ? L3_ENTRY_IPV6_MULTICASTm : L3_ENTRY_IPV4_MULTICASTm;
  32608 
  32609     /* Check if clear hit bit is required. */
  32610     clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR;
  32611 
  32612     /* Lookup Key preparation. */
  32613     _bcm_fb_l3_ipmc_ent_init(unit, (uint32 *)&l3x_key, l3cfg);
  32614 
  32615     /* Perform hw lookup. */
  32616 #ifdef BCM_TRX_SUPPORT
  32617     if (soc_feature(unit, soc_feature_generic_table_ops)) {
  32618         rv = soc_mem_search(unit, mem, MEM_BLOCK_ANY, &l3cfg->l3c_hw_index,
  32619                             &l3x_key, &l3x_entry, 0);
  32620     } else
  32621 #endif /*  BCM_TRX_SUPPORT */
  32622     {
  32623         rv = soc_fb_l3x_lookup(unit, (void *)&l3x_key, (void *)&l3x_entry,
  32624                                &l3cfg->l3c_hw_index);
  32625     }
  32626     BCM_XGS3_LKUP_IF_ERROR_RETURN(rv, BCM_E_NOT_FOUND);
  32627 
  32628     /* Extract buffer information. */
  32629     _bcm_fb_l3_ipmc_ent_parse(unit, l3cfg, &l3x_entry);
  32630 
  32631     /* Clear the HIT bit */
  32632     if (clear_hit) {
  32633         BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_clear_hit(unit, mem,
  32634                                                    l3cfg, &l3x_entry));
  32635     }
  32636     return rv;
  32637 }
  32638 
  32639 /*
  32640  * Function:
  32641  *      _bcm_fb_l3_ipmc_add
  32642  * Purpose:
  32643  *      Add l3 multicast entry.
  32644  * Parameters:
  32645  *      unit      - (IN)SOC unit number.
  32646  *      l3cfg     - (IN/OUT)Group/Source key.
  32647  * Returns:
  32648  *    BCM_E_XXX
  32649  */
  32650 STATIC int
  32651 _bcm_fb_l3_ipmc_add(int unit, _bcm_l3_cfg_t *l3cfg)
  32652 {
  32653     l3_entry_ipv6_multicast_entry_t l3x_entry;  /* Write entry buffer.   */
  32654     _bcm_l3_fields_t *fld;                      /* IPMC table fields.    */
  32655     soc_mem_t mem;                              /* IPMC table memory.    */
  32656     uint32 *buf_p;                              /* HW buffer address.    */
  32657     int ipv6;                                   /* IPv6 entry indicator. */
  32658     int idx;                                    /* Iteration index.      */
  32659     int rv;                                     /* Return value.         */
  32660     soc_field_t priorityf[] = { PRI_0f, PRI_1f, PRI_2f, PRI_3f };
  32661     soc_field_t idxf[] = { L3MC_INDEX_0f, L3MC_INDEX_1f, \
  32662                            L3MC_INDEX_2f, L3MC_INDEX_3f };
  32663     soc_field_t hitf[] = { HIT_0f, HIT_1f, HIT_2f, HIT_3f };
  32664     soc_field_t rpef[] = { RPE_0f, RPE_1f, RPE_2f, RPE_3f };
  32665     soc_field_t dst_discf[] = { DST_DISCARD_0f, DST_DISCARD_1f,\
  32666                                DST_DISCARD_2f, DST_DISCARD_3f };
  32667 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \
  32668     defined(BCM_TRX_SUPPORT)
  32669     soc_field_t vrf_idf[] = { VRF_ID_0f, VRF_ID_1f, VRF_ID_2f, VRF_ID_3f};
  32670 #else /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */
  32671     soc_field_t vrf_idf[] = { INVALIDf, INVALIDf, INVALIDf, INVALIDf};
  32672 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */
  32673     /* Get entry type. */
  32674     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
  32675 
  32676     /*  Zero buffers. */
  32677     buf_p = (uint32 *)&l3x_entry;
  32678     sal_memset(buf_p, 0, BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6));
  32679 
  32680     /* Get table memory. */
  32681     mem =  (ipv6) ? L3_ENTRY_IPV6_MULTICASTm : L3_ENTRY_IPV4_MULTICASTm;
  32682 
  32683     /* Extract l3 ipv6/4 fields information. */
  32684     fld = (_bcm_l3_fields_t *)((ipv6) ? BCM_XGS3_L3_MEM_FIELDS(unit, ipmc_v6) :\
  32685                                BCM_XGS3_L3_MEM_FIELDS(unit, ipmc_v4));
  32686 
  32687     /* Overwrite field values if entry is ipv4 */
  32688     if (!ipv6) {
  32689         priorityf[0] = fld->priority;
  32690         idxf[0] = fld->l3mc_index;
  32691         hitf[0] = fld->hit;
  32692         rpef[0] = fld->rpe;
  32693         dst_discf[0] = fld->dst_discard;
  32694         vrf_idf[0] = fld->vrf;
  32695     }
  32696 
  32697     /* Prepare entry to write. */
  32698     _bcm_fb_l3_ipmc_ent_init(unit, (uint32 *)&l3x_entry, l3cfg);
  32699 
  32700     for (idx = 0; idx < 4; idx++) {
  32701         /* Set hit bit. */
  32702         if (l3cfg->l3c_flags & BCM_L3_HIT) {
  32703             soc_mem_field32_set(unit, mem, buf_p, hitf[idx], 1);
  32704         }
  32705 
  32706         /* Set priority override bit. */
  32707         if (l3cfg->l3c_flags & BCM_L3_RPE) {
  32708             soc_mem_field32_set(unit, mem, buf_p, rpef[idx], 1);
  32709         }
  32710 
  32711         /* Set destination discard. */
  32712         if (SOC_MEM_FIELD_VALID(unit, mem, dst_discf[idx])) {
  32713             if (l3cfg->l3c_flags & BCM_L3_DST_DISCARD) {
  32714                 soc_mem_field32_set(unit, mem, buf_p, dst_discf[idx], 1);
  32715             }
  32716         }
  32717 
  32718         /* Virtual router id. */
  32719         if (SOC_MEM_FIELD_VALID(unit, mem, vrf_idf[idx])) {
  32720             soc_mem_field32_set(unit, mem, buf_p, vrf_idf[idx], l3cfg->l3c_vrf);
  32721         }
  32722 
  32723         /* Set priority. */
  32724         if (SOC_MEM_FIELD_VALID(unit, mem, priorityf[idx])) {
  32725             int pri_field_len;
  32726             int max_pri;
  32727 
  32728             pri_field_len = soc_mem_field_length(unit, mem, priorityf[idx]);
  32729             max_pri = (1 << pri_field_len) - 1;
  32730 
  32731             /*
  32732              * to validate the assigning priority :
  32733              *  - Different device may support different max priority.
  32734              */
  32735             if (l3cfg->l3c_prio > max_pri) {
  32736                 return BCM_E_PARAM;
  32737             }
  32738 
  32739             soc_mem_field32_set(unit, mem, buf_p,
  32740                                 priorityf[idx], l3cfg->l3c_prio);
  32741         }
  32742 
  32743         /* . */
  32744         soc_mem_field32_set(unit, mem, buf_p, idxf[idx], l3cfg->l3c_ipmc_ptr);
  32745 
  32746         /* IPv4 entry needs only first field. */
  32747         if (!ipv6) {
  32748             break;
  32749         }
  32750     }
  32751 
  32752     /* Write entry to the hw. */
  32753     /* Handle replacement. */
  32754     if (BCM_XGS3_L3_INVALID_INDEX != l3cfg->l3c_hw_index) {
  32755         rv = BCM_XGS3_MEM_WRITE(unit, mem, l3cfg->l3c_hw_index, buf_p);
  32756     } else {
  32757 #ifdef BCM_TRX_SUPPORT
  32758         if (soc_feature(unit, soc_feature_generic_table_ops)) {
  32759             rv = soc_mem_insert(unit, mem, MEM_BLOCK_ANY, (void *)buf_p);
  32760         } else
  32761 #endif /*  BCM_TRX_SUPPORT */
  32762         {
  32763             rv = soc_fb_l3x_insert(unit, (void *)buf_p);
  32764         }
  32765     }
  32766 
  32767     /* Increment number of ipmc routes. */
  32768     if ((rv >= 0) && (BCM_XGS3_L3_INVALID_INDEX == l3cfg->l3c_hw_index)) {
  32769         (ipv6) ? BCM_XGS3_L3_IP6_IPMC_CNT(unit)++ : \
  32770                  BCM_XGS3_L3_IP4_IPMC_CNT(unit)++;
  32771     }
  32772     return rv;
  32773 }
  32774 
  32775 /*
  32776  * Function:
  32777  *      _bcm_fb_l3_ipmc_del
  32778  * Purpose:
  32779  *      Delete l3 multicast entry.
  32780  * Parameters:
  32781  *      unit      - (IN)SOC unit number.
  32782  *      l3cfg     - (IN)Group/Source deletion key.
  32783  * Returns:
  32784  *    BCM_E_XXX
  32785  */
  32786 STATIC int
  32787 _bcm_fb_l3_ipmc_del(int unit, _bcm_l3_cfg_t *l3cfg)
  32788 {
  32789     l3_entry_ipv6_multicast_entry_t l3x_entry;  /* Delete buffer.          */
  32790 #ifdef BCM_TRX_SUPPORT
  32791     soc_mem_t mem;                              /* IPMC table memory.      */
  32792 #endif
  32793     int ipv6;                                   /* IPv6 entry indicator.   */
  32794     int rv;                                     /* Operation return value. */
  32795 
  32796     /* Get entry type. */
  32797     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
  32798 
  32799     /*  Zero entry buffer. */
  32800     sal_memset(&l3x_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6));
  32801 
  32802     /* Key preparation. */
  32803     _bcm_fb_l3_ipmc_ent_init(unit, (uint32 *)&l3x_entry, l3cfg);
  32804 
  32805     /* Delete the entry from hw. */
  32806 #ifdef BCM_TRX_SUPPORT
  32807     if (soc_feature(unit, soc_feature_generic_table_ops)) {
  32808         /* Get table memory. */
  32809         mem =  (ipv6) ? L3_ENTRY_IPV6_MULTICASTm : L3_ENTRY_IPV4_MULTICASTm;
  32810         rv = soc_mem_delete(unit, mem, MEM_BLOCK_ANY, (void *)&l3x_entry);
  32811     } else
  32812 #endif /* BCM_TRX_SUPPORT */
  32813     {
  32814        rv = soc_fb_l3x_delete(unit, (void *)&l3x_entry);
  32815     }
  32816 
  32817     /* Decrement number of ipmc routes. */
  32818     if (rv >= 0) {
  32819         (ipv6) ? BCM_XGS3_L3_IP6_IPMC_CNT(unit)-- : \
  32820                  BCM_XGS3_L3_IP4_IPMC_CNT(unit)--;
  32821     }
  32822     return rv;
  32823 }
  32824 
  32825 /*
  32826  * Function:
  32827  *      _bcm_fb_l3_ipmc_get_by_idx
  32828  * Purpose:
  32829  *      Get l3 multicast entry by entry index.
  32830  * Parameters:
  32831  *      unit      - (IN)SOC unit number.
  32832  *      dma_ptr  - (IN)Table pointer in dma.
  32833  *      idx       - (IN)Index to read.
  32834  *      l3cfg     - (IN/OUT)Entry data.
  32835  * Returns:
  32836  *    BCM_E_XXX
  32837  */
  32838 STATIC int
  32839 _bcm_fb_l3_ipmc_get_by_idx(int unit, void *dma_ptr,
  32840                                int idx, _bcm_l3_cfg_t *l3cfg)
  32841 {
  32842     l3_entry_ipv6_multicast_entry_t *l3x_entry_p; /* Read buffer address.    */
  32843     l3_entry_ipv6_multicast_entry_t l3x_entry;    /* Read buffer.            */
  32844     _bcm_l3_fields_t *fld;                        /* IPMC table fields.      */
  32845     soc_mem_t mem;                                /* IPMC table memory.      */
  32846     uint32 ipv6;                                  /* IPv6 entry indicator.   */
  32847     int clear_hit;                                /* Clear hit bit indicator.*/
  32848 
  32849     /* Get entry type. */
  32850     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
  32851 
  32852     /* Get table memory. */
  32853     mem =  (ipv6) ? L3_ENTRY_IPV6_MULTICASTm : L3_ENTRY_IPV4_MULTICASTm;
  32854 
  32855     /* Extract l3 ipv6/4 fields information. */
  32856     fld = (_bcm_l3_fields_t *)((ipv6) ? BCM_XGS3_L3_MEM_FIELDS(unit, ipmc_v6) :\
  32857                                BCM_XGS3_L3_MEM_FIELDS(unit, ipmc_v4));
  32858 
  32859     /* Check if clear hit is required. */
  32860     clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR;
  32861 
  32862     if (NULL == dma_ptr) {             /* Read from hardware. */
  32863         /* Zero buffers. */
  32864         l3x_entry_p = &l3x_entry;
  32865         sal_memset(l3x_entry_p, 0, BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6));
  32866         /* Read entry from hw. */
  32867         BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, l3x_entry_p));
  32868     } else {                    /* Read from dma. */
  32869         l3x_entry_p =
  32870             soc_mem_table_idx_to_pointer(unit, mem,
  32871                                          l3_entry_ipv6_multicast_entry_t *,
  32872                                          dma_ptr, idx);
  32873     }
  32874 
  32875     /* Ignore invalid entries. */
  32876     if (!soc_mem_field32_get(unit, mem, l3x_entry_p, fld->valid)) {
  32877         return (BCM_E_NOT_FOUND);
  32878     }
  32879 
  32880     /* Get protocol. */
  32881     if (soc_mem_field32_get(unit, mem, l3x_entry_p, fld->v6_entry)){
  32882         l3cfg->l3c_flags = BCM_L3_IP6;
  32883     } else {
  32884         l3cfg->l3c_flags = 0;
  32885     }
  32886 
  32887     /* Get ipmc flag . */
  32888     if (soc_mem_field32_get(unit, mem, l3x_entry_p, fld->ipmc_entry)) {
  32889         l3cfg->l3c_flags |= BCM_L3_IPMC;
  32890     }
  32891 
  32892     /* Ignore protocol mismatch & multicast entries. */
  32893     if ((ipv6  != (l3cfg->l3c_flags & BCM_L3_IP6)) ||
  32894         (!(l3cfg->l3c_flags & BCM_L3_IPMC))) {
  32895         return (BCM_E_NOT_FOUND);
  32896     }
  32897 
  32898     /* Set index to l3cfg. */
  32899     l3cfg->l3c_hw_index = idx;
  32900 
  32901     if (ipv6) {
  32902         /* Get group address. */
  32903         soc_mem_ip6_addr_get(unit, mem, l3x_entry_p, GROUP_IP_ADDR_LWR_64f,
  32904                              l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY);
  32905 
  32906         soc_mem_ip6_addr_get(unit, mem, l3x_entry_p, GROUP_IP_ADDR_UPR_56f,
  32907                              l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY);
  32908 
  32909         /* Get source  address. */
  32910         soc_mem_ip6_addr_get(unit, mem, l3x_entry_p, SOURCE_IP_ADDR_LWR_64f,
  32911                              l3cfg->l3c_sip6, SOC_MEM_IP6_LOWER_ONLY);
  32912         soc_mem_ip6_addr_get(unit, mem, l3x_entry_p, SOURCE_IP_ADDR_UPR_64f,
  32913                              l3cfg->l3c_sip6, SOC_MEM_IP6_UPPER_ONLY);
  32914 
  32915         l3cfg->l3c_ip6[0] = 0xff;    /* Set entry to multicast*/
  32916     } else {
  32917         /* Get group id. */
  32918         l3cfg->l3c_ip_addr =
  32919             soc_mem_field32_get(unit, mem, l3x_entry_p, GROUP_IP_ADDRf);
  32920 
  32921         /* Get source address. */
  32922         l3cfg->l3c_src_ip_addr =
  32923             soc_mem_field32_get(unit, mem,  l3x_entry_p, SOURCE_IP_ADDRf);
  32924     }
  32925     /* Get vlan id. */
  32926     l3cfg->l3c_vid = soc_mem_field32_get(unit, mem,  l3x_entry_p, fld->vlan_id);
  32927 
  32928     /* Parse entry data. */
  32929     _bcm_fb_l3_ipmc_ent_parse(unit, l3cfg, l3x_entry_p);
  32930 
  32931     /* Clear the HIT bit */
  32932     if (clear_hit) {
  32933         BCM_IF_ERROR_RETURN(_bcm_xgs3_l3_clear_hit(unit, mem,
  32934                                                    l3cfg, l3x_entry_p));
  32935     }
  32936     return (BCM_E_NONE);
  32937 }
  32938 
  32939 
  32940 /*
  32941  * Function:
  32942  *      bcm_xgs3_internal_lpm_vrf_calc
  32943  * Purpose:
  32944  *      Service routine used to translate API vrf id to hw specific.
  32945  * Parameters:
  32946  *      unit      - (IN)SOC unit number.
  32947  *      lpm_cfg   - (IN)Prefix info.
  32948  *      vrf_id    - (OUT)Internal vrf id.
  32949  *      vrf_mask  - (OUT)Internal vrf mask.
  32950  * Returns:
  32951  *      BCM_E_XXX
  32952  */
  32953 int
  32954 bcm_xgs3_internal_lpm_vrf_calc(int unit, _bcm_defip_cfg_t *lpm_cfg,
  32955                               int *vrf_id, int *vrf_mask)
  32956 {
  32957     /* Handle special vrf id cases. */
  32958     switch (lpm_cfg->defip_vrf) {
  32959       case BCM_L3_VRF_OVERRIDE:
  32960           *vrf_id = 0;
  32961           *vrf_mask = 0;
  32962           break;
  32963       case BCM_L3_VRF_GLOBAL:
  32964           *vrf_id = SOC_VRF_MAX(unit);
  32965           if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m) ||
  32966                    SOC_MEM_FIELD_VALID(unit,
  32967               BCM_XGS3_L3_MEM(unit, defip), GLOBAL_ROUTE0f)) {
  32968               *vrf_id = 0;
  32969           }
  32970           *vrf_mask = 0;
  32971           break;
  32972       default:
  32973           *vrf_id = lpm_cfg->defip_vrf;
  32974           *vrf_mask = SOC_VRF_MAX(unit);
  32975     }
  32976 
  32977     /* In any case vrf id shouldn't exceed max field mask. */
  32978     if ((*vrf_id < 0) || (*vrf_id > SOC_VRF_MAX(unit))) {
  32979         return (BCM_E_PARAM);
  32980     }
  32981     return (BCM_E_NONE);
  32982 }
  32983 
  32984 /*
  32985  *  Function:
  32986  *        bcm_ext_lpm_vrf_get
  32987  *  Purpose:
  32988  *        Service routine used to translate hw specific vrf id to API format.
  32989  *        i.e. Reverse operation of bcm_xgs3_internal_lpm_vrf_calc
  32990  *  Parameters:
  32991  *        unit      - (IN)SOC unit number.
  32992  *        vrf_id    - (IN)Virtual router id from HW entry
  32993  *        vrf_mask  - (IN)VRF Mask from HW entry
  32994  *        global    - (IN)GLOBAL_ROUTE field from HW entry
  32995  *   Returns:
  32996  *        VRF in API format
  32997  */
  32998 int
  32999 bcm_ext_lpm_vrf_get(int unit, int vrf_id, int vrf_mask, int global)
  33000 {
  33001     int vrf;
  33002 
  33003     /* Special vrf's handling. */
  33004     if (vrf_mask) {
  33005         vrf = vrf_id;
  33006     } else if (SOC_VRF_MAX(unit) == vrf_id) {
  33007         vrf = SOC_L3_VRF_GLOBAL;
  33008     } else {
  33009         vrf = SOC_L3_VRF_OVERRIDE;
  33010         if (global) {
  33011             vrf = SOC_L3_VRF_GLOBAL;
  33012         }
  33013     }
  33014     return vrf;
  33015 }
  33016 
  33017 /*
  33018  * Function:
  33019  *      _bcm_fb_lpm_ent_parse
  33020  * Purpose:
  33021  *      Parse an entry from DEFIP table.
  33022  * Parameters:
  33023  *      unit        - (IN)SOC unit number.
  33024  *      lpm_cfg     - (OUT)Buffer to fill defip information.
  33025  *      nh_ecmp_idx - (OUT)Next hop index or ecmp group id.
  33026  *      lpm_entry   - (IN) Buffer read from hw.
  33027  * Returns:
  33028  *      void
  33029  */
  33030 int
  33031 _bcm_fb_lpm_ent_parse(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx,
  33032                       uint32 *lpm_entry, int *b128)
  33033 {
  33034     int ipv6;
  33035     soc_mem_t mem = L3_DEFIPm;
  33036 
  33037     if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) {
  33038         mem = L3_DEFIP_LEVEL1m;
  33039     }
  33040 
  33041     /* Reset entry flags first. */
  33042     lpm_cfg->defip_flags = 0;
  33043 
  33044     /* Get hit bit. */
  33045     if (soc_mem_field32_get(unit, mem, lpm_entry, HIT0f)) {
  33046         lpm_cfg->defip_flags |= BCM_L3_HIT;
  33047     }
  33048 
  33049     if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) {
  33050         uint32          _key_data[2];
  33051         uint32 mode = 0;
  33052         sal_memset(_key_data, 0, sizeof(_key_data));
  33053 
  33054         soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, lpm_entry, KEY0f, _key_data);
  33055         ipv6 = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_TYPEf);
  33056 
  33057         lpm_cfg->defip_ip_addr = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, IP_ADDRf);
  33058         lpm_cfg->defip_entry_type = bcmDefipEntryTypeIp;
  33059         mode = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, KEY_MODEf);
  33060         lpm_cfg->defip_vrf = soc_format_field32_get(unit, L3_DEFIP_TCAM_KEYfmt, _key_data, VRF_IDf);
  33061 
  33062 
  33063         if (ipv6) {
  33064             if ((b128 != NULL) && (mode == 3)) {
  33065                 *b128 = 1;
  33066             }
  33067 
  33068             lpm_cfg->defip_flags |= BCM_L3_IP6;
  33069 
  33070             /* Get hit bit from the second part of the entry. */
  33071             if (soc_mem_field32_get(unit, mem,lpm_entry, HIT1f)) {
  33072                 lpm_cfg->defip_flags |= BCM_L3_HIT;
  33073             }
  33074         }
  33075 
  33076         soc_mem_field_get(unit, L3_DEFIP_LEVEL1m, lpm_entry, ASSOC_DATA0f, _key_data);
  33077         lpm_cfg->defip_prio = soc_format_field32_get(unit, ASSOC_DATA_FULLfmt, _key_data, PRIf);
  33078         lpm_cfg->defip_lookup_class = soc_format_field32_get(unit, ASSOC_DATA_FULLfmt, _key_data, CLASS_IDf);
  33079 
  33080         if (nh_ecmp_idx) {
  33081             *nh_ecmp_idx = soc_format_field32_get(unit, ASSOC_DATA_FULLfmt,
  33082                                                   _key_data, DESTINATIONf);
  33083         }
  33084 
  33085         if (soc_format_field32_get(unit, ASSOC_DATA_FULLfmt, _key_data, DEST_TYPEf)) {
  33086             lpm_cfg->defip_flags |= BCM_L3_MULTIPATH;
  33087             lpm_cfg->defip_ecmp = 1;
  33088         }
  33089 
  33090         /* Get priority override bit. */
  33091         if (soc_format_field32_get(unit, ASSOC_DATA_FULLfmt, _key_data, RPEf)) {
  33092             lpm_cfg->defip_flags |= BCM_L3_RPE;
  33093         }
  33094 
  33095         if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
  33096             lpm_cfg->defip_flex_ctr_mode = soc_format_field32_get(unit, ASSOC_DATA_FULLfmt, _key_data, FLEX_CTR_OFFSET_MODEf);
  33097             lpm_cfg->defip_flex_ctr_pool = soc_format_field32_get(unit, ASSOC_DATA_FULLfmt, _key_data, FLEX_CTR_POOL_NUMBERf);
  33098             lpm_cfg->defip_flex_ctr_base_id = soc_format_field32_get(unit, ASSOC_DATA_FULLfmt, _key_data, FLEX_CTR_BASE_COUNTER_IDXf);
  33099         }
  33100         if (soc_format_field32_get(unit, ASSOC_DATA_FULLfmt, _key_data, DST_DISCARDf)) {
  33101             lpm_cfg->defip_flags |= BCM_L3_DST_DISCARD;
  33102         }
  33103         return BCM_E_NONE;
  33104 
  33105     }
  33106     ipv6 = soc_mem_field32_get(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, defip_mode0_bit[unit]);
  33107     if (b128 != NULL && ipv6 == 3) {
  33108         *b128 = 1;
  33109     }
  33110 
  33111     /* Get priority override bit. */
  33112     if (soc_mem_field32_get(unit, mem, lpm_entry, RPE0f)) {
  33113         lpm_cfg->defip_flags |= BCM_L3_RPE;
  33114     }
  33115 
  33116 #ifdef BCM_TRIDENT3_SUPPORT
  33117     if (soc_feature(unit, soc_feature_flex_flow)) {
  33118         uint32 key_type;
  33119 
  33120         key_type = soc_mem_field32_get(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, KEY_TYPE0f);
  33121 
  33122         if (BCMI_LPM_FLEX_VIEW(key_type)) {
  33123             return _bcm_td3_lpm_flex_ent_parse(unit,
  33124                         (uint32 *)lpm_entry,
  33125                         key_type,
  33126                         L3_DEFIPm,
  33127                         lpm_cfg,
  33128                         nh_ecmp_idx);
  33129         }
  33130     }
  33131 #endif
  33132 
  33133     /* Check if entry points to ecmp group. */
  33134    /*hurricane does not have ecmp flag*/
  33135     lpm_cfg->defip_ecmp = 0;
  33136     if (SOC_IS_TRIDENT3X(unit)) {
  33137        uint32 dest_type = 0;
  33138        if (nh_ecmp_idx) {
  33139           *nh_ecmp_idx = soc_mem_field32_dest_get(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, DESTINATION0f,
  33140                                   &dest_type);
  33141        }
  33142        if (dest_type == SOC_MEM_FIF_DEST_ECMP) {
  33143            lpm_cfg->defip_ecmp = 1;
  33144            lpm_cfg->defip_flags |= BCM_L3_MULTIPATH;
  33145        } else {
  33146         /* Mark entry as non-ecmp. */
  33147         lpm_cfg->defip_ecmp = 0;
  33148 
  33149         /* Reset ecmp group next hop count. */
  33150         lpm_cfg->defip_ecmp_count = 0;
  33151        }
  33152     } else if ((!(SOC_IS_HURRICANE(unit) || SOC_IS_HURRICANE2(unit))) &&
  33153                (soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP0f))) {
  33154         lpm_cfg->defip_ecmp = 1;
  33155         /* Mark entry as ecmp */
  33156         lpm_cfg->defip_flags |= BCM_L3_MULTIPATH;
  33157 
  33158         /* Get ecmp group id. */
  33159         if (nh_ecmp_idx) {
  33160             *nh_ecmp_idx =
  33161                 soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP_PTR0f);
  33162         }
  33163     } else {
  33164         /* Mark entry as non-ecmp. */
  33165         lpm_cfg->defip_ecmp = 0;
  33166 
  33167         /* Reset ecmp group next hop count. */
  33168         lpm_cfg->defip_ecmp_count = 0;
  33169 
  33170         /* Get next hop index. */
  33171         if (nh_ecmp_idx) {
  33172             *nh_ecmp_idx =
  33173                 soc_L3_DEFIPm_field32_get(unit, lpm_entry, NEXT_HOP_INDEX0f);
  33174         }
  33175     }
  33176     /* Get entry priority. */
  33177     lpm_cfg->defip_prio = soc_L3_DEFIPm_field32_get(unit, lpm_entry, PRI0f);
  33178 
  33179     /* Get destination discard flag. */
  33180     if (SOC_MEM_FIELD_VALID(unit,  BCM_XGS3_L3_MEM(unit, defip), DST_DISCARD0f)) {
  33181         if(soc_L3_DEFIPm_field32_get(unit, lpm_entry, DST_DISCARD0f)) {
  33182             lpm_cfg->defip_flags |= BCM_L3_DST_DISCARD;
  33183         }
  33184     }
  33185 
  33186     if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, ENTRY_TYPE0f)) {
  33187         lpm_cfg->defip_entry_type = soc_L3_DEFIPm_field32_get(unit, lpm_entry,
  33188                                                               ENTRY_TYPE0f);
  33189         if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, D_ID0f)) {
  33190             lpm_cfg->defip_fcoe_d_id = soc_L3_DEFIPm_field32_get(unit, lpm_entry,
  33191                                                              D_ID0f);
  33192             lpm_cfg->defip_fcoe_d_id_mask = soc_L3_DEFIPm_field32_get(unit,
  33193                                                         lpm_entry, D_ID_MASK0f);
  33194         }
  33195         lpm_cfg->defip_vrf = soc_L3_DEFIPm_field32_get(unit, lpm_entry,
  33196                                                        VRF_ID_0f);
  33197     }
  33198 #if defined(BCM_TRIDENT3_SUPPORT)
  33199     else if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, KEY_TYPE0f)) {
  33200         lpm_cfg->defip_entry_type = soc_L3_DEFIPm_field32_get(unit, lpm_entry,
  33201                                                               KEY_TYPE0f);
  33202         if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, D_ID0f)) {
  33203             lpm_cfg->defip_fcoe_d_id = soc_L3_DEFIPm_field32_get(unit, lpm_entry,
  33204                                                              D_ID0f);
  33205             lpm_cfg->defip_fcoe_d_id_mask = soc_L3_DEFIPm_field32_get(unit,
  33206                                                         lpm_entry, D_ID_MASK0f);
  33207         }
  33208         lpm_cfg->defip_vrf = soc_L3_DEFIPm_field32_get(unit, lpm_entry,
  33209                                                        VRF_ID_0f);
  33210     }
  33211 #endif
  33212 
  33213 #if defined(BCM_TRX_SUPPORT)
  33214     /* Set classification group id. */
  33215     if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, CLASS_ID0f)) {
  33216         lpm_cfg->defip_lookup_class =
  33217             soc_L3_DEFIPm_field32_get(unit, lpm_entry, CLASS_ID0f);
  33218     }
  33219 #endif /* BCM_TRX_SUPPORT */
  33220 
  33221 
  33222     if (ipv6) {
  33223         lpm_cfg->defip_flags |= BCM_L3_IP6;
  33224         /* Get hit bit from the second part of the entry. */
  33225         if (ipv6 == 1) {
  33226             if (soc_mem_field32_get(unit, mem,lpm_entry, HIT1f)) {
  33227                 lpm_cfg->defip_flags |= BCM_L3_HIT;
  33228             }
  33229             /* Get priority override bit from the second part of the entry. */
  33230             if (soc_mem_field32_get(unit, mem, lpm_entry, RPE1f)) {
  33231                 lpm_cfg->defip_flags |= BCM_L3_RPE;
  33232             }
  33233         }
  33234     }
  33235 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
  33236     if (soc_feature(unit, soc_feature_ipmc_defip)) {
  33237         int ipmc_route = 0;
  33238         if (soc_mem_field_valid(unit, L3_DEFIPm, MULTICAST_ROUTE0f)) {
  33239             ipmc_route = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, MULTICAST_ROUTE0f);
  33240         } else if (soc_mem_field_valid(unit, L3_DEFIPm, DATA_TYPE0f)) {
  33241             if (soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, DATA_TYPE0f) == 2) {
  33242                 ipmc_route = 1;
  33243             } else {
  33244                 ipmc_route = 0;
  33245             }
  33246         }
  33247 
  33248         if (ipmc_route) {
  33249             int val;
  33250             lpm_cfg->defip_flags |= BCM_L3_IPMC;
  33251 
  33252             if (nh_ecmp_idx) {
  33253                 *nh_ecmp_idx = BCM_XGS3_L3_INVALID_INDEX;
  33254             }
  33255             if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_DROP0f)) {
  33256                 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RPF_FAIL_DROP;
  33257             }
  33258             if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPU0f)) {
  33259                 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RPF_FAIL_TOCPU;
  33260             }
  33261             /*
  33262              * RP ID and ExpectedIIF are overlaid.
  33263              */
  33264             val = soc_L3_DEFIPm_field32_get(unit, lpm_entry, EXPECTED_L3_IIF0f);
  33265             if (soc_feature(unit, soc_feature_l3defip_rp_l3iif_resolve)) {
  33266                 int rpa_id_mask = (1 << soc_mem_field_length(unit, L3_DEFIPm, RPA_ID0f)) - 1;
  33267                 /*
  33268                  * 1) If value is more than RPA_ID field then its l3_iif.
  33269                  *    N/A for TD3/MV2/HX5 to support warmboot.
  33270                  * 2) When RPF FAIL DROP/TOCPU flags are set then its l3iif valid
  33271                  */
  33272                 if ((lpm_cfg->defip_ipmc_flags &
  33273                      (BCM_IPMC_RPF_FAIL_DROP | BCM_IPMC_RPF_FAIL_TOCPU)) ||
  33274                     (!(SOC_IS_TRIDENT3(unit) || SOC_IS_MAVERICK2(unit) ||
  33275                        SOC_IS_HELIX5(unit)) && (val > rpa_id_mask))) {
  33276                     lpm_cfg->defip_expected_intf = val;
  33277                     if (0 != lpm_cfg->defip_expected_intf) {
  33278                         lpm_cfg->defip_ipmc_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK;
  33279                     }
  33280                     lpm_cfg->defip_l3a_rp = BCM_IPMC_RP_ID_INVALID;
  33281                 } else {
  33282                     lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RP_ID_EXPECTED_INTF_RESOLVE;
  33283                     lpm_cfg->defip_l3a_rp = val & rpa_id_mask;
  33284                     lpm_cfg->defip_expected_intf = val;
  33285                 }
  33286             } else if (_BCM_DEFIP_IPMC_RP_IS_SET(val)) {
  33287                 lpm_cfg->defip_l3a_rp = _BCM_DEFIP_IPMC_RP_GET(val);
  33288             } else {
  33289                 lpm_cfg->defip_expected_intf = val;
  33290                 if (0 != lpm_cfg->defip_expected_intf) {
  33291                     lpm_cfg->defip_ipmc_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK;
  33292                 }
  33293                 lpm_cfg->defip_l3a_rp = BCM_IPMC_RP_ID_INVALID;
  33294             }
  33295 
  33296             if (soc_feature(unit, soc_feature_generic_dest)) {
  33297                 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID;
  33298                 uint32 dest_value = 0;
  33299                 dest_value = soc_mem_field32_dest_get(unit,
  33300                         L3_DEFIPm, lpm_entry,
  33301                         DESTINATION0f, &dest_type);
  33302                 if (dest_type == SOC_MEM_FIF_DEST_IPMC) {
  33303                     lpm_cfg->defip_mc_group = dest_value;
  33304                 } else {
  33305                     lpm_cfg->defip_mc_group = 0;
  33306                 }
  33307             } else {
  33308                 lpm_cfg->defip_mc_group =
  33309                     soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, L3MC_INDEX0f);
  33310             }
  33311         }
  33312     }
  33313 #endif
  33314 #if defined(BCM_TRIDENT2_SUPPORT)
  33315     if (soc_feature(unit,soc_feature_advanced_flex_counter)) {
  33316         if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, FLEX_CTR_OFFSET_MODE0f)) {
  33317             lpm_cfg->defip_flex_ctr_mode =
  33318                 soc_L3_DEFIPm_field32_get(unit, lpm_entry,
  33319                                           FLEX_CTR_OFFSET_MODE0f);
  33320             lpm_cfg->defip_flex_ctr_pool =
  33321                 soc_L3_DEFIPm_field32_get(unit, lpm_entry,
  33322                                           FLEX_CTR_POOL_NUMBER0f);
  33323             lpm_cfg->defip_flex_ctr_base_id =
  33324                 soc_L3_DEFIPm_field32_get(unit, lpm_entry,
  33325                                           FLEX_CTR_BASE_COUNTER_IDX0f);
  33326         }
  33327     }
  33328 #endif
  33329     return BCM_E_NONE;
  33330 }
  33331 
  33332 /*
  33333  * Function:
  33334  *      _bcm_fb_lpm_get
  33335  * Purpose:
  33336  *      Get an entry from DEFIP table.
  33337  * Parameters:
  33338  *      unit        - (IN)SOC unit number.
  33339  *      lpm_cfg     - (IN)Buffer to fill defip information.
  33340  *      nh_ecmp_idx - (IN)Next hop or ecmp group index
  33341  * Returns:
  33342  *      BCM_E_XXX
  33343  */
  33344 int
  33345 _bcm_fb_lpm_get(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx)
  33346 {
  33347     uint32 lpm_key[SOC_MAX_MEM_WORDS];      /* Route lookup key.        */
  33348     uint32 lpm_entry[SOC_MAX_MEM_WORDS];    /* Search result buffer.    */
  33349     int clear_hit;              /* Clear hit indicator.     */
  33350     int rv;                     /* Operation return status. */
  33351     soc_mem_t  mem = L3_DEFIPm;
  33352     /* Input parameters check */
  33353     if (NULL == lpm_cfg) {
  33354         return (BCM_E_PARAM);
  33355     }
  33356 
  33357     if (!SOC_MEM_IS_VALID(unit, mem)) {
  33358         mem = L3_DEFIP_LEVEL1m;
  33359     }
  33360 
  33361     /* Zero buffers. */
  33362     sal_memset(lpm_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, defip));
  33363     sal_memset(lpm_key, 0, BCM_XGS3_L3_ENT_SZ(unit, defip));
  33364 
  33365     /* Check if clear hit bit required. */
  33366     clear_hit = lpm_cfg->defip_flags & BCM_L3_HIT_CLEAR;
  33367 
  33368     /* Initialize lkup key. */
  33369     BCM_IF_ERROR_RETURN(_bcm_fb_lpm_ent_init(unit, lpm_cfg, lpm_key));
  33370 
  33371 
  33372     /* Perform hw lookup. */
  33373     rv = soc_fb_lpm_match(unit, lpm_key, lpm_entry, &lpm_cfg->defip_index);
  33374     BCM_IF_ERROR_RETURN(rv);
  33375 
  33376     /*
  33377      * If entry is ipv4 we always operate on entry in "zero" half of the,
  33378      * buffer "zero" half of lpm_entry if the  original entry
  33379      * is in the "one" half.
  33380      */
  33381     if ((!(lpm_cfg->defip_flags & BCM_L3_IP6)) && (lpm_cfg->defip_index & 0x1)) {
  33382         soc_fb_lpm_ip4entry1_to_0(unit, &lpm_entry, &lpm_entry, TRUE);
  33383     }
  33384 
  33385 #ifdef BCM_TRIDENT_SUPPORT
  33386     if ((SOC_IS_TD_TT(unit) || SOC_IS_TD2_TT2(unit)) && !(SOC_IS_TOMAHAWK3(unit))) {
  33387         uint32 i, hit;
  33388         defip_hit_only_entry_t hit_entry[2];
  33389         soc_mem_t hit_mem[] = {L3_DEFIP_HIT_ONLY_Xm, L3_DEFIP_HIT_ONLY_Ym};
  33390         int hit_mem_cnt = 2;
  33391 
  33392         if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_APACHE(unit) || SOC_IS_TRIDENT3X(unit)) {
  33393             hit_mem[0] = L3_DEFIP_HIT_ONLYm;
  33394             hit_mem_cnt = 1;
  33395         }
  33396 
  33397         if (lpm_cfg->defip_flags & BCM_L3_IP6) {
  33398             for (i = 0, hit = 0; i < hit_mem_cnt; i++) {
  33399                 BCM_IF_ERROR_RETURN
  33400                     (BCM_XGS3_MEM_READ(unit, hit_mem[i],
  33401                                        lpm_cfg->defip_index, &hit_entry[i]));
  33402                 hit |= soc_mem_field32_get(unit, hit_mem[i],
  33403                                            &hit_entry[i], HIT0f);
  33404             }
  33405             soc_mem_field32_set(unit, mem, &lpm_entry, HIT0f, hit);
  33406             for (i = 0, hit = 0; i < hit_mem_cnt; i++) {
  33407                 hit |= soc_mem_field32_get(unit, hit_mem[i],
  33408                                            &hit_entry[i], HIT1f);
  33409             }            
  33410             soc_mem_field32_set(unit, mem, &lpm_entry, HIT1f, hit);
  33411         } else {
  33412             for (i = 0, hit = 0; i < hit_mem_cnt; i++) {
  33413                 BCM_IF_ERROR_RETURN
  33414                     (BCM_XGS3_MEM_READ(unit, hit_mem[i],
  33415                                        lpm_cfg->defip_index >> 1, &hit_entry[i]));
  33416                 hit |= soc_mem_field32_get(unit, hit_mem[i], &hit_entry[i],
  33417                                            lpm_cfg->defip_index & 0x1 ?
  33418                                            HIT1f : HIT0f);
  33419             }
  33420             soc_mem_field32_set(unit, mem, &lpm_entry, HIT0f, hit);
  33421         }
  33422     }
  33423 #endif /* BCM_TRIDENT_SUPPORT */
  33424 
  33425     /* Parse hw buffer to defip entry. */
  33426     BCM_IF_ERROR_RETURN(
  33427         _bcm_fb_lpm_ent_parse(unit, lpm_cfg, nh_ecmp_idx, (uint32 *)lpm_entry, NULL));
  33428 
  33429     /* Clear the HIT bit */
  33430     if (clear_hit) {
  33431         BCM_IF_ERROR_RETURN(_bcm_fb_lpm_clear_hit(unit, lpm_cfg, lpm_entry));
  33432     }
  33433     return (BCM_E_NONE);
  33434 }
  33435 
  33436 
  33437 /*
  33438  * Function:
  33439  *      _bcm_fb_lpm_add
  33440  * Purpose:
  33441  *      Add an entry to DEFIP table.
  33442  * Parameters:
  33443  *      unit        - (IN)SOC unit number.
  33444  *      lpm_cfg     - (IN)Buffer to fill defip information.
  33445  *      nh_ecmp_idx - (IN)Next hop or ecmp group index.
  33446  * Returns:
  33447  *      BCM_E_XXX
  33448  */
  33449 int
  33450 _bcm_fb_lpm_add(int unit, _bcm_defip_cfg_t *lpm_cfg, int nh_ecmp_idx)
  33451 {
  33452     uint32 lpm_entry[SOC_MAX_MEM_WORDS];    /* Search result buffer.    */
  33453     int rv;                     /* Operation return status. */
  33454 
  33455     /* Input parameters check */
  33456     if (NULL == lpm_cfg) {
  33457         return (BCM_E_PARAM);
  33458     }
  33459 
  33460     /* Zero buffers. */
  33461     sal_memset(lpm_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, defip));
  33462     _bcm_fb_lpm_prepare_defip_entry(unit, lpm_cfg, nh_ecmp_idx,
  33463                                     lpm_entry, NULL);
  33464     /* Write buffer to hw. */
  33465     rv = soc_fb_lpm_insert_index(unit, lpm_entry, lpm_cfg->defip_index);
  33466 
  33467     /* If new route added increment total number of routes.  */
  33468     /* Lack of index indicates a new route. */
  33469     if ((rv >= 0) && (BCM_XGS3_L3_INVALID_INDEX == lpm_cfg->defip_index)) {
  33470         BCM_XGS3_L3_DEFIP_CNT_INC(unit, (lpm_cfg->defip_flags & BCM_L3_IP6));
  33471     }
  33472 
  33473     return rv;
  33474 }
  33475 
  33476 /*
  33477  * Function:
  33478  *      _bcm_fb_lpm_del
  33479  * Purpose:
  33480  *      Delete an entry from DEFIP table.
  33481  * Parameters:
  33482  *      unit    - (IN)SOC unit number.
  33483  *      lpm_cfg - (IN)Buffer to fill defip information.
  33484  * Returns:
  33485  *      BCM_E_XXX
  33486  */
  33487 int
  33488 _bcm_fb_lpm_del(int unit, _bcm_defip_cfg_t *lpm_cfg)
  33489 {
  33490     int rv;                                 /* Operation return status. */
  33491     uint32 lpm_entry[SOC_MAX_MEM_WORDS];    /* Search result buffer.    */
  33492 
  33493     /* Input parameters check */
  33494     if (NULL == lpm_cfg) {
  33495         return (BCM_E_PARAM);
  33496     }
  33497 
  33498     /* Zero buffers. */
  33499     sal_memset(lpm_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, defip));
  33500 
  33501     /* Initialize hw buffer deletion key. */
  33502     BCM_IF_ERROR_RETURN(_bcm_fb_lpm_ent_init(unit, lpm_cfg, (uint32 *)lpm_entry));
  33503 
  33504     /* Write buffer to hw. */
  33505     rv = soc_fb_lpm_delete_index(unit, (uint32 *)lpm_entry, lpm_cfg->defip_index);
  33506 
  33507     /* If new route added increment total number of routes.  */
  33508     if (rv >= 0) {
  33509         BCM_XGS3_L3_DEFIP_CNT_DEC(unit, lpm_cfg->defip_flags & BCM_L3_IP6);
  33510     }
  33511     return rv;
  33512 }
  33513 
  33514 /*
  33515  * Function:
  33516  *      _bcm_fb_lpm_update_match
  33517  * Purpose:
  33518  *      Update/Delete all entries in defip table matching a certain rule.
  33519  * Parameters:
  33520  *      unit     - (IN)SOC unit number.
  33521  *      trv_data - (IN)Delete pattern + compare,act,notify routines.
  33522  * Returns:
  33523  *      BCM_E_XXX
  33524  */
  33525 int
  33526 _bcm_fb_lpm_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data)
  33527 {
  33528     uint32 ipv6;                /* Iterate over ipv6 only flag. */
  33529     int idx;                    /* Iteration index.             */
  33530     int tmp_idx;                /* ipv4 entries iterator.       */
  33531     char *lpm_tbl_ptr = NULL;   /* Dma table pointer.           */
  33532     int nh_ecmp_idx;            /* Next hop/Ecmp group index.   */
  33533     int cmp_result;             /* Test routine result.         */
  33534     uint32 *lpm_entry;   /* Hw entry buffer.             */
  33535     _bcm_defip_cfg_t lpm_cfg;   /* Buffer to fill route info.   */
  33536     int defip_table_size;       /* Defip table size.            */
  33537     int rv = BCM_E_NONE;        /* Operation return status.     */
  33538     int idx_start = 0;
  33539     int idx_end = 0;
  33540 #ifdef BCM_TRIDENT_SUPPORT
  33541     char *lpm_hit_only_tbl_ptr[2] = { NULL }; /* Dma table pointer. */
  33542     int tbl_entry_sz;
  33543 #endif /* BCM_TRIDENT_SUPPORT */
  33544 #ifdef BCM_KATANA_SUPPORT
  33545     soc_kt_lpm_ipv6_info_t *lpm_ipv6_info = soc_kt_lpm_ipv6_info_get(unit);
  33546 #endif
  33547     int tcam_pair_count = 0;
  33548     int tcam_depth = SOC_L3_DEFIP_TCAM_DEPTH_GET(unit);
  33549     uint32 lpm_entry_tmp[SOC_MAX_MEM_WORDS];
  33550 #ifdef BCM_WARM_BOOT_SUPPORT
  33551     int need_reinit = 0;
  33552 #endif
  33553 
  33554     ipv6 = (trv_data->flags & BCM_L3_IP6);
  33555 
  33556     if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
  33557         /* Table DMA the LPM table to software copy */
  33558         rv = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, defip),
  33559                                  BCM_XGS3_L3_ENT_SZ(unit, defip), "lpm_tbl",
  33560                                  &lpm_tbl_ptr, &defip_table_size);
  33561         if (rv < 0) {
  33562             goto free_table; 
  33563         }
  33564 
  33565         /* Table DMA the HIT table to software copy */
  33566 #ifdef BCM_TRIDENT_SUPPORT
  33567         if (SOC_IS_TD_TT(unit)) {
  33568             if (SOC_MEM_IS_VALID(unit, L3_DEFIP_HIT_ONLYm) && (SOC_IS_TOMAHAWKX(unit) || SOC_IS_APACHE(unit) || SOC_IS_TRIDENT3X(unit))) {
  33569                 tbl_entry_sz = WORDS2BYTES(soc_mem_entry_words(unit,
  33570                                            L3_DEFIP_HIT_ONLYm));
  33571                 rv = bcm_xgs3_l3_tbl_dma(unit,
  33572                                          L3_DEFIP_HIT_ONLYm,
  33573                                          tbl_entry_sz, 
  33574                                          "lpm_hit_only_tbl",
  33575                                          &lpm_hit_only_tbl_ptr[0], 
  33576                                          NULL);
  33577                 if (rv < 0) {
  33578                     goto free_table;
  33579                 }
  33580             } else if (SOC_MEM_IS_VALID(unit, L3_DEFIP_HIT_ONLY_Xm)){
  33581                 tbl_entry_sz = WORDS2BYTES(soc_mem_entry_words(unit,
  33582                                            L3_DEFIP_HIT_ONLY_Xm));
  33583                 rv = bcm_xgs3_l3_tbl_dma(unit,
  33584                                          L3_DEFIP_HIT_ONLY_Xm,
  33585                                          tbl_entry_sz, 
  33586                                          "lpm_hit_only_x_tbl",
  33587                                          &lpm_hit_only_tbl_ptr[0], 
  33588                                          NULL);
  33589                 if (rv < 0) {
  33590                     goto free_table;
  33591                 }
  33592 
  33593                 rv = bcm_xgs3_l3_tbl_dma(unit,
  33594                                          L3_DEFIP_HIT_ONLY_Ym,
  33595                                          tbl_entry_sz, 
  33596                                          "lpm_hit_only_y_tbl",
  33597                                          &lpm_hit_only_tbl_ptr[1],
  33598                                          NULL);
  33599                 if (rv < 0) {
  33600                     goto free_table;
  33601                 }
  33602             }
  33603         }
  33604 #endif /* BCM_TRIDENT_SUPPORT */
  33605     } else {
  33606         defip_table_size = soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, defip));
  33607         idx_end = soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, defip));
  33608         rv = soc_fb_lpm_tcam_pair_count_get(unit,
  33609                             &tcam_pair_count);
  33610         if (rv < 0) {
  33611             goto free_table;
  33612         }
  33613         /* If soc_feature_l3_defip_advanced_lookup is TRUE then
  33614          * both DIP and SIP lookup is done using only 1 L3_DEFIP entry.
  33615          * L3_DEFIP table is not divided into 2 to support URPF (For ex: Katana2).
  33616          */
  33617         if (SOC_URPF_STATUS_GET(unit) &&
  33618             !soc_feature(unit, soc_feature_l3_defip_advanced_lookup)) {
  33619                 defip_table_size >>= 1;
  33620                 idx_end >>= 1;
  33621                 switch(tcam_pair_count) {
  33622                 case 1:
  33623                 case 2:
  33624                     idx_start = 2 * tcam_depth;
  33625                     break;
  33626                 case 3:
  33627                 case 4:
  33628                     idx_start = 4 * tcam_depth;
  33629                     break;
  33630                 case 5:
  33631                 case 6:
  33632                     idx_start = 6 * tcam_depth;
  33633                     break;
  33634                 case 7:
  33635                 case 8:
  33636                     idx_start = 8 * tcam_depth;
  33637                     break;
  33638                 default:
  33639                     idx_start = 0;
  33640                    break;
  33641             }
  33642         } else {
  33643             idx_start = (tcam_pair_count * tcam_depth * 2);
  33644         }
  33645         defip_table_size = defip_table_size - idx_start;
  33646         if (!defip_table_size) {
  33647             rv = BCM_E_NONE;
  33648             goto free_table;
  33649         }
  33650 
  33651         /* Table DMA the LPM table to software copy */
  33652         rv = bcm_xgs3_l3_tbl_range_dma(unit, BCM_XGS3_L3_MEM(unit, defip),
  33653                                  BCM_XGS3_L3_ENT_SZ(unit, defip), "lpm_tbl",
  33654                                  idx_start, idx_end - 1,
  33655                                  &lpm_tbl_ptr);
  33656         if (rv < 0) {
  33657             goto free_table;
  33658         }
  33659 
  33660         /* Table DMA the HIT table to software copy */
  33661 #ifdef BCM_TRIDENT_SUPPORT
  33662         if (SOC_IS_TD_TT(unit) && !(SOC_IS_TOMAHAWK3(unit))) {
  33663             if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_APACHE(unit) || SOC_IS_TRIDENT3X(unit)) {
  33664                 tbl_entry_sz = WORDS2BYTES(soc_mem_entry_words(unit,
  33665                                            L3_DEFIP_HIT_ONLYm));
  33666                 rv = bcm_xgs3_l3_tbl_range_dma(unit,
  33667                                                L3_DEFIP_HIT_ONLYm,
  33668                                                tbl_entry_sz,
  33669                                                "lpm_hit_only_x_tbl",
  33670                                                idx_start, idx_end - 1,
  33671                                                &lpm_hit_only_tbl_ptr[0]);
  33672                 if (rv < 0) {
  33673                     goto free_table;
  33674                 }
  33675             } else {
  33676                 tbl_entry_sz = WORDS2BYTES(soc_mem_entry_words(unit,
  33677                                            L3_DEFIP_HIT_ONLY_Xm));
  33678                 rv = bcm_xgs3_l3_tbl_range_dma(unit,
  33679                                                L3_DEFIP_HIT_ONLY_Xm,
  33680                                                tbl_entry_sz,
  33681                                                "lpm_hit_only_x_tbl",
  33682                                                idx_start, idx_end - 1,
  33683                                                &lpm_hit_only_tbl_ptr[0]);
  33684                 if (rv < 0) {
  33685                     goto free_table;
  33686                 }
  33687 
  33688                 rv = bcm_xgs3_l3_tbl_range_dma(unit,
  33689                                                L3_DEFIP_HIT_ONLY_Ym,
  33690                                                tbl_entry_sz,
  33691                                                "lpm_hit_only_y_tbl",
  33692                                                idx_start, idx_end - 1,
  33693                                                &lpm_hit_only_tbl_ptr[1]);
  33694                 if (rv < 0) {
  33695                     goto free_table;
  33696                 }
  33697             }
  33698         }
  33699 #endif /* BCM_TRIDENT_SUPPORT */
  33700     }
  33701 
  33702     /* If soc_feature_l3_defip_advanced_lookup is TRUE then
  33703      * both DIP and SIP lookup is done using only 1 L3_DEFIP entry.
  33704      * L3_DEFIP table is not divided into 2 to support URPF (For ex: Katana2).
  33705      */
  33706     if (SOC_URPF_STATUS_GET(unit)  &&
  33707         !soc_feature(unit, soc_feature_l3_defip_advanced_lookup)) {
  33708         if (soc_feature(unit, soc_feature_l3_defip_hole)) {
  33709               defip_table_size = SOC_APOLLO_B0_L3_DEFIP_URPF_SIZE;
  33710         } else if (SOC_IS_APOLLO(unit)) {
  33711             defip_table_size = SOC_APOLLO_L3_DEFIP_URPF_SIZE;
  33712         } else {
  33713             if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
  33714                 defip_table_size >>= 1;
  33715             }
  33716         }
  33717     }
  33718 
  33719 #if defined(BCM_KATANA_SUPPORT)
  33720     if (SOC_IS_KATANA(unit)) {
  33721         idx_start = lpm_ipv6_info->ipv6_64b.dip_start_offset;
  33722         idx_end = idx_start + lpm_ipv6_info->ipv6_64b.depth;
  33723     } else
  33724 #endif
  33725     {
  33726         if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
  33727             idx_start = 0;
  33728             idx_end = defip_table_size;
  33729         }
  33730 
  33731     }
  33732 
  33733     for (idx = idx_start; idx < idx_end; idx++) {
  33734         /* Calculate entry ofset. */
  33735         if (SOC_MEM_IS_VALID(unit, L3_DEFIPm)) {
  33736         lpm_entry =
  33737                 (uint32 *)soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip),
  33738                                  defip_entry_t *, lpm_tbl_ptr, idx - idx_start);
  33739         } else {
  33740             lpm_entry =
  33741                 (uint32 *)soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip),
  33742                                          defip_level1_entry_t *, lpm_tbl_ptr, idx - idx_start);
  33743         }
  33744 
  33745         sal_memcpy(&lpm_entry_tmp, lpm_entry, BCM_XGS3_L3_ENT_SZ(unit, defip));
  33746 #ifdef BCM_WARM_BOOT_SUPPORT
  33747         need_reinit = 0;
  33748 #endif
  33749         /* Each lpm entry contains 2 ipv4 entries ->  Check both. */
  33750         for (tmp_idx = 0; tmp_idx < ((ipv6) ? 1 : 2); tmp_idx++) {
  33751 
  33752             if (tmp_idx) {
  33753                 /* Check second part of the entry. */
  33754                 soc_fb_lpm_ip4entry1_to_0(unit, lpm_entry, lpm_entry, TRUE);
  33755             }
  33756 
  33757             /* The ipv4 route can not be in the first half of L3_DEFIPm since the TH2 L3_DEFIP issue , 
  33758                          so skip it*/
  33759             if (soc_feature(unit,soc_feature_half_of_l3_defip_ipv4_capacity) &&
  33760                 !ipv6 && !tmp_idx) {
  33761                 continue;
  33762             }
  33763 
  33764             /* Make sure entry is valid. */
  33765             if (!soc_mem_field32_get(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, VALID0f)) {
  33766                 continue;
  33767             }
  33768 
  33769 #ifdef BCM_TRIDENT_SUPPORT
  33770             if (SOC_IS_TD_TT(unit) && !SOC_IS_TOMAHAWK3(unit)) {
  33771                 uint32 i, hit;
  33772                 defip_hit_only_entry_t *hit_entry[2];
  33773                 soc_mem_t hit_mem[] = {L3_DEFIP_HIT_ONLY_Xm, L3_DEFIP_HIT_ONLY_Ym};
  33774                 int hit_mem_cnt = 2;
  33775 
  33776                 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_APACHE(unit) || SOC_IS_TRIDENT3X(unit)) {
  33777                     hit_mem[0] = L3_DEFIP_HIT_ONLYm;
  33778                     hit_mem_cnt = 1;
  33779                 }
  33780 
  33781                 if (ipv6) {
  33782                     for (i = 0, hit = 0; i < hit_mem_cnt; i++) {
  33783                         hit_entry[i] = soc_mem_table_idx_to_pointer(unit,
  33784                                            hit_mem[i],
  33785                                            defip_hit_only_entry_t *,
  33786                                            lpm_hit_only_tbl_ptr[i],
  33787                                            idx - idx_start);
  33788                         hit |= soc_mem_field32_get(unit, hit_mem[i],
  33789                                                    hit_entry[i], HIT0f);
  33790                     }
  33791                     soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, HIT0f, hit);
  33792                     for (i = 0, hit = 0; i < hit_mem_cnt; i++) {
  33793                         hit |= soc_mem_field32_get(unit, hit_mem[i],
  33794                                                    hit_entry[i], HIT1f);
  33795                     }
  33796                     soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, HIT1f, hit);
  33797                 } else {
  33798                     for (i = 0, hit = 0; i < hit_mem_cnt; i++) {
  33799                         hit_entry[i] = soc_mem_table_idx_to_pointer(unit,
  33800                                            hit_mem[i],
  33801                                            defip_hit_only_entry_t *,
  33802                                            lpm_hit_only_tbl_ptr[i],
  33803                                            idx - idx_start);
  33804                         hit |= soc_mem_field32_get(unit, hit_mem[i],
  33805                                                    hit_entry[i],
  33806                                                    tmp_idx ? HIT1f : HIT0f);
  33807                     }
  33808                     soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), lpm_entry, HIT0f, hit);
  33809                 }
  33810             }
  33811 #endif /* BCM_TRIDENT_SUPPORT */
  33812 
  33813             /* Zero destination buffer first. */
  33814             sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t));
  33815 
  33816             /* Parse  the entry. */
  33817             rv = _bcm_fb_lpm_ent_parse(unit, &lpm_cfg, &nh_ecmp_idx, (uint32 *)lpm_entry, NULL);
  33818             if (BCM_FAILURE(rv)) {
  33819                LOG_ERROR(BSL_LS_BCM_L3,
  33820                           (BSL_META_U(unit,
  33821                                       "_bcm_fb_lpm_ent_parse failed\n")));
  33822                 goto free_table;
  33823             }
  33824             lpm_cfg.defip_index = idx;
  33825 
  33826             /* If protocol doesn't match skip the entry. */
  33827             if ((lpm_cfg.defip_flags & BCM_L3_IP6) != ipv6) {
  33828                 continue;
  33829             }
  33830 #ifdef BCM_TRIDENT3_SUPPORT
  33831             if (tmp_idx) {
  33832                 /* Continue if V4 entry using double wide view */
  33833                 if (soc_feature(unit, soc_feature_flex_flow) &&
  33834                         lpm_cfg.defip_flow_handle != 0) {
  33835                     soc_mem_t view_id;
  33836                     BCM_IF_ERROR_RETURN(
  33837                             soc_flow_db_ffo_to_mem_view_id_get(unit,
  33838                                 lpm_cfg.defip_flow_handle,
  33839                                 lpm_cfg.defip_flow_option_handle,
  33840                                 SOC_FLOW_DB_FUNC_L3_ROUTE_ID,
  33841                                 (uint32 *)&view_id));
  33842                     if (SOC_MEM_FIELD_VALID(unit, view_id, DWf)) {
  33843                         continue;
  33844                     }
  33845                 }
  33846             }
  33847 #endif
  33848             /* Fill entry ip address &  subnet mask. */
  33849             _bcm_fb_lpm_ent_get_key(unit, &lpm_cfg, lpm_entry);
  33850 
  33851             /* Execute operation routine if any. */
  33852             if (trv_data->op_cb) {
  33853                 rv = (*trv_data->op_cb) (unit, (void *)trv_data,
  33854                                          (void *)&lpm_cfg,
  33855                                          (void *)&nh_ecmp_idx, &cmp_result);
  33856                 if (rv < 0) {
  33857                     goto free_table;
  33858                 }
  33859             }
  33860 #ifdef BCM_WARM_BOOT_SUPPORT
  33861             need_reinit = 1;
  33862 #endif
  33863         }
  33864 #ifdef BCM_WARM_BOOT_SUPPORT
  33865         if (SOC_WARM_BOOT(unit) && need_reinit) {
  33866             rv = soc_fb_lpm_reinit(unit, idx, (uint32 *)&lpm_entry_tmp);
  33867             if (rv < 0) {
  33868                 goto free_table;
  33869             }
  33870         }
  33871 #endif /* BCM_WARM_BOOT_SUPPORT */
  33872     }
  33873 
  33874 #ifdef BCM_WARM_BOOT_SUPPORT
  33875     if (SOC_WARM_BOOT(unit)) {
  33876         rv = soc_fb_lpm_reinit_done(unit, ipv6);
  33877          if (rv < 0) {
  33878             goto free_table;
  33879         }
  33880     }
  33881 #endif /* BCM_WARM_BOOT_SUPPORT */
  33882 
  33883 free_table:
  33884     if (lpm_tbl_ptr != NULL) {
  33885         soc_cm_sfree(unit, lpm_tbl_ptr);
  33886     }
  33887 #ifdef BCM_TRIDENT_SUPPORT
  33888     if (lpm_hit_only_tbl_ptr[0] != NULL) {
  33889         soc_cm_sfree(unit, lpm_hit_only_tbl_ptr[0]);
  33890     }
  33891     if (lpm_hit_only_tbl_ptr[1] != NULL) {
  33892         soc_cm_sfree(unit, lpm_hit_only_tbl_ptr[1]);
  33893     }
  33894 #endif
  33895 
  33896     return (rv);
  33897 }
  33898 
  33899 /*
  33900  * Function:
  33901  *      _bcm_fbx_lpm_get
  33902  * Purpose:
  33903  *      Get an entry from DEFIP table.
  33904  * Parameters:
  33905  *      unit        - (IN)SOC unit number.
  33906  *      lpm_cfg     - (IN)Buffer to fill defip information.
  33907  *      nh_ecmp_idx - (IN)Next hop or ecmp group index
  33908  * Returns:
  33909  *      BCM_E_XXX
  33910  */
  33911 STATIC int
  33912 _bcm_fbx_lpm_get(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx)
  33913 {
  33914     soc_mem_t mem = L3_DEFIPm;
  33915 #if defined(BCM_KATANA_SUPPORT)
  33916     soc_kt_lpm_ipv6_info_t *lpm_ipv6_info = soc_kt_lpm_ipv6_info_get(unit);
  33917 #endif
  33918 
  33919     /* Input parameters check */
  33920     if (NULL == lpm_cfg) {
  33921         return (BCM_E_PARAM);
  33922     }
  33923 
  33924 #if defined(BCM_TRX_SUPPORT)
  33925     if (SOC_IS_TRX(unit)) {
  33926         BCM_IF_ERROR_RETURN
  33927             (_bcm_trx_l3_defip_mem_get(unit, lpm_cfg->defip_flags,
  33928                                       lpm_cfg->defip_sub_len, &mem));
  33929     }
  33930 #endif /* BCM_TRX_SUPPORT */
  33931 
  33932 
  33933     switch (mem) {
  33934 #if defined(BCM_TRIUMPH_SUPPORT)
  33935       case EXT_IPV6_128_DEFIPm:
  33936       case EXT_IPV6_64_DEFIPm:
  33937       case EXT_IPV4_DEFIPm:
  33938           return _bcm_tr_ext_lpm_match(unit, lpm_cfg, nh_ecmp_idx);
  33939 #endif /* BCM_TRIUMPH_SUPPORT */
  33940 #if defined(BCM_TRX_SUPPORT)
  33941         case L3_DEFIP_128m:
  33942 #if defined(BCM_KATANA_SUPPORT)
  33943             if (SOC_IS_KATANA(unit) && (lpm_ipv6_info->ipv6_128b.depth > 0)) {
  33944                 return _bcm_kt_defip_pair128_get(unit, lpm_cfg, nh_ecmp_idx);
  33945             } else
  33946 #endif
  33947             {
  33948                 return _bcm_trx_defip_128_get(unit, lpm_cfg, nh_ecmp_idx);
  33949             }
  33950 #endif /* BCM_TRX_SUPPORT */
  33951       default:
  33952 #if defined(BCM_HURRICANE2_SUPPORT)||defined(BCM_GREYHOUND_SUPPORT)
  33953             if (SOC_IS_HURRICANE2(unit)||SOC_IS_GREYHOUND(unit) ||
  33954                 SOC_IS_HURRICANE3(unit)||SOC_IS_GREYHOUND2(unit)) {
  33955                 return _bcm_hu2_lpm_get(unit, lpm_cfg, nh_ecmp_idx);
  33956             } else
  33957 #endif /* BCM_HURRICANE2_SUPPORT||BCM_GREYHOUND_SUPPORT */
  33958             {
  33959                 return _bcm_fb_lpm_get(unit, lpm_cfg, nh_ecmp_idx);
  33960             }
  33961     }
  33962     return (BCM_E_INTERNAL); /* Never reached. */
  33963 }
  33964 
  33965 /*
  33966  * Function:
  33967  *      _bcm_fbx_lpm_add
  33968  * Purpose:
  33969  *      Add an entry to DEFIP table.
  33970  * Parameters:
  33971  *      unit        - (IN)SOC unit number.
  33972  *      lpm_cfg     - (IN)Buffer to fill defip information.
  33973  *      nh_ecmp_idx - (IN)Next hop or ecmp group index.
  33974  * Returns:
  33975  *      BCM_E_XXX
  33976  */
  33977 STATIC int
  33978 _bcm_fbx_lpm_add(int unit, _bcm_defip_cfg_t *lpm_cfg, int nh_ecmp_idx)
  33979 {
  33980     soc_mem_t mem = L3_DEFIPm;
  33981 #if defined(BCM_KATANA_SUPPORT)
  33982     soc_kt_lpm_ipv6_info_t *lpm_ipv6_info = soc_kt_lpm_ipv6_info_get(unit);
  33983 #endif
  33984 
  33985     /* Input parameters check */
  33986     if (NULL == lpm_cfg) {
  33987         return (BCM_E_PARAM);
  33988     }
  33989 
  33990 #if defined(BCM_TRX_SUPPORT)
  33991     if (SOC_IS_TRX(unit)) {
  33992         BCM_IF_ERROR_RETURN
  33993             (_bcm_trx_l3_defip_mem_get(unit, lpm_cfg->defip_flags,
  33994                                       lpm_cfg->defip_sub_len, &mem));
  33995     }
  33996 #endif /* BCM_TRX_SUPPORT */
  33997 
  33998     switch (mem) {
  33999 #if defined(BCM_TRIUMPH_SUPPORT)
  34000       case EXT_IPV6_128_DEFIPm:
  34001       case EXT_IPV6_64_DEFIPm:
  34002       case EXT_IPV4_DEFIPm:
  34003           return _bcm_tr_ext_lpm_add(unit, lpm_cfg, nh_ecmp_idx);
  34004 #endif /* BCM_TRIUMPH_SUPPORT */
  34005 #if defined(BCM_TRX_SUPPORT)
  34006         case L3_DEFIP_128m:
  34007 #if defined(BCM_KATANA_SUPPORT)
  34008             if (SOC_IS_KATANA(unit) && (lpm_ipv6_info->ipv6_128b.depth > 0)) {
  34009                 return _bcm_kt_defip_pair128_add(unit, lpm_cfg, nh_ecmp_idx);
  34010             } else
  34011 #endif
  34012             {
  34013                 return _bcm_trx_defip_128_add(unit, lpm_cfg, nh_ecmp_idx);
  34014             }
  34015 #endif /* BCM_TRX_SUPPORT */
  34016         default:
  34017 #if defined(BCM_HURRICANE2_SUPPORT)||defined(BCM_GREYHOUND_SUPPORT)
  34018             if (SOC_IS_HURRICANE2(unit)||SOC_IS_GREYHOUND(unit) ||
  34019                 SOC_IS_HURRICANE3(unit)||SOC_IS_GREYHOUND2(unit)) {
  34020                 return _bcm_hu2_lpm_add(unit, lpm_cfg, nh_ecmp_idx);
  34021             } else
  34022 #endif /* BCM_HURRICANE2_SUPPORT */
  34023             {
  34024                 return _bcm_fb_lpm_add(unit, lpm_cfg, nh_ecmp_idx);
  34025             }
  34026     }
  34027     return (BCM_E_INTERNAL); /* Never reached. */
  34028 }
  34029 
  34030 /*
  34031  * Function:
  34032  *      _bcm_fbx_lpm_del
  34033  * Purpose:
  34034  *      Delete an entry from DEFIP table.
  34035  * Parameters:
  34036  *      unit    - (IN)SOC unit number.
  34037  *      lpm_cfg - (IN)Buffer to fill defip information.
  34038  * Returns:
  34039  *      BCM_E_XXX
  34040  */
  34041 STATIC int
  34042 _bcm_fbx_lpm_del(int unit, _bcm_defip_cfg_t *lpm_cfg)
  34043 {
  34044     soc_mem_t mem = L3_DEFIPm;
  34045 #if defined(BCM_KATANA_SUPPORT)
  34046     soc_kt_lpm_ipv6_info_t *lpm_ipv6_info = soc_kt_lpm_ipv6_info_get(unit);
  34047 #endif
  34048 
  34049     /* Input parameters check */
  34050     if (NULL == lpm_cfg) {
  34051         return (BCM_E_PARAM);
  34052     }
  34053 
  34054 #if defined(BCM_TRX_SUPPORT)
  34055     if (SOC_IS_TRX(unit)) {
  34056         BCM_IF_ERROR_RETURN
  34057             (_bcm_trx_l3_defip_mem_get(unit, lpm_cfg->defip_flags,
  34058                                       lpm_cfg->defip_sub_len, &mem));
  34059     }
  34060 #endif /* BCM_TRX_SUPPORT */
  34061 
  34062     switch (mem) {
  34063 #if defined(BCM_TRIUMPH_SUPPORT)
  34064       case EXT_IPV6_128_DEFIPm:
  34065       case EXT_IPV6_64_DEFIPm:
  34066       case EXT_IPV4_DEFIPm:
  34067           return _bcm_tr_ext_lpm_delete(unit, lpm_cfg);
  34068 #endif /* BCM_TRIUMPH_SUPPORT */
  34069 #if defined(BCM_TRX_SUPPORT)
  34070         case L3_DEFIP_128m:
  34071 #if defined(BCM_KATANA_SUPPORT)
  34072             if (SOC_IS_KATANA(unit) && (lpm_ipv6_info->ipv6_128b.depth > 0)) {
  34073                 return _bcm_kt_defip_pair128_delete(unit, lpm_cfg);
  34074             } else
  34075 #endif
  34076             {
  34077                 return _bcm_trx_defip_128_delete(unit, lpm_cfg);
  34078             }
  34079 #endif /* BCM_TRX_SUPPORT */
  34080       default:
  34081 #if defined(BCM_HURRICANE2_SUPPORT)||defined(BCM_GREYHOUND_SUPPORT)
  34082             if (SOC_IS_HURRICANE2(unit)||SOC_IS_GREYHOUND(unit) ||
  34083                 SOC_IS_HURRICANE3(unit)||SOC_IS_GREYHOUND2(unit)) {
  34084                 return _bcm_hu2_lpm_del(unit, lpm_cfg);
  34085             } else
  34086 #endif /* BCM_HURRICANE2_SUPPORT */
  34087             {
  34088                 return _bcm_fb_lpm_del(unit, lpm_cfg);
  34089             }
  34090     }
  34091     return (BCM_E_INTERNAL); /* Never reached. */
  34092 }
  34093 
  34094 /*
  34095  * Function:
  34096  *      _bcm_fbx_lpm_update_match
  34097  * Purpose:
  34098  *      Update/Delete all entries in defip table matching a certain rule.
  34099  * Parameters:
  34100  *      unit     - (IN)SOC unit number.
  34101  *      trv_data - (IN)Delete pattern + compare,act,notify routines.
  34102  * Returns:
  34103  *      BCM_E_XXX
  34104  */
  34105 STATIC int
  34106 _bcm_fbx_lpm_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data)
  34107 {
  34108     soc_mem_t mem = L3_DEFIPm;  /* Route table memory.      */
  34109     int rv = BCM_E_NONE;        /* Operation return status. */
  34110 #ifdef BCM_KATANA_SUPPORT
  34111     soc_kt_lpm_ipv6_info_t *lpm_ipv6_info = soc_kt_lpm_ipv6_info_get(unit);
  34112 #endif
  34113 #if defined(BCM_TRIUMPH_SUPPORT)
  34114     if (SOC_IS_TR_VL(unit)) {
  34115         BCM_IF_ERROR_RETURN
  34116             (_bcm_tr_l3_defip_mem_get(unit, trv_data->flags, 0, &mem));
  34117     }
  34118 #endif /* BCM_TRIUMPH_SUPPORT */
  34119 
  34120     switch (mem) {
  34121 #if defined(BCM_TRIUMPH_SUPPORT)
  34122       case EXT_IPV6_128_DEFIPm:
  34123       case EXT_IPV6_64_DEFIPm:
  34124       case EXT_IPV4_DEFIPm:
  34125           return  _bcm_tr_defip_traverse(unit, trv_data);
  34126 #endif /* BCM_TRIUMPH_SUPPORT */
  34127       default:
  34128 #if defined(BCM_HURRICANE2_SUPPORT)||defined(BCM_GREYHOUND_SUPPORT)
  34129             if (SOC_IS_HURRICANE2(unit)||SOC_IS_GREYHOUND(unit) ||
  34130                 SOC_IS_HURRICANE3(unit)||SOC_IS_GREYHOUND2(unit)) {
  34131                 return _bcm_hu2_lpm_update_match(unit, trv_data);
  34132             } else
  34133 #endif /* BCM_HURRICANE2_SUPPORT */
  34134             {
  34135                 rv = _bcm_fb_lpm_update_match(unit, trv_data);
  34136             }
  34137     }
  34138     if (BCM_FAILURE(rv)) {
  34139         return (rv);
  34140     }
  34141 
  34142 #if defined(BCM_KATANA_SUPPORT)
  34143     if (SOC_IS_KATANA(unit) && (lpm_ipv6_info->ipv6_128b.depth > 0)) {
  34144         if ((trv_data->flags & BCM_L3_IP6)) {
  34145             rv = _bcm_trx_defip_128_update_match(unit, trv_data);
  34146             rv = _bcm_kt_defip_pair128_update_match(unit, trv_data);
  34147         }
  34148     } else
  34149 #endif /* BCM_KATANA_SUPPORT */
  34150     {
  34151 #if defined(BCM_TRX_SUPPORT)
  34152         if ((trv_data->flags & BCM_L3_IP6) &&
  34153             SOC_MEM_IS_VALID(unit, L3_DEFIP_128m)) {
  34154             rv = _bcm_trx_defip_128_update_match(unit, trv_data);
  34155         }
  34156 #endif /* BCM_TRX_SUPPORT */
  34157     }
  34158     return (rv);
  34159 }
  34160 
  34161 
  34162 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \
  34163     defined(BCM_HAWKEYE_SUPPORT)
  34164 
  34165 /*
  34166  * Function:
  34167  *      _bcm_rp_grp_priority_cmp
  34168  * Purpose:
  34169  *      Compare two FP groups priorities.
  34170  * Parameters:
  34171  *      b - (IN)first compared group.
  34172  *      a - (IN)second compared group.
  34173  * Returns:
  34174  *      a<=>b
  34175  */
  34176 static INLINE int
  34177 _bcm_rp_grp_priority_cmp(void *a, void *b)
  34178 {
  34179     _bcm_rp_l3_fp_group_t first;       /* First compared group.  */
  34180     _bcm_rp_l3_fp_group_t second;      /* Second compared group. */
  34181 
  34182     /* Cast group info pointers. */
  34183     first = *(_bcm_rp_l3_fp_group_t *)a;
  34184     second = *(_bcm_rp_l3_fp_group_t *)b;
  34185 
  34186     /* Compare groups priorities. */
  34187     return _bcm_xgs3_cmp_int(&first.grp_hdlr, &second.grp_hdlr);
  34188 }
  34189 
  34190 /*
  34191  * Function:
  34192  *      _bcm_rp_l3_rule_create
  34193  * Purpose:
  34194  *      Create L3 field processor rule & meter.
  34195  * Parameters:
  34196  *      unit     - (IN)SOC unit number.
  34197  *      rule_idx - (IN)Rule index.
  34198  * Returns:
  34199  *      BCM_E_XXX
  34200  */
  34201 STATIC int
  34202 _bcm_rp_l3_rule_create(int unit, int rule_idx)
  34203 {
  34204     _bcm_rp_l3_data_t *tbl_ptr;      /* L3 sw table address. */
  34205     bcm_field_entry_t rule_hdlr;     /* FP l3 rule handler.  */
  34206     bcm_field_group_t grp_hdlr;      /* FP l3 group handler. */
  34207     int grp_idx;                     /* FP l3 group index.   */
  34208     bcm_field_stat_t stat_type;      /* FP entry Stat type.  */
  34209     int stat_id;                     /* FP entry Stat ID.    */
  34210 
  34211 
  34212     /* Get l3 prefixes table. */
  34213     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  34214 
  34215     grp_idx = rule_idx/(tbl_ptr->rules_per_group);
  34216     grp_hdlr = (tbl_ptr->l3_grp[grp_idx]).grp_hdlr;
  34217 
  34218     /* Create FP rule. */
  34219     BCM_IF_ERROR_RETURN(bcm_esw_field_entry_create(unit, grp_hdlr, &rule_hdlr));
  34220 
  34221     /* Create packet type stat and attach to the rule */
  34222     stat_type = bcmFieldStatPackets;
  34223     BCM_IF_ERROR_RETURN(bcm_esw_field_stat_create(unit, grp_hdlr, 1,
  34224                                                   &stat_type, &stat_id));
  34225     BCM_IF_ERROR_RETURN(bcm_esw_field_entry_stat_attach(unit, rule_hdlr,
  34226                                                     stat_id));
  34227     /* Preserve rule handler. */
  34228     (tbl_ptr->l3_arr[rule_idx]).rule_hdlr = rule_hdlr;
  34229 
  34230     return (BCM_E_NONE);
  34231 }
  34232 
  34233 /*
  34234  * Function:
  34235  *      _bcm_rp_l3_rule_destroy
  34236  * Purpose:
  34237  *      Destroy L3 field processor rule.
  34238  * Parameters:
  34239  *      unit     - (IN)SOC unit number.
  34240  *      rule_idx - (IN)Rule index.
  34241  * Returns:
  34242  *      BCM_E_XXX
  34243  */
  34244 STATIC int
  34245 _bcm_rp_l3_rule_destroy(int unit, int rule_idx)
  34246 {
  34247     _bcm_rp_l3_data_t *tbl_ptr;      /* L3 sw table address.  */
  34248     bcm_field_entry_t rule_hdlr;     /* FP l3 rule handler.   */
  34249     int stat_id;                     /* FP entry Stat ID.     */
  34250 
  34251     /* Get l3 prefixes table. */
  34252     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  34253 
  34254     /* Get Rule Handler. */
  34255     rule_hdlr = (tbl_ptr->l3_arr[rule_idx]).rule_hdlr;
  34256 
  34257     /* If entry is valid -> remove it from HW. */
  34258     if (tbl_ptr->l3_arr[rule_idx].flags & BCM_XGS3_L3_ENT_VALID) {
  34259         /* Uinstall fp entry from hw. */
  34260         BCM_IF_ERROR_RETURN(bcm_esw_field_entry_remove(unit, rule_hdlr));
  34261     }
  34262 
  34263     /* Delete match Stat ID. */
  34264     BCM_IF_ERROR_RETURN
  34265         (bcm_esw_field_entry_stat_get(unit, rule_hdlr, &stat_id));
  34266 
  34267     BCM_IF_ERROR_RETURN
  34268         (bcm_esw_field_entry_stat_detach(unit, rule_hdlr, stat_id));
  34269 
  34270     /* Uinstall fp entry from sw. */
  34271     BCM_IF_ERROR_RETURN(bcm_esw_field_entry_destroy(unit, rule_hdlr));
  34272 
  34273     return (BCM_E_NONE);
  34274 }
  34275 /*
  34276  * Function:
  34277  *      _bcm_rp_l3_usage_cntr_set
  34278  * Purpose:
  34279  *      Copy usage counter from one l3 entry rule to another.
  34280  *      or reset usage counter if second entry is invalid.
  34281  * Parameters:
  34282  *      unit     - (IN)SOC unit number.
  34283  *      dst_idx  - (IN)Destination counter entry index.
  34284  *      src_idx  - (IN)Counter entry index.
  34285  *      flags    - (IN)BCM_L3_HIT.
  34286  * Returns:
  34287  *      BCM_E_XXX
  34288  */
  34289 STATIC int
  34290 _bcm_rp_l3_usage_cntr_set(int unit, int dst_idx, int src_idx, uint32 flags)
  34291 {
  34292     _bcm_rp_l3_data_t *tbl_ptr;   /* L3 sw table address.   */
  34293     uint64 usage_cntr;            /* Entry usage counter.   */
  34294     bcm_field_stat_t stat_type;   /* FP entry Stat type.    */
  34295     int stat_id;                  /* FP entry Stat ID.      */
  34296 
  34297     /* Get l3 prefixes table. */
  34298     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  34299 
  34300     if(BCM_XGS3_L3_INVALID_INDEX != src_idx)
  34301     {
  34302         /* Get the Stat ID. */
  34303         BCM_IF_ERROR_RETURN
  34304             (bcm_esw_field_entry_stat_get(unit,
  34305                                       tbl_ptr->l3_arr[src_idx].rule_hdlr,
  34306                                       &stat_id));
  34307 
  34308         /* Read Stat value. */
  34309         stat_type = bcmFieldStatPackets;
  34310         BCM_IF_ERROR_RETURN
  34311             (bcm_esw_field_stat_get(unit, stat_id, stat_type, &usage_cntr));
  34312     } else {
  34313         sal_memset(&usage_cntr, 0, sizeof usage_cntr);
  34314         if (flags & BCM_L3_HIT) {
  34315              COMPILER_64_ADD_32(usage_cntr, 1);
  34316         }
  34317     }
  34318 
  34319     /* Get the Stat ID. */
  34320     BCM_IF_ERROR_RETURN
  34321         (bcm_esw_field_entry_stat_get(unit, tbl_ptr->l3_arr[dst_idx].rule_hdlr,
  34322                                   &stat_id));
  34323 
  34324     /* Set Stat value. */
  34325     stat_type = bcmFieldStatPackets;
  34326     return bcm_esw_field_stat_set(unit, stat_id, stat_type,
  34327                             usage_cntr);
  34328 }
  34329 
  34330 /*
  34331  * Function:
  34332  *      _bcm_rp_l3_entry_add
  34333  * Purpose:
  34334  *      Add L3 rule to field processor.
  34335  * Parameters:
  34336  *      unit      - (IN)SOC unit number.
  34337  *      rule_idx  - (IN)FP entry rule index.
  34338  *      l3_entry  - (IN)Added L3 entry information.
  34339  * Returns:
  34340  *      BCM_E_XXX
  34341  */
  34342 STATIC int
  34343 _bcm_rp_l3_entry_add(int unit, int rule_idx, _bcm_rp_l3_entry_t *l3_entry)
  34344 {
  34345     _bcm_rp_l3_data_t *tbl_ptr;  /* L3 sw table address.     */
  34346     bcm_ip6_t ip6_mask;          /* IPv6 destination mask.   */
  34347     bcm_ip_t  ip4_mask;          /* IPv4 destination mask.   */
  34348     bcm_field_entry_t rule_hdlr; /* L3 rule handler.         */
  34349     bcm_ip6_t ip6;               /* IPv6 address.            */
  34350     int ip_type;                 /* QualifyIpType value.     */
  34351     int rule_priority;           /* Rule prioiry.            */
  34352     int nh_idx;                  /* Next hop index.          */
  34353 
  34354 
  34355     /* Get l3 prefixes table. */
  34356     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  34357 
  34358     /* Preserve rule handler. */
  34359     rule_hdlr =  tbl_ptr->l3_arr[rule_idx].rule_hdlr;
  34360 
  34361     /* Copy FP rule info. */
  34362     tbl_ptr->l3_arr[rule_idx] = *l3_entry;
  34363 
  34364     /* Restore rule handler. */
  34365     tbl_ptr->l3_arr[rule_idx].rule_hdlr = rule_hdlr;
  34366 
  34367     /* Get next hop index for the rule. */
  34368     nh_idx = l3_entry->nh_idx;
  34369     if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
  34370         if (l3_entry->flags & BCM_L3_MULTIPATH) {
  34371             nh_idx += BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  34372         } else {
  34373             nh_idx += BCM_XGS3_EGRESS_IDX_MIN(unit);
  34374         }
  34375     }
  34376 
  34377     /* Set rule qualification criterias. */
  34378 #if defined(BCM_MIRAGE_SUPPORT)
  34379     if (soc_feature(unit, soc_feature_fp_routing_mirage)) {
  34380         BCM_IF_ERROR_RETURN(bcm_esw_field_qualify_DstPort(unit, rule_hdlr,
  34381                                       0, 0, BCM_MIRAGE_L3_PORT, BCM_MIRAGE_L3_PORT));
  34382     } else
  34383 #endif /* BCM_MIRAGE_SUPPORT */
  34384     {
  34385         /* Add unknown unicast. */
  34386         BCM_IF_ERROR_RETURN
  34387             (bcm_esw_field_qualify_L3Routable(unit, rule_hdlr,
  34388                                                 0x1, 0x1));
  34389 
  34390     }
  34391     if (l3_entry->flags & BCM_L3_IP6) {
  34392         /* Set to protocol ipv6. */
  34393         BCM_IF_ERROR_RETURN
  34394             (bcm_esw_field_qualify_IpType(unit, rule_hdlr,
  34395                                           bcmFieldIpTypeIpv6));
  34396 
  34397         /* Calculate subnet mask. */
  34398         bcm_ip6_mask_create(ip6_mask, l3_entry->prefixlen);
  34399 
  34400         /* Rule priority. */
  34401         rule_priority = l3_entry->prefixlen;
  34402 
  34403         /* Copy address. */
  34404         sal_memcpy(ip6, l3_entry->addr.ip6, sizeof(bcm_ip6_t));
  34405     } else {
  34406 
  34407 #if defined(BCM_XGS3_L3_FORWARD_IPV4_WITH_OPTIONS)
  34408         ip_type = bcmFieldIpTypeIpv4Any;
  34409 #else  /* BCM_XGS3_L3_FORWARD_IPV4_WITH_OPTIONS */
  34410         ip_type = bcmFieldIpTypeIpv4NoOpts;
  34411 #endif /* BCM_XGS3_L3_FORWARD_IPV4_WITH_OPTIONS */
  34412 #if defined(BCM_MIRAGE_SUPPORT)
  34413         if (soc_feature(unit, soc_feature_fp_routing_mirage)) {
  34414             ip_type = bcmFieldIpTypeIpv4Any;
  34415         }
  34416 #endif /* BCM_MIRAGE_SUPPORT */
  34417 
  34418         /* Set to protocol ipv4. */
  34419         BCM_IF_ERROR_RETURN
  34420             (bcm_esw_field_qualify_IpType(unit, rule_hdlr, ip_type));
  34421 
  34422         /* Calculate subnet mask. */
  34423         ip4_mask = BCM_IP4_MASKLEN_TO_ADDR(l3_entry->prefixlen);
  34424         BCM_XGS3_L3_CP_V4_ADDR_TO_V6(ip6_mask, ip4_mask);
  34425 
  34426         /* Rule priority. */
  34427         if(l3_entry->prefixlen) {
  34428             /* This code comes to avoid extra shifts for host v4 entries. */
  34429             rule_priority = l3_entry->prefixlen +
  34430                 (BCM_XGS3_L3_IPV6_PREFIX_LEN - BCM_XGS3_L3_IPV4_PREFIX_LEN);
  34431         } else {
  34432             rule_priority = l3_entry->prefixlen;
  34433         }
  34434 
  34435         /* Set address. */
  34436         BCM_XGS3_L3_CP_V4_ADDR_TO_V6(ip6, l3_entry->addr.ip4);
  34437     }
  34438 
  34439     /* Add destination ip. */
  34440     BCM_IF_ERROR_RETURN
  34441         (bcm_esw_field_qualify_DstIp6(unit, rule_hdlr, ip6, ip6_mask));
  34442 
  34443     /* Set entry priority. */
  34444     BCM_IF_ERROR_RETURN
  34445         (bcm_esw_field_entry_prio_set(unit, rule_hdlr, rule_priority));
  34446 
  34447 
  34448     /* Add  route  action  */
  34449     BCM_IF_ERROR_RETURN(bcm_esw_field_action_add(unit, rule_hdlr,
  34450                                                  bcmFieldActionL3Switch,
  34451                                                  nh_idx, 0));
  34452 
  34453     /* Install entry to hw. */
  34454     BCM_IF_ERROR_RETURN(bcm_esw_field_entry_install(unit, rule_hdlr));
  34455 
  34456     /* Mark entry as valid. */
  34457     tbl_ptr->l3_arr[rule_idx].flags |= BCM_XGS3_L3_ENT_VALID;
  34458 
  34459     /* Reset entry counter. */
  34460     BCM_IF_ERROR_RETURN
  34461         (_bcm_rp_l3_usage_cntr_set(unit, rule_idx,
  34462                                    BCM_XGS3_L3_INVALID_INDEX, l3_entry->flags));
  34463 
  34464     return (BCM_E_NONE);
  34465 }
  34466 
  34467 
  34468 /*
  34469  * Function:
  34470  *      _bcm_rp_l3_entry_delete
  34471  * Purpose:
  34472  *      Remove L3 rule from  field processor.
  34473  * Parameters:
  34474  *      unit      - (IN)SOC unit number.
  34475  *      rule_idx  - (IN)FP entry rule index.
  34476  * Returns:
  34477  *      BCM_E_XXX
  34478  */
  34479 STATIC int
  34480 _bcm_rp_l3_entry_delete(int unit, int rule_idx)
  34481 {
  34482     _bcm_rp_l3_entry_t *l3_entry; /* L3 entry to be removed. */
  34483 
  34484     /* Get l3 entry. */
  34485     l3_entry = &(BCM_XGS3_L3_TBL(unit, rp_prefix)).l3_arr[rule_idx];
  34486 
  34487     /* Uinstall entry from hw. */
  34488     BCM_IF_ERROR_RETURN(bcm_esw_field_entry_remove(unit, l3_entry->rule_hdlr));
  34489 
  34490     /* Remove all actions from the entry */
  34491     BCM_IF_ERROR_RETURN
  34492         (bcm_esw_field_action_remove_all(unit, l3_entry->rule_hdlr));
  34493 
  34494     /* Mark entry as invalid. */
  34495     l3_entry->flags &= ~BCM_XGS3_L3_ENT_VALID;
  34496 
  34497     return (BCM_E_NONE);
  34498 }
  34499 
  34500 /*
  34501  * Function:
  34502  *      _bcm_rp_l3_sw_entry_swap
  34503  * Purpose:
  34504  *      Swap to entries in host/route sw image.
  34505  * Parameters:
  34506  *      unit     - (IN)SOC unit number.
  34507  *      dst_idx  - (IN)Destination entry rule index.
  34508  *      src_idx  - (IN)Original entry rule index.
  34509  * Returns:
  34510  *      void
  34511  */
  34512 STATIC INLINE void
  34513 _bcm_rp_l3_entry_swap(int unit, int dst_idx, int src_idx)
  34514 {
  34515     _bcm_rp_l3_data_t *tbl_ptr;   /* L3 sw table address.  */
  34516     _bcm_rp_l3_entry_t l3_temp;  /* Entry swap buffer.    */
  34517 
  34518     /* Get l3 prefixes table. */
  34519     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  34520 
  34521     /* Preserve source entry. */
  34522     l3_temp = tbl_ptr->l3_arr[src_idx];
  34523 
  34524     /* Write destination to the source. */
  34525     tbl_ptr->l3_arr[src_idx] = tbl_ptr->l3_arr[dst_idx];
  34526 
  34527     /* Write souce to the destination. */
  34528     tbl_ptr->l3_arr[dst_idx] = l3_temp;
  34529     return;
  34530 }
  34531 
  34532 /*
  34533  * Function:
  34534  *      _bcm_rp_l3_entry_shift
  34535  * Purpose:
  34536  *      Copy l3 entry rule from one index to another.
  34537  *      NOTE: Should be called with protection mutex locked.
  34538  * Parameters:
  34539  *      unit     - (IN)SOC unit number.
  34540  *      dst_idx  - (IN)Destination entry rule index.
  34541  *      src_idx  - (IN)Original entry rule index.
  34542  * Returns:
  34543  *      BCM_E_XXX
  34544  */
  34545 STATIC int
  34546 _bcm_rp_l3_entry_shift(int unit, int dst_idx, int src_idx)
  34547 {
  34548     _bcm_rp_l3_data_t *tbl_ptr;   /* L3 sw table address.  */
  34549 
  34550     /* Get l3 prefixes table. */
  34551     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  34552 
  34553     /*
  34554      * If destination & source sitting in the same FP group just swap
  34555      * software images. (This saves  extra hw updates).
  34556      */
  34557     if ((dst_idx/tbl_ptr->rules_per_group) ==
  34558         (src_idx/tbl_ptr->rules_per_group)) {
  34559         _bcm_rp_l3_entry_swap(unit, dst_idx, src_idx);
  34560         return (BCM_E_NONE);
  34561     }
  34562 
  34563     /*
  34564      * Rules are in the different groups we have to move/pack them.
  34565      * Add shifted rule new group and remove it from original one.
  34566      */
  34567     BCM_IF_ERROR_RETURN
  34568         (_bcm_rp_l3_entry_add(unit, dst_idx, &tbl_ptr->l3_arr[src_idx]));
  34569 
  34570     /* Copy rule usage counter. */
  34571     BCM_IF_ERROR_RETURN(_bcm_rp_l3_usage_cntr_set(unit, dst_idx, src_idx, 0));
  34572 
  34573     /* Uinstall original entry from hw. */
  34574     if (BCM_XGS3_L3_RP_HOST_ENTRY((&tbl_ptr->l3_arr[src_idx]))) {
  34575         /* Remove host entry. */
  34576         return  _bcm_rp_l3_entry_delete(unit, src_idx);
  34577     }
  34578 
  34579     /* Remove route entry. */
  34580     return _bcm_rp_lpm_entry_remove(unit, src_idx);
  34581 }
  34582 
  34583 /*
  34584  * Function:
  34585  *      _bcm_rp_grp_rules_num_get
  34586  * Purpose:
  34587  *      Get number rules in group.
  34588  * Parameters:
  34589  *      unit     - (IN)SOC unit number.
  34590  *      rules    - (OUT)Interface table size.
  34591  * Returns:
  34592  *      BCM_E_XXX
  34593  */
  34594 STATIC int
  34595 _bcm_rp_grp_rules_num_get(int unit, int *rules)
  34596 {
  34597     int tcam_sz;         /* FP tcam size.        */
  34598     int tcam_slices;     /* Number of FP slices. */
  34599 
  34600     /* Get tcam size. */
  34601     tcam_sz = soc_mem_index_count(unit, FP_TCAMm);
  34602 
  34603     /* Note tcam_slices only counts internal slices. */
  34604     if (soc_feature(unit, soc_feature_field_slices2)) {
  34605         tcam_slices = 2;
  34606     } else if (soc_feature(unit, soc_feature_field_slices4)) {
  34607         tcam_slices = 4;
  34608     } else {
  34609         tcam_slices = soc_feature(unit, soc_feature_field_slices8) ? 8 : 16;
  34610     }
  34611 
  34612     /* Get number of rules  */
  34613     *rules = (tcam_sz / tcam_slices) - 1;
  34614 
  34615     return (BCM_E_NONE);
  34616 }
  34617 
  34618 /*
  34619  * Function:
  34620  *      _bcm_rp_lpm_group_update
  34621  * Purpose:
  34622  *      Update FP group properties (min/max) prefix length location.
  34623  * Parameters:
  34624  *      unit       - (IN)SOC unit number.
  34625  *      grp_id     - (IN)FP group id.
  34626  * Returns:
  34627  *      void
  34628  */
  34629 STATIC void
  34630 _bcm_rp_lpm_group_update(int unit, int grp_id)
  34631 {
  34632     _bcm_rp_l3_data_t *tbl_ptr;   /* L3 sw table address.                 */
  34633     int max_pfx_len_idx;          /* Max prefix length rule idx in group  */
  34634     int min_pfx_len_idx;          /* Max prefix length rule idx in group  */
  34635     int idx;                      /* Iteration index.                     */
  34636 
  34637     /* Initialization. */
  34638     max_pfx_len_idx = BCM_XGS3_L3_INVALID_INDEX;
  34639     min_pfx_len_idx = BCM_XGS3_L3_INVALID_INDEX;
  34640 
  34641     /* Get l3 prefixes table. */
  34642     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  34643 
  34644     /* Get l3 prefixes table. */
  34645     /* Set min & max to first entry. */
  34646     for (idx = grp_id * tbl_ptr->rules_per_group;
  34647          ((idx < ((grp_id + 1) * tbl_ptr->rules_per_group)) &&
  34648           (idx <= tbl_ptr->route_maxused_rule_id)); idx ++) {
  34649 
  34650         /* Check  only valid entries. */
  34651         if (!(tbl_ptr->l3_arr[idx].flags & BCM_XGS3_L3_ENT_VALID)) {
  34652             continue;
  34653         }
  34654 
  34655         /* Set minimum & maximum to the first valid entry. */
  34656         if(max_pfx_len_idx == BCM_XGS3_L3_INVALID_INDEX) {
  34657             max_pfx_len_idx =  min_pfx_len_idx = idx;
  34658             continue;
  34659         }
  34660 
  34661         /* Check if entry prefix length is less than minimum. */
  34662         if (tbl_ptr->l3_arr[idx].prefixlen <
  34663             tbl_ptr->l3_arr[min_pfx_len_idx].prefixlen){
  34664             min_pfx_len_idx = idx;
  34665         }
  34666 
  34667         /* Check if entry prefix length is greater than maximum. */
  34668         if (tbl_ptr->l3_arr[idx].prefixlen >
  34669             tbl_ptr->l3_arr[max_pfx_len_idx].prefixlen){
  34670             max_pfx_len_idx = idx;
  34671         }
  34672     }
  34673     /* Preserve group max/min prefix length indexes. */
  34674     tbl_ptr->l3_grp[grp_id].max_prefix_len_idx = max_pfx_len_idx;
  34675     tbl_ptr->l3_grp[grp_id].min_prefix_len_idx = min_pfx_len_idx;
  34676     return;
  34677 }
  34678 
  34679 /*
  34680  * Function:
  34681  *      _bcm_rp_lpm_group_add_del
  34682  * Purpose:
  34683  *      Insert prefixlen to the group and
  34684  *      update (min/max) prefix length location.
  34685  * Parameters:
  34686  *      unit       - (IN)SOC unit number.
  34687  *      rule_idx   - (IN)FP prefix rule idx.
  34688  *      prefixlen  - (IN)Prefix length.
  34689  * Returns:
  34690  *      void
  34691  */
  34692 STATIC void
  34693 _bcm_rp_lpm_group_add_del(int unit, int rule_idx, int prefixlen)
  34694 {
  34695     _bcm_rp_l3_data_t *tbl_ptr;   /* L3 sw table address.                 */
  34696     int *max_pfx_len_idx;         /* Max prefix length rule idx in group  */
  34697     int *min_pfx_len_idx;         /* Min prefix length rule idx in group  */
  34698     int grp_id;                   /* FP l3 group index.                   */
  34699 
  34700     /* Get l3 prefixes table. */
  34701     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  34702 
  34703     /* Get group id. */
  34704     grp_id = rule_idx/(tbl_ptr->rules_per_group);
  34705 
  34706     /* Get group min & max prefix length indexes. */
  34707     max_pfx_len_idx = &tbl_ptr->l3_grp[grp_id].max_prefix_len_idx;
  34708     min_pfx_len_idx = &tbl_ptr->l3_grp[grp_id].min_prefix_len_idx;
  34709 
  34710     /* If first group entry added set min & max idx to it. */
  34711     if (BCM_XGS3_L3_INVALID_INDEX != prefixlen) {
  34712         if(0 == tbl_ptr->l3_grp[grp_id].rule_count) {
  34713             *max_pfx_len_idx = *min_pfx_len_idx  = rule_idx;
  34714         } else {
  34715             /* Update group max & min indexes if necessary. */
  34716             if (prefixlen < tbl_ptr->l3_arr[*min_pfx_len_idx].prefixlen) {
  34717                 *min_pfx_len_idx  = rule_idx;
  34718             }
  34719             if (prefixlen > tbl_ptr->l3_arr[*max_pfx_len_idx].prefixlen) {
  34720                 *max_pfx_len_idx  = rule_idx;
  34721             }
  34722         }
  34723         /* Increment number of valid rules. */
  34724         tbl_ptr->l3_grp[grp_id].rule_count++;
  34725     } else {
  34726         /* Prefix deleted from the group. */
  34727         /* If first group entry added set min & max idx to it. */
  34728         if(1 == tbl_ptr->l3_grp[grp_id].rule_count) {
  34729             *max_pfx_len_idx = *min_pfx_len_idx  = BCM_XGS3_L3_INVALID_INDEX;
  34730         } else {
  34731             if ((rule_idx == *max_pfx_len_idx) ||
  34732                 (rule_idx == *min_pfx_len_idx)) {
  34733                 /* Update group max & min indexes. */
  34734                 _bcm_rp_lpm_group_update(unit, grp_id);
  34735             }
  34736         }
  34737         /* Decrement number of valid rules. */
  34738         tbl_ptr->l3_grp[grp_id].rule_count--;
  34739     }
  34740 }
  34741 
  34742 /*
  34743  * Function:
  34744  *      _bcm_rp_l3_deinit
  34745  * Purpose:
  34746  *      Deinitialize L3 functionality on Raptor 6530x devices.
  34747  * Parameters:
  34748  *      unit     - (IN)SOC unit number.
  34749  * Returns:
  34750  *      BCM_E_XXX
  34751  */
  34752 STATIC int
  34753 _bcm_rp_l3_deinit(int unit)
  34754 {
  34755     _bcm_rp_l3_data_t *tbl_ptr;   /* L3 sw table address.         */
  34756     int idx;                      /* Iteration index.             */
  34757     int rv = BCM_E_NONE;          /* Operation return status.     */
  34758     int first_error = BCM_E_NONE; /* First error occured.         */
  34759 
  34760     /* Get l3 prefixes table. */
  34761     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  34762 
  34763     /* If table was not initialized just return. */
  34764     if ((NULL == tbl_ptr->l3_arr) || (NULL == tbl_ptr->l3_grp)) {
  34765         return (BCM_E_NONE);
  34766     }
  34767 
  34768     /* Iterate over all rules & delete them. */
  34769     if (0 == SOC_HW_ACCESS_DISABLE(unit)) {
  34770         for (idx = 0; idx < BCM_XGS3_L3_RP_MAX_PREFIXES(unit); idx++) {
  34771             if (!tbl_ptr->l3_arr[idx].rule_hdlr) {
  34772                 continue;
  34773             }
  34774             rv = _bcm_rp_l3_rule_destroy(unit, idx);
  34775             if ((rv < 0) && (first_error == BCM_E_NONE)) {
  34776                 first_error = rv;
  34777             }
  34778         }
  34779 
  34780         /* Delete allocated FP groups. */
  34781         for (idx = 0; idx < tbl_ptr->l3_group_num; idx ++) {
  34782             if (!tbl_ptr->l3_grp[idx].grp_hdlr) {
  34783                 continue;
  34784             }
  34785             rv = bcm_esw_field_group_destroy(unit,
  34786                                              (tbl_ptr->l3_grp[idx]).grp_hdlr);
  34787             if ((rv < 0) && (first_error == BCM_E_NONE)) {
  34788                 first_error = rv;
  34789             }
  34790         }
  34791     }
  34792 
  34793     /* Free allocated memory. */
  34794     if (tbl_ptr->l3_grp) {
  34795         sal_free(tbl_ptr->l3_grp);
  34796     }
  34797     if (tbl_ptr->l3_arr) {
  34798         sal_free(tbl_ptr->l3_arr);
  34799     }
  34800 
  34801     /* Reset l3 control structure. */
  34802     sal_memset(tbl_ptr, 0, sizeof(_bcm_rp_l3_data_t));
  34803     return (rv);
  34804 }
  34805 
  34806 #ifdef BCM_WARM_BOOT_SUPPORT
  34807 /*
  34808  * Function:
  34809  *      _bcm_hk_l3_field_init
  34810  * Purpose:
  34811  *      Allocate FP group and entries on Hakweye device.
  34812  * Parameters:
  34813  *      unit     - (IN)SOC unit number.
  34814  * Returns:
  34815  *      BCM_E_XXX
  34816  */
  34817 STATIC int
  34818 _bcm_hk_l3_field_init(int unit)
  34819 {
  34820     _bcm_rp_l3_data_t *tbl_ptr;   /* L3 sw table address.      */
  34821     bcm_field_qset_t qset;        /* FP qualifiers set.        */
  34822     int idx;                      /* Iteration index.          */
  34823     int rv = BCM_E_NONE;          /* Operation return status.  */
  34824 
  34825     /* Get l3 prefixes table. */
  34826     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  34827 
  34828     /* Create qualifiers set. */
  34829     BCM_FIELD_QSET_INIT(qset);
  34830 
  34831     /* Add qualifier fields. */
  34832     BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyIpType);
  34833     BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyL2Format);
  34834     BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyVlanFormat);
  34835     BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyDstIp6);
  34836     BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyL3Routable);
  34837 
  34838     /* Add FP groups. */
  34839     for (idx = 0; idx < tbl_ptr->l3_group_num; idx++) {
  34840         /* Create FP group. */
  34841         if (tbl_ptr->l3_grp[idx].grp_hdlr) {
  34842             /* This group has been created. */
  34843             continue;
  34844         }
  34845 
  34846         rv = bcm_esw_field_group_create(unit, qset, BCM_FIELD_GROUP_PRIO_ANY,
  34847                                         &tbl_ptr->l3_grp[idx].grp_hdlr);
  34848         if (rv < 0) {
  34849             return rv;
  34850         }
  34851         /* Set max & min prefix length indexes. */
  34852         tbl_ptr->l3_grp[idx].max_prefix_len_idx = BCM_XGS3_L3_INVALID_INDEX;
  34853         tbl_ptr->l3_grp[idx].min_prefix_len_idx = BCM_XGS3_L3_INVALID_INDEX;
  34854     }
  34855 
  34856     /* Sort groups by priority. */
  34857     _shr_sort(tbl_ptr->l3_grp, tbl_ptr->l3_group_num,
  34858               sizeof(_bcm_rp_l3_fp_group_t), _bcm_rp_grp_priority_cmp);
  34859 
  34860     /* Allocate rule handlers. */
  34861     for (idx = 0; idx < BCM_XGS3_L3_RP_MAX_PREFIXES(unit); idx++) {
  34862         if (tbl_ptr->l3_arr[idx].rule_hdlr) {
  34863             /* This entry has been created. */
  34864             continue;
  34865         }
  34866         rv = _bcm_rp_l3_rule_create(unit, idx);
  34867         if (rv < 0) {
  34868             return rv;
  34869         }
  34870     }
  34871     return (BCM_E_NONE);
  34872 }
  34873 #endif /* BCM_WARM_BOOT_SUPPORT */
  34874 
  34875 /*
  34876  * Function:
  34877  *      _bcm_rp_l3_init
  34878  * Purpose:
  34879  *      Initialize l3 functionality on Raptor 6530x device.
  34880  * Parameters:
  34881  *      unit     - (IN)SOC unit number.
  34882  * Returns:
  34883  *      BCM_E_XXX
  34884  */
  34885 STATIC int
  34886 _bcm_rp_l3_init(int unit)
  34887 {
  34888     _bcm_rp_l3_data_t *tbl_ptr;   /* L3 sw table address.      */
  34889     bcm_field_qset_t qset;        /* FP qualifiers set.        */
  34890     int mem_sz;                   /* Allocated memory size.    */
  34891     int idx;                      /* Iteration index.          */
  34892     int rv = BCM_E_NONE;          /* Operation return status.  */
  34893 #ifdef BCM_WARM_BOOT_SUPPORT
  34894     int group_idx = 0;
  34895 #endif
  34896     /* If number of prefixes is 0 - L3 functionality is disabled.*/
  34897     /*
  34898     * COVERITY
  34899     *
  34900     * The operands don't affect result. It is kept intentionally as
  34901     * a defensive default for future development.
  34902     */
  34903     /* coverity[result_independent_of_operands] */
  34904     if(!BCM_XGS3_L3_RP_MAX_PREFIXES(unit)) {
  34905     /* coverity[dead_error_line : FALSE] */
  34906         return (BCM_E_NONE);
  34907     }
  34908 
  34909     /* If fp rules & groups already present remove them first. */
  34910     if(BCM_XGS3_L3_INITIALIZED(unit)) {
  34911         _bcm_rp_l3_deinit(unit);
  34912     }
  34913 
  34914     /* Get l3 prefixes table. */
  34915     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  34916 
  34917     /* Set min used host index & max used route index. */
  34918     tbl_ptr->route_maxused_rule_id = -1;
  34919     tbl_ptr->host_minused_rule_id = BCM_XGS3_L3_RP_MAX_PREFIXES(unit);
  34920 
  34921     /* Get number of rules per group. */
  34922     _bcm_rp_grp_rules_num_get(unit, &tbl_ptr->rules_per_group);
  34923 
  34924     /* Get number of groups. */
  34925     tbl_ptr->l3_group_num =
  34926         BCM_XGS3_L3_RP_MAX_PREFIXES(unit)/tbl_ptr->rules_per_group;
  34927     if (BCM_XGS3_L3_RP_MAX_PREFIXES(unit) % tbl_ptr->rules_per_group) {
  34928         tbl_ptr->l3_group_num++;
  34929     }
  34930 
  34931     /* FP group handlers. */
  34932     mem_sz = tbl_ptr->l3_group_num * sizeof(_bcm_rp_l3_fp_group_t);
  34933     BCM_XGS3_L3_ALLOC(tbl_ptr->l3_grp, mem_sz, "l3_fp_groups");
  34934     if (NULL == tbl_ptr->l3_grp) {
  34935         _bcm_rp_l3_deinit(unit);
  34936         return (BCM_E_MEMORY);
  34937     }
  34938 
  34939     /* FP rule handlers. */
  34940     mem_sz = BCM_XGS3_L3_RP_MAX_PREFIXES(unit) * sizeof(_bcm_rp_l3_entry_t);
  34941     BCM_XGS3_L3_ALLOC(tbl_ptr->l3_arr, mem_sz, "l3_fp_rules");
  34942     if (NULL == tbl_ptr->l3_arr) {
  34943         _bcm_rp_l3_deinit(unit);
  34944         return (BCM_E_MEMORY);
  34945     }
  34946 
  34947     /* Create qualifiers set. */
  34948     BCM_FIELD_QSET_INIT(qset);
  34949 
  34950     /* Add qualifier fields. */
  34951     BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyIpType);
  34952     BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyL2Format);
  34953     BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyVlanFormat);
  34954     BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyDstIp6);
  34955 #if defined(BCM_MIRAGE_SUPPORT)
  34956     if (soc_feature(unit, soc_feature_fp_routing_mirage)) {
  34957         BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyDstPort);
  34958     } else
  34959 #endif /* BCM_MIRAGE_SUPPORT */
  34960     {
  34961         BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyL3Routable);
  34962     }
  34963 
  34964 #ifdef BCM_WARM_BOOT_SUPPORT
  34965     if (SOC_IS_HAWKEYE(unit)) {
  34966         if (SOC_WARM_BOOT(unit)) {
  34967             rv = bcm_esw_field_group_traverse(unit,
  34968                                           _bcm_rp_l3_group_reload,
  34969                                           &group_idx);
  34970             /* Init is done if nothing recovered. */
  34971             if (tbl_ptr->route_maxused_rule_id == -1 &&
  34972                 tbl_ptr->host_minused_rule_id == BCM_XGS3_L3_RP_MAX_PREFIXES(unit)) {
  34973                 return BCM_E_NONE;
  34974             }
  34975             rv = _bcm_hk_l3_field_init(unit);
  34976             return (rv);
  34977         }
  34978         return BCM_E_NONE;
  34979     }
  34980 #endif
  34981 
  34982     /* Add FP groups. */
  34983     for (idx = 0; idx < tbl_ptr->l3_group_num; idx++) {
  34984         /* Create FP group. */
  34985         rv = bcm_esw_field_group_create(unit, qset, BCM_FIELD_GROUP_PRIO_ANY,
  34986                                         &tbl_ptr->l3_grp[idx].grp_hdlr);
  34987         if (rv < 0) {
  34988             goto RP_INIT_ERR;
  34989         }
  34990         /* Set max & min prefix length indexes. */
  34991         tbl_ptr->l3_grp[idx].max_prefix_len_idx = BCM_XGS3_L3_INVALID_INDEX;
  34992         tbl_ptr->l3_grp[idx].min_prefix_len_idx = BCM_XGS3_L3_INVALID_INDEX;
  34993     }
  34994 
  34995     /* Sort groups by priority. */
  34996     _shr_sort(tbl_ptr->l3_grp, tbl_ptr->l3_group_num,
  34997               sizeof(_bcm_rp_l3_fp_group_t), _bcm_rp_grp_priority_cmp);
  34998 
  34999     /* Allocate rule handlers. */
  35000     for (idx = 0; idx < BCM_XGS3_L3_RP_MAX_PREFIXES(unit); idx++) {
  35001         rv = _bcm_rp_l3_rule_create(unit, idx);
  35002         if (rv < 0) {
  35003             goto RP_INIT_ERR;
  35004         }
  35005     }
  35006     return (BCM_E_NONE);
  35007 
  35008 RP_INIT_ERR:
  35009     _bcm_rp_l3_deinit(unit);
  35010     return rv;
  35011 }
  35012 
  35013 /*
  35014  * Function:
  35015  *      _bcm_rp_l3_entry_idx_get
  35016  * Purpose:
  35017  *      Get host entry index.
  35018  * Parameters:
  35019  *      unit      - (IN)SOC unit number.
  35020  *      l3cfg     - (IN)Host lookup key.
  35021  *      rule_idx  - (OUT) Entry index.
  35022  * Returns:
  35023  *      BCM_E_XXX
  35024  */
  35025 STATIC int
  35026 _bcm_rp_l3_entry_idx_get(int unit, _bcm_l3_cfg_t *l3cfg, int *rule_idx)
  35027 {
  35028     _bcm_rp_l3_data_t *tbl_ptr;   /* L3 sw table address.      */
  35029     _bcm_rp_l3_entry_t *l3_entry; /* L3 host entry.            */
  35030     int ipv6;                     /* Entry family.             */
  35031     int idx;                      /* Iteration index.          */
  35032 
  35033     /* Get l3 prefixes table. */
  35034     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  35035 
  35036     /* Get entry type. */
  35037     ipv6 = l3cfg->l3c_flags & BCM_L3_IP6;
  35038 
  35039     /* Iterate over all host rules try to match passed address. */
  35040     for (idx = tbl_ptr->host_minused_rule_id;
  35041          idx < BCM_XGS3_L3_RP_MAX_PREFIXES(unit); idx++) {
  35042 
  35043         l3_entry = &tbl_ptr->l3_arr[idx];
  35044         /* Skip family mismatch and invalid entries. */
  35045         if (!(l3_entry->flags & BCM_XGS3_L3_ENT_VALID) ||
  35046             ((l3_entry->flags & BCM_L3_IP6) != ipv6)) {
  35047             continue;
  35048         }
  35049 
  35050         /* Compare requested address with entry address. */
  35051         if (ipv6) {
  35052             if(sal_memcmp(l3_entry->addr.ip6,
  35053                           l3cfg->l3c_ip6, sizeof(bcm_ip6_t))) {
  35054                 continue;
  35055             }
  35056         } else {
  35057             if (l3_entry->addr.ip4 != l3cfg->l3c_ip_addr) {
  35058                 continue;
  35059             }
  35060         }
  35061         /* Entry Found. */
  35062         *rule_idx = idx;
  35063         return (BCM_E_NONE);
  35064     }
  35065     /* Passed over all the entries & didn't find the match. */
  35066     return (BCM_E_NOT_FOUND);
  35067 }
  35068 
  35069 /*
  35070  * Function:
  35071  *      _bcm_rp_l3_ent_parse
  35072  * Purpose:
  35073  *      Service routine used to parse  l3 entry to api format.
  35074  * Parameters:
  35075  *      unit      - (IN)SOC unit number.
  35076  *      l3cfg     - (OUT)l3 entry  lookup key & search result.
  35077  *      nh_idx    - (OUT)Next hop index.
  35078  *      rule_idx  - (IN)Rule index.
  35079  * Returns:
  35080  *      void
  35081  */
  35082 STATIC void
  35083 _bcm_rp_l3_ent_parse(int unit, _bcm_l3_cfg_t *l3cfg, int *nh_idx, int rule_idx)
  35084 {
  35085     _bcm_rp_l3_data_t *tbl_ptr;   /* L3 sw table address.     */
  35086     int ipv6;                     /* Entry is IPv6 flag.      */
  35087     uint64 usage_cntr;            /* Entry usage counter.     */
  35088     int rv;                       /* Operation return status. */
  35089     bcm_field_stat_t stat_type;   /* FP entry Stat type.      */
  35090     int stat_id;                  /* FP entry Stat ID.        */
  35091 
  35092     /* Get l3 prefixes table. */
  35093     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  35094 
  35095     /*  Get lookup type. */
  35096     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
  35097 
  35098     /* Reset entry flags first. */
  35099     l3cfg->l3c_flags = (ipv6) ? BCM_L3_IP6 : 0;
  35100 
  35101     /* Set entry hw index. */
  35102     l3cfg->l3c_hw_index = rule_idx;
  35103 
  35104     /* Set vrf id to default. */
  35105     l3cfg->l3c_vrf = BCM_L3_VRF_DEFAULT;
  35106 
  35107 
  35108     /* Get the Stat ID. */
  35109     rv = bcm_esw_field_entry_stat_get(unit, tbl_ptr->l3_arr[rule_idx].rule_hdlr,
  35110                                   &stat_id);
  35111     if (BCM_SUCCESS(rv)) {
  35112         /* Get entry Stat value. */
  35113         stat_type = bcmFieldStatPackets;
  35114         rv = bcm_esw_field_stat_get(unit, stat_id, stat_type, &usage_cntr);
  35115         if ((rv >= 0) && (!COMPILER_64_IS_ZERO(usage_cntr))) {
  35116             l3cfg->l3c_flags |= BCM_L3_HIT;
  35117         }
  35118     }
  35119 
  35120     /* Get next hop index. */
  35121     if(nh_idx) {
  35122         *nh_idx =  tbl_ptr->l3_arr[rule_idx].nh_idx;
  35123     }
  35124 
  35125     return;
  35126 }
  35127 
  35128 /*
  35129  * Function:
  35130  *      _bcm_rp_l3_pack
  35131  * Purpose:
  35132  *      Pack l3 entries & free space for routes.
  35133  * Parameters:
  35134  *      unit     - (IN)SOC unit number.
  35135  * Returns:
  35136  *      BCM_E_NONE - If pack succeeded.
  35137  *      BCM_E_FULL - Otherwise.
  35138  */
  35139 STATIC int
  35140 _bcm_rp_l3_pack(int unit)
  35141 {
  35142     _bcm_rp_l3_data_t *tbl_ptr;   /* L3 sw table address.      */
  35143     int rule_idx;                 /* Entry index to write.     */
  35144 
  35145     /* Get l3 prefixes table. */
  35146     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  35147 
  35148     /* Try to find unused index. */
  35149     for(rule_idx = BCM_XGS3_L3_RP_MAX_PREFIXES(unit) - 1;
  35150         rule_idx > tbl_ptr->route_maxused_rule_id; rule_idx--) {
  35151         if(!(tbl_ptr->l3_arr[rule_idx].flags & BCM_XGS3_L3_ENT_VALID)) {
  35152             break;
  35153         }
  35154     }
  35155 
  35156     /* If failed to allocated a new index -> table is full. */
  35157     if (rule_idx == tbl_ptr->route_maxused_rule_id) {
  35158         return (BCM_E_FULL);
  35159     }
  35160 
  35161     /* Shift last entry into an empty slot. */
  35162     _bcm_rp_l3_entry_shift(unit, rule_idx, tbl_ptr->host_minused_rule_id);
  35163 
  35164     /* Update host minused rule id. */
  35165     rule_idx = tbl_ptr->host_minused_rule_id;
  35166     while (!(tbl_ptr->l3_arr[rule_idx].flags & BCM_XGS3_L3_ENT_VALID) &&
  35167            rule_idx < BCM_XGS3_L3_RP_MAX_PREFIXES(unit)) {
  35168         rule_idx++;
  35169     }
  35170     tbl_ptr->host_minused_rule_id = rule_idx;
  35171 
  35172     return (BCM_E_NONE);
  35173 }
  35174 
  35175 /*
  35176  * Function:
  35177  *      _bcm_rp_l3_get
  35178  * Purpose:
  35179  *      Get an entry from L3 table.
  35180  * Parameters:
  35181  *      unit     - (IN)SOC unit number.
  35182  *      l3cfg    - (IN/OUT)l3 entry  lookup key & search result.
  35183  *      nh_index - (OUT)Next hop index.
  35184  * Returns:
  35185  *      BCM_E_XXX
  35186  */
  35187 STATIC int
  35188 _bcm_rp_l3_get(int unit, _bcm_l3_cfg_t *l3cfg, int *nh_idx)
  35189 {
  35190     int clear_hit;                /* Clear hit bit indicator.  */
  35191     int rule_idx;                 /* Array entry index.        */
  35192     int rv;                       /* Operation return status.  */
  35193 
  35194     /* Preserve clear_hit value. */
  35195     clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR;
  35196 
  35197     /* Lookup hosts table for match. */
  35198     rv = _bcm_rp_l3_entry_idx_get(unit, l3cfg, &rule_idx);
  35199     if(rv >= 0) {
  35200         /* Entry Found - parse it. */
  35201         _bcm_rp_l3_ent_parse(unit, l3cfg, nh_idx, rule_idx);
  35202 
  35203         /* Clear the HIT bit */
  35204         if (clear_hit) {
  35205             rv = _bcm_rp_l3_usage_cntr_set(unit, rule_idx,
  35206                                            BCM_XGS3_L3_INVALID_INDEX, 0);
  35207         }
  35208     }
  35209 
  35210     return (rv);
  35211 }
  35212 
  35213 /*
  35214  * Function:
  35215  *      _bcm_rp_l3_add
  35216  * Purpose:
  35217  *      Add an entry to L3 table.
  35218  * Parameters:
  35219  *      unit     - (IN)SOC unit number.
  35220  *      l3cfg    - (IN)l3 entry information.
  35221  *      nh_idx   - (IN)Next hop index.
  35222  * Returns:
  35223  *      BCM_E_XXX
  35224  */
  35225 STATIC int
  35226 _bcm_rp_l3_add(int unit, _bcm_l3_cfg_t *l3cfg, int nh_idx)
  35227 {
  35228     _bcm_rp_l3_entry_t l3_entry;  /* Host entry information.   */
  35229     _bcm_rp_l3_data_t *tbl_ptr;   /* L3 sw table address.      */
  35230     int rule_idx;                 /* Entry index to write.     */
  35231     int rv;                       /* Operation return status.  */
  35232 
  35233     /* Initialization. */
  35234     sal_memset(&l3_entry, 0, sizeof(_bcm_rp_l3_entry_t));
  35235 
  35236     /* Get l3 prefixes table. */
  35237     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  35238 #ifdef BCM_WARM_BOOT_SUPPORT
  35239     /* Initialize field if necessary. */
  35240     if (SOC_IS_HAWKEYE(unit)) {
  35241         if ( tbl_ptr->route_maxused_rule_id == -1 &&
  35242              tbl_ptr->host_minused_rule_id == BCM_XGS3_L3_RP_MAX_PREFIXES(unit)) {
  35243             rv = _bcm_hk_l3_field_init(unit);
  35244             if (BCM_FAILURE(rv)) {
  35245                 return (rv);
  35246             }
  35247         }
  35248     }
  35249 #endif
  35250     /* Fill the entry info. */
  35251 
  35252     /* Set family . */
  35253     l3_entry.flags = l3cfg->l3c_flags & BCM_L3_IP6;
  35254 
  35255     /* Set hit bit. */
  35256     l3_entry.flags |= l3cfg->l3c_flags & BCM_L3_HIT;
  35257 
  35258     /* Set next hop index. */
  35259     l3_entry.nh_idx = nh_idx;
  35260 
  35261     /* Set address and prefix length. */
  35262     if (l3_entry.flags & BCM_L3_IP6) {
  35263         l3_entry.prefixlen = BCM_XGS3_L3_IPV6_PREFIX_LEN;
  35264         sal_memcpy(l3_entry.addr.ip6, l3cfg->l3c_ip6, sizeof(bcm_ip6_t));
  35265     } else {
  35266         l3_entry.prefixlen = BCM_XGS3_L3_IPV4_PREFIX_LEN;
  35267         l3_entry.addr.ip4 = l3cfg->l3c_ip_addr;
  35268     }
  35269 
  35270     /* Handle replacement if hw index already known, write directly. */
  35271     if (BCM_XGS3_L3_INVALID_INDEX != l3cfg->l3c_hw_index) {
  35272         rule_idx = l3cfg->l3c_hw_index;
  35273 
  35274         /* Remove original entry & actions */
  35275         _bcm_rp_l3_entry_delete(unit, rule_idx);
  35276     } else {
  35277         /* Allocate a new index otherwise. */
  35278         for(rule_idx = BCM_XGS3_L3_RP_MAX_PREFIXES(unit) - 1;
  35279             rule_idx > tbl_ptr->route_maxused_rule_id; rule_idx--) {
  35280             if(!(tbl_ptr->l3_arr[rule_idx].flags & BCM_XGS3_L3_ENT_VALID)) {
  35281                 break;
  35282             }
  35283         }
  35284         /* If failed to allocated a new index -> table is full. */
  35285         if (rule_idx == tbl_ptr->route_maxused_rule_id) {
  35286             return (BCM_E_FULL);
  35287         }
  35288     }
  35289 
  35290     /* Add rule to FP. */
  35291     rv = _bcm_rp_l3_entry_add(unit, rule_idx, &l3_entry);
  35292 
  35293     /* Write status check. */
  35294     if ((rv >= 0) && (BCM_XGS3_L3_INVALID_INDEX == l3cfg->l3c_hw_index)) {
  35295         /* Update host entry count. */
  35296         (l3_entry.flags & BCM_L3_IP6) ?  \
  35297             BCM_XGS3_L3_IP6_CNT(unit)++ : BCM_XGS3_L3_IP4_CNT(unit)++;
  35298 
  35299         /* Update host min used index. */
  35300         if (rule_idx < tbl_ptr->host_minused_rule_id) {
  35301             tbl_ptr->host_minused_rule_id = rule_idx;
  35302         }
  35303     }
  35304 
  35305     return (rv);
  35306 }
  35307 
  35308 /*
  35309  * Function:
  35310  *      _bcm_rp_l3_del
  35311  * Purpose:
  35312  *      Delete an entry from L3 table.
  35313  * Parameters:
  35314  *      unit     - (IN)SOC unit number.
  35315  *      l3cfg    - (IN)l3 entry deletion key.
  35316  * Returns:
  35317  *      BCM_E_XXX
  35318  */
  35319 STATIC int
  35320 _bcm_rp_l3_del(int unit, _bcm_l3_cfg_t *l3cfg)
  35321 {
  35322     _bcm_rp_l3_data_t *tbl_ptr;   /* L3 sw table address.      */
  35323     int rule_idx;                 /* L3 entry rule index.      */
  35324     int rv;                       /* Operation return status.  */
  35325 
  35326     /* Get l3 prefixes table. */
  35327     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  35328 
  35329     /* Lookup hosts table for match. */
  35330     rv =  _bcm_rp_l3_entry_idx_get(unit, l3cfg, &rule_idx);
  35331     BCM_IF_ERROR_RETURN(rv);
  35332 
  35333     /* Delete the entry.*/
  35334     rv = _bcm_rp_l3_entry_delete(unit, rule_idx);
  35335 
  35336     /* Write status check. */
  35337     if (rv >= 0) {
  35338         /* Update host entry count. */
  35339         (l3cfg->l3c_flags & BCM_L3_IP6) ? \
  35340             BCM_XGS3_L3_IP6_CNT(unit)-- : BCM_XGS3_L3_IP4_CNT(unit)--;
  35341 
  35342         /* Update host min used index. */
  35343         if (rule_idx == tbl_ptr->host_minused_rule_id) {
  35344             while (!(tbl_ptr->l3_arr[rule_idx].flags & BCM_XGS3_L3_ENT_VALID) &&
  35345                    rule_idx < BCM_XGS3_L3_RP_MAX_PREFIXES(unit)) {
  35346                 rule_idx++;
  35347             }
  35348             tbl_ptr->host_minused_rule_id = rule_idx;
  35349         }
  35350     }
  35351 
  35352     return (rv);
  35353 }
  35354 
  35355 /*
  35356  * Function:
  35357  *      _bcm_rp_l3_get_by_idx
  35358  * Purpose:
  35359  *      Get an entry from L3 table by index.
  35360  * Parameters:
  35361  *      unit     - (IN)SOC unit number.
  35362  *      dma_ptr  - (IN)NOT USED
  35363  *      idx      - (IN)Index to read.
  35364  *      l3cfg    - (OUT)l3 entry search result.
  35365  *      nh_index - (OUT)Next hop index.
  35366  * Returns:
  35367  *      BCM_E_XXX
  35368  */
  35369 STATIC int
  35370 _bcm_rp_l3_get_by_idx(int unit, void *dma_ptr, int idx,
  35371                       _bcm_l3_cfg_t *l3cfg, int *nh_idx)
  35372 {
  35373     _bcm_rp_l3_data_t *tbl_ptr;   /* L3 sw table address.      */
  35374     _bcm_rp_l3_entry_t *l3_entry; /* L3 host entry.            */
  35375     int clear_hit;                /* Clear hit bit indicator.  */
  35376     int rule_idx;                 /* Array entry index.        */
  35377     int ipv6;                     /* Entry family to read.     */
  35378     int rv = BCM_E_NONE;          /* Operation return status.  */
  35379 
  35380     /* Get entry type. */
  35381     ipv6 = l3cfg->l3c_flags & BCM_L3_IP6;
  35382 
  35383     /* Get l3 prefixes table. */
  35384     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  35385 
  35386     /* Preserve clear_hit value. */
  35387     clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR;
  35388 
  35389     /* Calculate rule index. */
  35390     rule_idx = BCM_XGS3_L3_RP_MAX_PREFIXES(unit) - idx;
  35391     if (rule_idx < 0) {
  35392         return (BCM_E_NOT_FOUND);
  35393     }
  35394 
  35395     l3_entry = &tbl_ptr->l3_arr[rule_idx];
  35396 
  35397     /* Make sure entry is a host & valid. */
  35398     if ((rule_idx < tbl_ptr->host_minused_rule_id) ||
  35399         (!(l3_entry->flags & BCM_XGS3_L3_ENT_VALID))) {
  35400         return (BCM_E_NOT_FOUND);
  35401     }
  35402 
  35403     /* Get entry protocol. */
  35404     l3cfg->l3c_flags = l3_entry->flags & BCM_L3_IP6;
  35405 
  35406     /* If protocol doesn't match the request return. */
  35407     if ((l3_entry->flags  & BCM_L3_IP6) != ipv6) {
  35408         return (BCM_E_NONE);
  35409     }
  35410 
  35411     /* Get entry  address. */
  35412     if (ipv6) {
  35413         sal_memcpy(l3cfg->l3c_ip6, l3_entry->addr.ip6, sizeof(bcm_ip6_t));
  35414     } else {
  35415         l3cfg->l3c_ip_addr = l3_entry->addr.ip4;
  35416     }
  35417 
  35418     /* Parset entry flags. */
  35419     _bcm_rp_l3_ent_parse(unit, l3cfg, nh_idx, rule_idx);
  35420 
  35421     /* Clear the HIT bit */
  35422     if (clear_hit) {
  35423         rv = _bcm_rp_l3_usage_cntr_set(unit, rule_idx,
  35424                                        BCM_XGS3_L3_INVALID_INDEX, 0);
  35425     }
  35426 
  35427     /* Set index to l3cfg. */
  35428     l3cfg->l3c_hw_index = idx;
  35429 
  35430     return (rv);
  35431 }
  35432 
  35433 /*
  35434  * Function:
  35435  *      _bcm_rp_lpm_ent_parse
  35436  * Purpose:
  35437  *      Service routine used to parse  l3 entry to api format.
  35438  * Parameters:
  35439  *      unit      - (IN)SOC unit number.
  35440  *      lpm_cfg   - (IN/OUT)l3 entry  lookup key & search result.
  35441  *      nh_idx    - (OUT)Next hop index.
  35442  *      rule_idx  - (IN)Rule index.
  35443  * Returns:
  35444  *      void
  35445  */
  35446 STATIC void
  35447 _bcm_rp_lpm_ent_parse(int unit, _bcm_defip_cfg_t *lpm_cfg,
  35448                       int *nh_idx, int rule_idx)
  35449 {
  35450     _bcm_rp_l3_data_t *tbl_ptr;   /* L3 sw table address.     */
  35451     int ipv6;                     /* Entry is IPv6 flag.      */
  35452     uint64 usage_cntr;            /* Entry usage counter.     */
  35453     int rv;                       /* Operation return status. */
  35454     bcm_field_stat_t stat_type;   /* FP entry Stat type.      */
  35455     int stat_id;                  /* FP entry Stat ID.        */
  35456 
  35457     /* Get l3 prefixes table. */
  35458     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  35459 
  35460     /*  Get lookup type. */
  35461     ipv6 = (lpm_cfg->defip_flags & BCM_L3_IP6);
  35462 
  35463     /* Reset entry flags first. */
  35464     lpm_cfg->defip_flags = (ipv6) ? BCM_L3_IP6 : 0;
  35465 
  35466     /* Set entry ecmp flag. */
  35467     lpm_cfg->defip_flags |=
  35468         (tbl_ptr->l3_arr[rule_idx].flags & BCM_L3_MULTIPATH);
  35469 
  35470     /* Set vrf id to default. */
  35471     lpm_cfg->defip_vrf = BCM_L3_VRF_DEFAULT;
  35472 
  35473     /* Set index of the defip table entry */
  35474     lpm_cfg->defip_index = rule_idx;
  35475 
  35476     /* Get the Stat ID. */
  35477     rv = bcm_esw_field_entry_stat_get(unit,
  35478                                       tbl_ptr->l3_arr[rule_idx].rule_hdlr,
  35479                                       &stat_id);
  35480     if (BCM_SUCCESS(rv)) {
  35481         /* Get entry Stat value. */
  35482         stat_type = bcmFieldStatPackets;
  35483         rv = bcm_esw_field_stat_get(unit, stat_id, stat_type, &usage_cntr);
  35484         if ((rv >= 0) && (!COMPILER_64_IS_ZERO(usage_cntr))) {
  35485             lpm_cfg->defip_flags  |= BCM_L3_HIT;
  35486         }
  35487     }
  35488 
  35489     /* Get next hop index. */
  35490     if(nh_idx) {
  35491         *nh_idx =  tbl_ptr->l3_arr[rule_idx].nh_idx;
  35492     }
  35493 
  35494     return;
  35495 }
  35496 
  35497 /*
  35498  * Function:
  35499  *      _bcm_rp_lpm_entry_idx_get
  35500  * Purpose:
  35501  *      Get route entry rule index.
  35502  * Parameters:
  35503  *      unit      - (IN)SOC unit number.
  35504  *      lpm_cfg   - (IN)Route lookup key.
  35505  *      rule_idx  - (OUT) Entry index.
  35506  * Returns:
  35507  *      BCM_E_XXX
  35508  */
  35509 STATIC int
  35510 _bcm_rp_lpm_entry_idx_get(int unit, _bcm_defip_cfg_t *lpm_cfg, int *rule_idx)
  35511 {
  35512     _bcm_rp_l3_data_t *tbl_ptr;   /* L3 sw table address.      */
  35513     _bcm_rp_l3_entry_t *l3_entry; /* L3 route entry.           */
  35514     int ipv6;                     /* Entry family.             */
  35515     int idx;                      /* Iteration index.          */
  35516 
  35517     /* Get l3 prefixes table. */
  35518     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  35519 
  35520     /* Get entry type. */
  35521     ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6;
  35522 
  35523     /* Iterate over all host rules try to match passed address. */
  35524     for (idx = 0; idx <= tbl_ptr->route_maxused_rule_id; idx++) {
  35525 
  35526         l3_entry = &tbl_ptr->l3_arr[idx];
  35527         /* Skip family mismatch/prefix length mismatch  and invalid entries. */
  35528         if (!(l3_entry->flags & BCM_XGS3_L3_ENT_VALID) ||
  35529             ((l3_entry->flags & BCM_L3_IP6) != ipv6) ||
  35530             (l3_entry->prefixlen != lpm_cfg->defip_sub_len)) {
  35531             continue;
  35532         }
  35533 
  35534         /* Compare requested address with entry address. */
  35535         if (ipv6) {
  35536             if(sal_memcmp(l3_entry->addr.ip6,
  35537                           lpm_cfg->defip_ip6_addr, sizeof(bcm_ip6_t))) {
  35538                 continue;
  35539             }
  35540         } else {
  35541             if (l3_entry->addr.ip4 != lpm_cfg->defip_ip_addr) {
  35542                 continue;
  35543             }
  35544         }
  35545         /* Entry Found. */
  35546         *rule_idx = idx;
  35547         return (BCM_E_NONE);
  35548     }
  35549     /* Passed over all the entries & didn't find the match. */
  35550     return (BCM_E_NOT_FOUND);
  35551 }
  35552 
  35553 /*
  35554  * Function:
  35555  *      _bcm_rp_lpm_entry_insert
  35556  * Purpose:
  35557  *      Allocate rule index and write route to FP.
  35558  *      Function invoked recursively if there is no room in destination
  35559  *      group & rules shift is required. Max prefix length rule in each
  35560  *      group shifted one group ahead.
  35561  * Parameters:
  35562  *      unit        - (IN)SOC unit number.
  35563  *      lpm_cfg     - (IN)Buffer to fill defip information.
  35564  *      nh_ecmp_idx - (IN)Next hop or ecmp group index.
  35565  * Returns:
  35566  *      BCM_E_XXX
  35567  */
  35568 STATIC int
  35569 _bcm_rp_lpm_entry_insert(int unit, _bcm_rp_l3_entry_t *l3_entry, int shift_idx)
  35570 {
  35571     _bcm_rp_l3_data_t *tbl_ptr;   /* L3 sw table address.                 */
  35572     int max_prefix_len_idx;       /* Max prefix length rule idx in group  */
  35573     int *max_rt_idx;              /* Last route rule index.               */
  35574     int grp_idx;                  /* FP group index.                      */
  35575     int insert_idx = BCM_XGS3_L3_INVALID_INDEX;  /* Rule insertion index. */
  35576 
  35577     /* Get l3 prefixes table. */
  35578     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  35579 
  35580     /* Get max used route rule index. */
  35581     max_rt_idx = &tbl_ptr->route_maxused_rule_id;
  35582 
  35583     if(BCM_XGS3_L3_INVALID_INDEX == shift_idx) {
  35584         /* Attempt to insert into the first group. */
  35585         grp_idx = 0;
  35586     } else  {
  35587         /*
  35588          * Group is full shift required - move maximum prefix
  35589          * length rule to the next group (group + 1).
  35590          */
  35591         grp_idx = (shift_idx/tbl_ptr->rules_per_group) + 1;
  35592     }
  35593 
  35594     /* Iterate over all the group & try to find free rule idx. */
  35595     for(; grp_idx < tbl_ptr->l3_group_num; grp_idx++) {
  35596         /* Get group longet prefix rule index. */
  35597         max_prefix_len_idx = tbl_ptr->l3_grp[grp_idx].max_prefix_len_idx;
  35598 
  35599         /* Check if group has an empty slot. NOTE: max_rt_idx is 0 based.*/
  35600         if((grp_idx + 1) * tbl_ptr->rules_per_group  > (*max_rt_idx + 1)) {
  35601 
  35602             /* Make sure we  are not overwriting host entries. */
  35603             if((*max_rt_idx) + 1 == tbl_ptr->host_minused_rule_id) {
  35604                 /* Attempt to pack host entries. */
  35605                 BCM_IF_ERROR_RETURN(_bcm_rp_l3_pack(unit));
  35606             }
  35607 
  35608             /* Set write index to max used + 1 */
  35609             insert_idx = ++(*max_rt_idx);
  35610             break;
  35611 
  35612             /* Check if prefix length belongs to the group & there */
  35613         } else if(tbl_ptr->l3_arr[max_prefix_len_idx].prefixlen >
  35614                   l3_entry->prefixlen) {
  35615 
  35616             /* If this is last group - we can't shift rules anymore. */
  35617             if (grp_idx == tbl_ptr->l3_group_num - 1) {
  35618                 break;
  35619             }
  35620 
  35621             /*
  35622              *  Shift max prefix length entry to the next group.
  35623              *  Write new entry into max prefix length entry place.
  35624              */
  35625             insert_idx = max_prefix_len_idx;
  35626             BCM_IF_ERROR_RETURN
  35627                 (_bcm_rp_lpm_entry_insert(unit,&tbl_ptr->l3_arr[insert_idx],
  35628                                           insert_idx));
  35629             break;
  35630         }
  35631     }
  35632 
  35633     /* If failed to allocate an index - table is full. */
  35634     if (insert_idx == BCM_XGS3_L3_INVALID_INDEX) {
  35635         return (BCM_E_FULL);
  35636     }
  35637 
  35638     /* Write entry to FP & update group properties. */
  35639     BCM_IF_ERROR_RETURN(_bcm_rp_l3_entry_add(unit, insert_idx, l3_entry));
  35640 
  35641     /* Update group max/min prefix location. */
  35642     _bcm_rp_lpm_group_add_del(unit, insert_idx, l3_entry->prefixlen);
  35643 
  35644     /* If entry was shifted -> delete original entry. */
  35645     if(BCM_XGS3_L3_INVALID_INDEX != shift_idx) {
  35646         /* Remove shifted rule. */
  35647         BCM_IF_ERROR_RETURN(_bcm_rp_l3_entry_delete(unit, shift_idx));
  35648 
  35649         /* Decrement number of rules in original group */
  35650         _bcm_rp_lpm_group_add_del(unit, shift_idx, BCM_XGS3_L3_INVALID_INDEX);
  35651     }
  35652     return (BCM_E_NONE);
  35653 }
  35654 
  35655 /*
  35656  * Function:
  35657  *      _bcm_rp_lpm_entry_remove
  35658  * Purpose:
  35659  *      Free rule index and delete route rule from FP.
  35660  *      Function fills gaps rule array. And invoked recursively
  35661  *      if there are rules in higher groups - which need to be
  35662  *      shifted to to lower group which currently has an empty space.
  35663  * Parameters:
  35664  *      unit     - (IN)SOC unit number.
  35665  *      rule_idx - (IN)Route entry rule for deletion.
  35666  * Returns:
  35667  *      BCM_E_XXX
  35668  */
  35669 STATIC int
  35670 _bcm_rp_lpm_entry_remove(int unit, int rule_idx)
  35671 {
  35672     _bcm_rp_l3_data_t *tbl_ptr;   /* L3 sw table address.      */
  35673     int *max_rt_idx;              /* Last route rule index.    */
  35674     int shift_idx;                /* Shifted entry rule index. */
  35675     int grp_idx;                  /* FP group index.           */
  35676 
  35677     /* Get l3 prefixes table. */
  35678     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  35679 
  35680     /* Get max used route rule index. */
  35681     max_rt_idx = &tbl_ptr->route_maxused_rule_id;
  35682 
  35683     /* Get FP group index. */
  35684     grp_idx = (rule_idx/tbl_ptr->rules_per_group);
  35685 
  35686     /* Remove the rule from FP. */
  35687     BCM_IF_ERROR_RETURN(_bcm_rp_l3_entry_delete(unit, rule_idx));
  35688 
  35689     /* Update group prefix count & min/max locations. */
  35690     _bcm_rp_lpm_group_add_del(unit, rule_idx, BCM_XGS3_L3_INVALID_INDEX);
  35691 
  35692     /* If last entry was removed just decrement max used route index. */
  35693     if (rule_idx == (*max_rt_idx)) {
  35694         /* Last entry was removed update max route index. */
  35695         (*max_rt_idx)--;
  35696         return (BCM_E_NONE);
  35697     }
  35698 
  35699     /*
  35700      *  If all the routes are in the same group, take the last one
  35701      *  and write to the location of the deleted one.
  35702      *  If routes are spread across the groups, shift min prefixlen
  35703      *  route in each group one group down.
  35704      */
  35705     if((grp_idx + 1) * tbl_ptr->rules_per_group > (*max_rt_idx)) {
  35706 
  35707         /* Last group. */
  35708         shift_idx = (*max_rt_idx);
  35709 
  35710         /* Swap last entry with deleted one. */
  35711         _bcm_rp_l3_entry_swap(unit, rule_idx, shift_idx);
  35712 
  35713         /* If maximum prefix length entry shifted update index. */
  35714         if (shift_idx == tbl_ptr->l3_grp[grp_idx].max_prefix_len_idx) {
  35715             tbl_ptr->l3_grp[grp_idx].max_prefix_len_idx = rule_idx;
  35716         }
  35717 
  35718         /* If minimum prefix length entry shifted update index. */
  35719         if (shift_idx == tbl_ptr->l3_grp[grp_idx].min_prefix_len_idx) {
  35720             tbl_ptr->l3_grp[grp_idx].min_prefix_len_idx = rule_idx;
  35721         }
  35722 
  35723         /* Since we are shifting last entry decrement max route index. */
  35724         (*max_rt_idx)--;
  35725     } else {
  35726 
  35727         /* Shift min prefix length entry from the next group if any. */
  35728         shift_idx = tbl_ptr->l3_grp[grp_idx + 1].min_prefix_len_idx;
  35729 
  35730         /* Perform rule shift operation. */
  35731         BCM_IF_ERROR_RETURN(_bcm_rp_l3_entry_shift(unit, rule_idx, shift_idx));
  35732 
  35733         /* Add shifted rule prefix length to the destination group. */
  35734         _bcm_rp_lpm_group_add_del(unit, rule_idx,
  35735                                   tbl_ptr->l3_arr[shift_idx].prefixlen);
  35736     }
  35737     return (BCM_E_NONE);
  35738 }
  35739 
  35740 
  35741 /*
  35742  * Function:
  35743  *      _bcm_rp_lpm_get
  35744  * Purpose:
  35745  *      Get an entry from DEFIP table.
  35746  * Parameters:
  35747  *      unit        - (IN)SOC unit number.
  35748  *      lpm_cfg     - (IN)Buffer to fill defip information.
  35749  *      nh_ecmp_idx - (IN)Next hop or ecmp group index
  35750  * Returns:
  35751  *      BCM_E_XXX
  35752  */
  35753 STATIC int
  35754 _bcm_rp_lpm_get(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx)
  35755 {
  35756     int clear_hit;                /* Clear hit bit indicator.  */
  35757     int rule_idx;                 /* Array entry index.        */
  35758     int rv;                       /* Operation return status.  */
  35759 
  35760     /* Preserve clear_hit value. */
  35761     clear_hit = lpm_cfg->defip_flags & BCM_L3_HIT_CLEAR;
  35762 
  35763     /* Lookup hosts table for match. */
  35764     rv = _bcm_rp_lpm_entry_idx_get(unit, lpm_cfg, &rule_idx);
  35765     if(rv >= 0) {
  35766         /* Entry Found - parse it. */
  35767         _bcm_rp_lpm_ent_parse(unit, lpm_cfg, nh_ecmp_idx, rule_idx);
  35768 
  35769         /* Clear the HIT bit */
  35770         if (clear_hit) {
  35771             rv = _bcm_rp_l3_usage_cntr_set(unit, rule_idx,
  35772                                            BCM_XGS3_L3_INVALID_INDEX, 0);
  35773         }
  35774     }
  35775 
  35776     return (rv);
  35777 }
  35778 
  35779 /*
  35780  * Function:
  35781  *      _bcm_rp_lpm_add
  35782  * Purpose:
  35783  *      Add an entry to route table.
  35784  * Parameters:
  35785  *      unit        - (IN)SOC unit number.
  35786  *      lpm_cfg     - (IN)Buffer to fill defip information.
  35787  *      nh_ecmp_idx - (IN)Next hop or ecmp group index.
  35788  * Returns:
  35789  *      BCM_E_XXX
  35790  */
  35791 STATIC int
  35792 _bcm_rp_lpm_add(int unit, _bcm_defip_cfg_t *lpm_cfg, int nh_ecmp_idx)
  35793 {
  35794     _bcm_rp_l3_data_t *tbl_ptr;   /* L3 sw table address.      */
  35795     _bcm_rp_l3_entry_t l3_entry;  /* Route entry.              */
  35796     int rule_idx;                 /* Entry index to write.     */
  35797     int rv;                       /* Operation return status.  */
  35798 
  35799     /* Get l3 prefixes table. */
  35800     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  35801 
  35802 #ifdef BCM_WARM_BOOT_SUPPORT
  35803     /* Initialize field if necessary. */
  35804     if (SOC_IS_HAWKEYE(unit)) {
  35805         if ( tbl_ptr->route_maxused_rule_id == -1 &&
  35806              tbl_ptr->host_minused_rule_id == BCM_XGS3_L3_RP_MAX_PREFIXES(unit)) {
  35807             rv = _bcm_hk_l3_field_init(unit);
  35808             if (BCM_FAILURE(rv)) {
  35809                 return (rv);
  35810             }
  35811         }
  35812     }
  35813 #endif
  35814     /* Fill the entry info. */
  35815     /* Set family and prefix length. */
  35816     l3_entry.flags = lpm_cfg->defip_flags & BCM_L3_IP6;
  35817 
  35818     /* Set hit bit. */
  35819     l3_entry.flags |= lpm_cfg->defip_flags & BCM_L3_HIT;
  35820 
  35821     /* Set ecmp bit. */
  35822     l3_entry.flags |= lpm_cfg->defip_flags & BCM_L3_MULTIPATH;
  35823 
  35824     /* Set prefix length. */
  35825     l3_entry.prefixlen = lpm_cfg->defip_sub_len;
  35826 
  35827     /* Set subnet address */
  35828     if (l3_entry.flags & BCM_L3_IP6) {
  35829         sal_memcpy(l3_entry.addr.ip6, lpm_cfg->defip_ip6_addr, sizeof(bcm_ip6_t));
  35830     } else {
  35831         l3_entry.addr.ip4 = lpm_cfg->defip_ip_addr;
  35832     }
  35833 
  35834     /* Set next hop index. */
  35835     l3_entry.nh_idx = nh_ecmp_idx;
  35836 
  35837     /* Handle replacement if hw index already known, write directly. */
  35838     if (BCM_XGS3_L3_INVALID_INDEX != lpm_cfg->defip_index) {
  35839 
  35840         rule_idx = lpm_cfg->defip_index;
  35841 
  35842         /* Remove original entry & actions */
  35843         _bcm_rp_l3_entry_delete(unit, rule_idx);
  35844 
  35845         /* Only next hop update is supported. */
  35846         tbl_ptr->l3_arr[rule_idx].nh_idx = nh_ecmp_idx;
  35847 
  35848         /* Write rule to FP. */
  35849         rv = _bcm_rp_l3_entry_add(unit, rule_idx, &tbl_ptr->l3_arr[rule_idx]);
  35850 
  35851         return (rv);
  35852     }
  35853 
  35854     /* Add rule to FP. */
  35855     rv = _bcm_rp_lpm_entry_insert(unit, &l3_entry, BCM_XGS3_L3_INVALID_INDEX);
  35856 
  35857     /* Increment number of routes. */
  35858     if (rv >= 0) {
  35859         BCM_XGS3_L3_DEFIP_CNT_INC(unit, (lpm_cfg->defip_flags & BCM_L3_IP6));
  35860     }
  35861 
  35862     return (rv);
  35863 }
  35864 
  35865 /*
  35866  * Function:
  35867  *      _bcm_rp_lpm_del
  35868  * Purpose:
  35869  *      Delete an entry from route table.
  35870  * Parameters:
  35871  *      unit    - (IN)SOC unit number.
  35872  *      lpm_cfg - (IN)Buffer to fill defip information.
  35873  * Returns:
  35874  *      BCM_E_XXX
  35875  */
  35876 STATIC int
  35877 _bcm_rp_lpm_del(int unit, _bcm_defip_cfg_t *lpm_cfg)
  35878 {
  35879     int rule_idx;                 /* Array entry index.        */
  35880     int rv;                       /* Operation return status.  */
  35881 
  35882     /* Lookup hosts table for match. */
  35883     rv = _bcm_rp_lpm_entry_idx_get(unit, lpm_cfg, &rule_idx);
  35884     BCM_IF_ERROR_RETURN(rv);
  35885 
  35886     /* Remove the route rule from FP. */
  35887     rv = _bcm_rp_lpm_entry_remove(unit, rule_idx);
  35888 
  35889     /* Decrement number of routes. */
  35890     if (rv >= 0) {
  35891         BCM_XGS3_L3_DEFIP_CNT_DEC(unit, (lpm_cfg->defip_flags & BCM_L3_IP6));
  35892     }
  35893 
  35894     return (rv);
  35895 }
  35896 
  35897 /*
  35898  * Function:
  35899  *      _bcm_rp_lpm_update_match
  35900  * Purpose:
  35901  *      Update/Delete all entries in defip table matching a certain rule.
  35902  * Parameters:
  35903  *      unit     - (IN)SOC unit number.
  35904  *      trv_data - (IN)Delete pattern + compare,act,notify routines.
  35905  * Returns:
  35906  *      BCM_E_XXX
  35907  */
  35908 STATIC int
  35909 _bcm_rp_lpm_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data)
  35910 {
  35911     _bcm_rp_l3_data_t *tbl_ptr;   /* L3 sw table address.      */
  35912     _bcm_rp_l3_entry_t *l3_entry; /* L3 route entry.           */
  35913     _bcm_rp_l3_entry_t *rt_tbl;   /* L3 route table shadow.    */
  35914     _bcm_defip_cfg_t lpm_cfg;     /* Buffer to fill route info.*/
  35915     int nh_ecmp_idx;              /* Next hop/Ecmp group index.*/
  35916     int cmp_result;               /* Test routine result.      */
  35917     int tbl_sz;                   /* L3 route table size.      */
  35918     int ipv6;                     /* Entry family.             */
  35919     int idx;                      /* Iteration index.          */
  35920     int rv = BCM_E_NOT_FOUND;     /* Operation return status.  */
  35921 
  35922     /* Get l3 prefixes table. */
  35923     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  35924 
  35925     /* Create shaddow image. */
  35926 
  35927     tbl_sz= (tbl_ptr->route_maxused_rule_id + 1) * sizeof(_bcm_rp_l3_entry_t);
  35928 
  35929     /* Allocate memory for shadow image. */
  35930     rt_tbl = sal_alloc(tbl_sz, "rp_routes_shadow");
  35931     if (NULL == rt_tbl) {
  35932         return (BCM_E_MEMORY);
  35933     }
  35934 
  35935     /* Copy all  the routes. */
  35936     sal_memcpy(rt_tbl, tbl_ptr->l3_arr, tbl_sz);
  35937 
  35938     /* Preserve route table size. */
  35939     tbl_sz = tbl_ptr->route_maxused_rule_id + 1;
  35940 
  35941     /* Get requested entry type. */
  35942     ipv6 = trv_data->flags & BCM_L3_IP6;
  35943 
  35944     /* Iterate over all host rules try to match passed address. */
  35945     for (idx = 0; idx < tbl_sz; idx++) {
  35946 
  35947         l3_entry = rt_tbl + idx;
  35948 
  35949 
  35950         /* Skip family mismatch/prefix length mismatch  and invalid entries. */
  35951         if (!(l3_entry->flags & BCM_XGS3_L3_ENT_VALID) ||
  35952             ((l3_entry->flags & BCM_L3_IP6) != ipv6)) {
  35953             continue;
  35954         }
  35955 
  35956         /* Zero destination buffer first. */
  35957         sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t));
  35958 
  35959         /* Set entry flags. */
  35960         lpm_cfg.defip_flags = l3_entry->flags & BCM_L3_IP6;
  35961 
  35962         /* Fill entry ip address &  prefix length. */
  35963         if (ipv6) {
  35964             sal_memcpy(lpm_cfg.defip_ip6_addr, l3_entry->addr.ip6,
  35965                        sizeof(bcm_ip6_t));
  35966         } else {
  35967             lpm_cfg.defip_ip_addr = l3_entry->addr.ip4;
  35968         }
  35969         lpm_cfg.defip_sub_len = l3_entry->prefixlen;
  35970 
  35971         /* Get entry flags  & info . */
  35972         _bcm_rp_lpm_get(unit, &lpm_cfg, &nh_ecmp_idx);
  35973 
  35974         /* Execute operation routine if any. */
  35975         if (trv_data->op_cb) {
  35976             rv = (*trv_data->op_cb) (unit, (void *)trv_data,
  35977                                      (void *)&lpm_cfg,
  35978                                      (void *)&nh_ecmp_idx, &cmp_result);
  35979             if (rv < 0) {
  35980                 sal_free(rt_tbl);
  35981                 return rv;
  35982             }
  35983         }
  35984     }
  35985     /* Free shadow image. */
  35986     sal_free(rt_tbl);
  35987     return (BCM_E_NONE);
  35988 }
  35989 
  35990 #ifdef BCM_WARM_BOOT_SUPPORT
  35991 /*
  35992  * Function:
  35993  *      _bcm_rp_l3_group_reload
  35994  * Purpose:
  35995  *      Restore l3 route entries from FP.
  35996  * Parameters:
  35997  *      unit     - (IN)SOC unit number.
  35998  * Returns:
  35999  *      BCM_E_XXX
  36000  */
  36001 static int _bcm_rp_l3_group_reload(int unit, bcm_field_group_t group,
  36002     void *user_data)
  36003 {
  36004     int idx, pfx_len, rule_idx, rv, nh_index, update_grp_idx = 0;
  36005     int *grp_idx;
  36006     int entry_count, entry_num;
  36007     bcm_field_IpType_t iptype;
  36008     bcm_ip6_t data;
  36009     bcm_ip6_t mask;
  36010     bcm_ip_t ip_mask;
  36011     _bcm_rp_l3_data_t *tbl_ptr;
  36012     int alloc_sz;
  36013     bcm_field_entry_t *entry_array, entry_id;
  36014     uint32 param0, param1;
  36015 
  36016     BCM_IF_ERROR_RETURN
  36017         (bcm_esw_field_entry_multi_get(unit, group, 0, NULL, &entry_num));
  36018 
  36019     if (entry_num == 0) {
  36020         return BCM_E_PARAM;
  36021     }
  36022 
  36023     alloc_sz = sizeof(bcm_field_entry_t) * entry_num;
  36024     entry_array = sal_alloc(alloc_sz, "Field IDs");
  36025     if (NULL == entry_array) {
  36026         return BCM_E_MEMORY;
  36027     }
  36028     sal_memset(entry_array, 0, alloc_sz);
  36029 
  36030     rv = bcm_esw_field_entry_multi_get(unit, group, entry_num,
  36031                                        entry_array, &entry_count);
  36032 
  36033     if (BCM_FAILURE(rv)) {
  36034         sal_free(entry_array);
  36035         return rv;
  36036     }
  36037 
  36038     if (entry_count != entry_num) {
  36039         /* Why didn't we get the number of ID's we were told existed? */
  36040         sal_free(entry_array);
  36041         return BCM_E_INTERNAL;
  36042     }
  36043 
  36044     grp_idx = (int *)user_data;
  36045     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, rp_prefix);
  36046 
  36047     for (idx = 0; idx < entry_num; idx++) {
  36048         entry_id = entry_array[idx];
  36049         rv = bcm_esw_field_action_get(unit, entry_id,
  36050                                       bcmFieldActionL3Switch,
  36051                                       &param0, &param1);
  36052         if (BCM_SUCCESS(rv)) {
  36053             if (*grp_idx >= tbl_ptr->l3_group_num) {
  36054                 sal_free(entry_array);
  36055                 return (BCM_E_NONE);
  36056             }
  36057             tbl_ptr->l3_grp[*grp_idx].grp_hdlr = group;
  36058             nh_index = param0;
  36059         } else {
  36060             continue;
  36061         }
  36062 
  36063         rv = bcm_esw_field_qualify_IpType_get(unit, entry_id, &iptype);
  36064         if (BCM_FAILURE(rv)) {
  36065             continue;
  36066         }
  36067 
  36068         rv = bcm_esw_field_qualify_DstIp6_get(unit, entry_id, &data, &mask);
  36069         if (BCM_FAILURE(rv)) {
  36070             continue;
  36071         }
  36072 
  36073         update_grp_idx = 1;
  36074 
  36075         if (iptype == bcmFieldIpTypeIpv6) {
  36076             pfx_len = bcm_ip6_mask_length(mask);
  36077             if (pfx_len == BCM_XGS3_L3_IPV6_PREFIX_LEN) {
  36078                 /* Assume this is host entry. */
  36079                 tbl_ptr->host_minused_rule_id--;
  36080                 rule_idx = tbl_ptr->host_minused_rule_id;
  36081                 BCM_XGS3_L3_IP6_CNT(unit)++;
  36082             } else {
  36083                 /* Assume this is route entry. */
  36084                 tbl_ptr->route_maxused_rule_id++;
  36085                 rule_idx = tbl_ptr->route_maxused_rule_id;
  36086                 BCM_XGS3_L3_DEFIP_CNT_INC(unit, TRUE);
  36087                 tbl_ptr->l3_grp[*grp_idx].rule_count++;
  36088             }
  36089             sal_memcpy(tbl_ptr->l3_arr[rule_idx].addr.ip6, data, sizeof(bcm_ip6_t));
  36090             tbl_ptr->l3_arr[rule_idx].prefixlen = pfx_len;
  36091             tbl_ptr->l3_arr[rule_idx].flags |= BCM_L3_IP6;
  36092         } else {
  36093             sal_memcpy(&ip_mask,
  36094                         (uint8 *)mask + BCM_XGS3_V4_IN_V6_OFFSET,
  36095                         sizeof(bcm_ip_t));
  36096             pfx_len = bcm_ip_mask_length(ip_mask);
  36097             if (pfx_len == BCM_XGS3_L3_IPV4_PREFIX_LEN) {
  36098                 /* Assume this is host entry. */
  36099                 tbl_ptr->host_minused_rule_id--;
  36100                 rule_idx = tbl_ptr->host_minused_rule_id;
  36101                 BCM_XGS3_L3_IP4_CNT(unit)++;
  36102 
  36103             } else {
  36104                 /* Assume this is route entry. */
  36105                 tbl_ptr->route_maxused_rule_id++;
  36106                 rule_idx = tbl_ptr->route_maxused_rule_id;
  36107                 BCM_XGS3_L3_DEFIP_CNT_INC(unit, FALSE);
  36108                 tbl_ptr->l3_grp[*grp_idx].rule_count++;
  36109             }
  36110             sal_memcpy(&tbl_ptr->l3_arr[rule_idx].addr.ip4,
  36111                         (uint8 *)data + BCM_XGS3_V4_IN_V6_OFFSET,
  36112                         sizeof(bcm_ip_t));
  36113             tbl_ptr->l3_arr[rule_idx].prefixlen = pfx_len;
  36114         }
  36115         tbl_ptr->l3_arr[rule_idx].rule_hdlr = entry_id;
  36116         tbl_ptr->l3_arr[rule_idx].nh_idx = nh_index;
  36117         tbl_ptr->l3_arr[rule_idx].flags |= BCM_XGS3_L3_ENT_VALID;
  36118     }
  36119 
  36120     if (update_grp_idx) {
  36121         if (tbl_ptr->route_maxused_rule_id != -1 &&
  36122             *grp_idx < tbl_ptr->l3_group_num) {
  36123             _bcm_rp_lpm_group_update(unit, *grp_idx);
  36124         }
  36125         *grp_idx = *grp_idx+1;
  36126     }
  36127 
  36128     if (rv == BCM_E_NOT_FOUND) {
  36129         rv = BCM_E_NONE; /* Do not propagate this error */
  36130     }
  36131 
  36132     sal_free(entry_array);
  36133     return BCM_E_NONE;
  36134 }
  36135 #endif /* BCM_WARM_BOOT_SUPPORT */
  36136 
  36137 #endif /* BCM_RAPTOR_SUPPORT  || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */
  36138 
  36139 #endif /* BCM_FIREBOLT_SUPPORT  */
  36140 
  36141 /*
  36142  * Function:
  36143  *      _bcm_xgs3_l3_hw_call_init
  36144  * Purpose:
  36145  *      Initialize L3 hardware operations memories & callbacks.
  36146  * Parameters:
  36147  *      unit      - (IN)SOC unit number.
  36148  * Returns:
  36149  *      BCM_E_XXX
  36150  */
  36151 STATIC int
  36152 _bcm_xgs3_l3_hw_call_init(int unit)
  36153 {
  36154 #ifdef BCM_FIREBOLT_SUPPORT
  36155     static _bcm_l3_hw_calls_t     fb_hw_call[BCM_MAX_NUM_UNITS]; /* FBX hw calls .        */
  36156     static _bcm_l3_intf_fields_t  fb_l3_intf_fields; /* L3 intf fields.       */
  36157     static _bcm_l3_nh_fields_t    fb_nh_fields;      /* NH table fields.      */
  36158     static _bcm_l3_fields_t       fb_l3_v4_fields;   /* L3 ipv4 table fields. */
  36159     static _bcm_l3_fields_t       fb_l3_v6_fields;   /* L3 ipv6 table fields. */
  36160 #endif /* BCM_FIREBOLT_SUPPORT */
  36161 #if defined (BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \
  36162     defined(BCM_HAWKEYE_SUPPORT)
  36163     static _bcm_l3_hw_calls_t    rp_hw_call[BCM_MAX_NUM_UNITS]; /* Raptor/Raven hw calls. */
  36164 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */
  36165 #if defined(BCM_TRIUMPH_SUPPORT)
  36166     static _bcm_l3_hw_calls_t     tr_hw_call[BCM_MAX_NUM_UNITS]; /* Triumph hw calls. */
  36167     static _bcm_l3_fields_t       tr_l3_v6_fields;  /* Truimph l3 ipv6 fields.*/
  36168 #endif /* BCM_TRIUMPH_SUPPORT */
  36169 #if defined(BCM_TRX_SUPPORT)
  36170     static _bcm_l3_nh_fields_t    trx_nh_fields;     /* NH table fields.      */
  36171 #endif /* BCM_TRX_SUPPORT */
  36172 #if defined(BCM_TRIDENT_SUPPORT)
  36173     static _bcm_l3_hw_calls_t     td_hw_call[BCM_MAX_NUM_UNITS]; /* Trident hw calls. */
  36174 #endif /* BCM_TRIDENT_SUPPORT */
  36175 #if defined(BCM_TRIUMPH2_SUPPORT)
  36176     static _bcm_l3_hw_calls_t     tr2_hw_call[BCM_MAX_NUM_UNITS]; /* Triumph2 hw calls. */
  36177 #endif /* BCM_TRIUMPH2_SUPPORT */
  36178 #if defined(BCM_TRIDENT2_SUPPORT)
  36179     static _bcm_l3_hw_calls_t     td2_hw_call[BCM_MAX_NUM_UNITS]; /* Trident2 hw calls. */
  36180     static _bcm_l3_fields_t       td2_l3_v4_fields;    /* Trident2 l3 ipv4 fields.*/
  36181     static _bcm_l3_fields_t       td2_l3_v4_2_fields;  /* Trident2 l3 ext ipv4 fields.*/
  36182     static _bcm_l3_fields_t       td2_l3_v6_fields;    /* Trident2 l3 ipv6 fields.*/
  36183     static _bcm_l3_fields_t       td2_l3_v6_4_fields;  /* Trident2 l3 ext ipv6 fields.*/
  36184     static _bcm_l3_intf_fields_t  td2_l3_intf_fields;  /* L3 intf fields.       */
  36185 #endif /* BCM_TRIDENT2_SUPPORT */
  36186 #if defined(BCM_TRIUMPH3_SUPPORT)
  36187     static _bcm_l3_hw_calls_t     tr3_hw_call[BCM_MAX_NUM_UNITS]; /* Triumph3 hw calls. */
  36188     static _bcm_l3_fields_t       tr3_l3_v4_fields;    /* Truimph l3 ipv4 fields.*/
  36189     static _bcm_l3_fields_t       tr3_l3_v4_2_fields;  /* Truimph l3 ext ipv4 fields.*/
  36190     static _bcm_l3_fields_t       tr3_l3_v6_fields;    /* Truimph l3 ipv6 fields.*/
  36191     static _bcm_l3_fields_t       tr3_l3_v6_4_fields;  /* Truimph l3 ext ipv6 fields.*/
  36192     static _bcm_l3_fields_t       tr3_l3_v4esm_fields;    /* Truimph l3 ipv4 esm fields.*/
  36193     static _bcm_l3_fields_t       tr3_l3_v4esm_w_fields;  /* Truimph l3 ext esm ipv4 fields.*/
  36194     static _bcm_l3_fields_t       tr3_l3_v6esm_fields;    /* Truimph l3 ipv6 esm fields.*/
  36195     static _bcm_l3_fields_t       tr3_l3_v6esm_w_fields;  /* Truimph l3 ext esm ipv6 fields.*/
  36196     static _bcm_l3_intf_fields_t  tr3_l3_intf_fields;  /* L3 intf fields.       */
  36197 #endif /* BCM_TRIUMPH3_SUPPORT */
  36198 #if defined(BCM_KATANA2_SUPPORT)
  36199     static _bcm_l3_hw_calls_t     kt2_hw_call[BCM_MAX_NUM_UNITS]; /* Katana2 hw calls */
  36200 #endif /* BCM_KATANA2_SUPPORT */
  36201     static int hw_call_initialized[BCM_MAX_NUM_UNITS] = {0};
  36202     _bcm_l3_hw_calls_t     tmp_hw_call;              /* Common hw calls.      */
  36203 
  36204     if (!hw_call_initialized[unit]) {
  36205         /* Hw calls pointers. */
  36206         sal_memset(&tmp_hw_call, 0, sizeof(_bcm_l3_hw_calls_t));
  36207         tmp_hw_call.l3_clear_all      = _bcm_xgs3_l3_clear_all;
  36208         tmp_hw_call.if_get            = _bcm_xgs3_l3_intf_get;
  36209         tmp_hw_call.if_add            = _bcm_xgs3_l3_intf_add;
  36210         tmp_hw_call.if_del            = _bcm_xgs3_l3_intf_del;
  36211         tmp_hw_call.if_tnl_init_get   = _bcm_xgs3_l3_intf_tnl_init_get;
  36212         tmp_hw_call.if_tnl_init_set   = _bcm_xgs3_l3_intf_tnl_init_set;
  36213         tmp_hw_call.if_tnl_init_reset = _bcm_xgs3_l3_intf_tnl_init_reset;
  36214         tmp_hw_call.nh_get            = _bcm_xgs3_nh_get;
  36215         tmp_hw_call.nh_del            = _bcm_xgs3_nh_del;
  36216         tmp_hw_call.nh_update_match   = _bcm_xgs3_nh_update_match;
  36217         tmp_hw_call.tnl_term_get      = _bcm_xgs3_l3_tnl_term_get;
  36218         tmp_hw_call.tnl_term_add      = _bcm_xgs3_l3_tnl_term_add;
  36219         tmp_hw_call.tnl_term_del      = _bcm_xgs3_l3_tnl_term_del;
  36220         tmp_hw_call.tnl_term_traverse = _bcm_xgs3_l3_tnl_term_traverse;
  36221         tmp_hw_call.tnl_init_get      = _bcm_xgs3_l3_tnl_init_get;
  36222         tmp_hw_call.tnl_init_add      = _bcm_xgs3_l3_tnl_init_add;
  36223         tmp_hw_call.tnl_init_del      = _bcm_xgs3_l3_tnl_init_del;
  36224         tmp_hw_call.tnl_dscp_get      = _bcm_xgs3_l3_tnl_dscp_get;
  36225         tmp_hw_call.tnl_dscp_set      = _bcm_xgs3_l3_tnl_dscp_set;
  36226 
  36227 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \
  36228     defined(BCM_HAWKEYE_SUPPORT)
  36229         /* Hw calls pointers. */
  36230         sal_memcpy(&rp_hw_call[unit], &tmp_hw_call, sizeof(_bcm_l3_hw_calls_t));
  36231         rp_hw_call[unit].nh_add            = _bcm_fb_nh_add;
  36232         rp_hw_call[unit].l3_get            = _bcm_rp_l3_get;
  36233         rp_hw_call[unit].l3_add            = _bcm_rp_l3_add;
  36234         rp_hw_call[unit].l3_del            = _bcm_rp_l3_del;
  36235         rp_hw_call[unit].l3_get_by_idx     = _bcm_rp_l3_get_by_idx;
  36236         rp_hw_call[unit].l3_traverse       = _bcm_xgs3_l3_traverse;
  36237         rp_hw_call[unit].l3_del_match      = _bcm_xgs3_l3_del_match;
  36238         rp_hw_call[unit].lpm_get           = _bcm_rp_lpm_get;
  36239         rp_hw_call[unit].lpm_add           = _bcm_rp_lpm_add;
  36240         rp_hw_call[unit].lpm_del           = _bcm_rp_lpm_del;
  36241         rp_hw_call[unit].lpm_update_match  = _bcm_rp_lpm_update_match;
  36242         if (soc_feature(unit, soc_feature_fp_routing_mirage)) {
  36243             rp_hw_call[unit].ecmp_grp_get      = _bcm_xgs3_ecmp_grp_get;
  36244             rp_hw_call[unit].ecmp_grp_add      = _bcm_xgs3_ecmp_grp_add;
  36245             rp_hw_call[unit].ecmp_grp_del      = _bcm_xgs3_ecmp_grp_del;
  36246         }
  36247 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */
  36248 #ifdef BCM_FIREBOLT_SUPPORT
  36249         /* Hw calls pointers. */
  36250         sal_memcpy(&fb_hw_call[unit], &tmp_hw_call, sizeof(_bcm_l3_hw_calls_t));
  36251         fb_hw_call[unit].nh_add            = _bcm_fb_nh_add;
  36252         fb_hw_call[unit].ecmp_grp_get      = _bcm_xgs3_ecmp_grp_get;
  36253         fb_hw_call[unit].ecmp_grp_add      = _bcm_xgs3_ecmp_grp_add;
  36254         fb_hw_call[unit].ecmp_grp_del      = _bcm_xgs3_ecmp_grp_del;
  36255         fb_hw_call[unit].l3_get            = _bcm_xgs3_l3_get;
  36256         fb_hw_call[unit].l3_add            = _bcm_xgs3_l3_add;
  36257         fb_hw_call[unit].l3_del            = _bcm_xgs3_l3_del;
  36258         fb_hw_call[unit].l3_get_by_idx     = _bcm_xgs3_l3_get_by_idx;
  36259         fb_hw_call[unit].l3_traverse       = _bcm_xgs3_l3_traverse;
  36260         fb_hw_call[unit].l3_del_match      = _bcm_xgs3_l3_del_match;
  36261         fb_hw_call[unit].l3_bucket_get     = _bcm_xgs3_l3_bucket_get;
  36262         fb_hw_call[unit].ipmc_get          = _bcm_fb_l3_ipmc_get;
  36263         fb_hw_call[unit].ipmc_add          = _bcm_fb_l3_ipmc_add;
  36264         fb_hw_call[unit].ipmc_del          = _bcm_fb_l3_ipmc_del;
  36265         fb_hw_call[unit].ipmc_get_by_idx   = _bcm_fb_l3_ipmc_get_by_idx;
  36266         fb_hw_call[unit].lpm_get           = _bcm_fbx_lpm_get;
  36267         fb_hw_call[unit].lpm_add           = _bcm_fbx_lpm_add;
  36268         fb_hw_call[unit].lpm_del           = _bcm_fbx_lpm_del;
  36269         fb_hw_call[unit].lpm_update_match  = _bcm_fbx_lpm_update_match;
  36270         if(!(SOC_IS_HURRICANEX(unit) || SOC_IS_GREYHOUND(unit))) {
  36271            fb_hw_call[unit].if_vrf_get        = _bcm_fb_l3_intf_vrf_get;
  36272            fb_hw_call[unit].if_vrf_bind       = _bcm_fb_l3_intf_vrf_bind;
  36273            fb_hw_call[unit].if_vrf_unbind     = _bcm_fb_l3_intf_vrf_unbind;
  36274         }
  36275 #if defined(BCM_TRIUMPH_SUPPORT)
  36276         sal_memcpy(&tr_hw_call[unit], &fb_hw_call[unit], sizeof(_bcm_l3_hw_calls_t));
  36277         tr_hw_call[unit].ipmc_get          = _bcm_tr_l3_ipmc_get;
  36278         tr_hw_call[unit].ipmc_add          = _bcm_tr_l3_ipmc_add;
  36279         tr_hw_call[unit].ipmc_del          = _bcm_tr_l3_ipmc_del;
  36280         tr_hw_call[unit].ipmc_get_by_idx   = _bcm_tr_l3_ipmc_get_by_idx;
  36281         tr_hw_call[unit].ing_intf_add      = _bcm_tr_l3_ingress_interface_set;
  36282         tr_hw_call[unit].ing_intf_del      = _bcm_tr_l3_ingress_interface_clr;
  36283         tr_hw_call[unit].ing_intf_get      = _bcm_tr_l3_ingress_interface_get;
  36284         tr_hw_call[unit].ing_intf_update_match = _bcm_xgs3_ing_intf_update_match;
  36285 #endif /* BCM_TRIUMPH_SUPPORT */
  36286 #if defined(BCM_TRIUMPH2_SUPPORT)
  36287         sal_memcpy(&tr2_hw_call[unit], &tr_hw_call[unit], sizeof(_bcm_l3_hw_calls_t));
  36288         tr2_hw_call[unit].ecmp_grp_get  = _bcm_tr2_l3_ecmp_grp_get;
  36289         tr2_hw_call[unit].ecmp_grp_add  = _bcm_tr2_l3_ecmp_grp_add;
  36290         tr2_hw_call[unit].ecmp_grp_del  = _bcm_tr2_l3_ecmp_grp_del;
  36291 #endif /* BCM_TRIUMPH2_SUPPORT */
  36292 #if defined(BCM_TRIDENT_SUPPORT)
  36293         sal_memcpy(&td_hw_call[unit], &tr_hw_call[unit], sizeof(_bcm_l3_hw_calls_t));
  36294         td_hw_call[unit].ecmp_grp_get  = _bcm_td_l3_ecmp_grp_get;
  36295         td_hw_call[unit].ecmp_grp_add  = _bcm_td_l3_ecmp_grp_add;
  36296         td_hw_call[unit].ecmp_grp_del  = _bcm_td_l3_ecmp_grp_del;
  36297 #endif /* BCM_TRIDENT_SUPPORT */
  36298 #if defined(BCM_TRIDENT2_SUPPORT)
  36299         sal_memcpy(&td2_hw_call[unit], &td_hw_call[unit], sizeof(_bcm_l3_hw_calls_t));
  36300         td2_hw_call[unit].l3_add       = _bcm_td2_l3_add;
  36301         td2_hw_call[unit].l3_get       = _bcm_td2_l3_get;
  36302         td2_hw_call[unit].l3_del       = _bcm_td2_l3_del;
  36303         td2_hw_call[unit].l3_traverse  = _bcm_td2_l3_traverse;
  36304         td2_hw_call[unit].l3_del_match = _bcm_td2_l3_del_match;
  36305         td2_hw_call[unit].l3_get_by_idx = _bcm_td2_l3_get_by_idx;
  36306 
  36307         td2_hw_call[unit].lpm_get       = _bcm_l3_lpm_get;
  36308         td2_hw_call[unit].lpm_add       = _bcm_l3_lpm_add;
  36309         td2_hw_call[unit].lpm_del       = _bcm_l3_lpm_del;
  36310         td2_hw_call[unit].lpm_update_match  = _bcm_l3_lpm_update_match;
  36311 
  36312 #ifdef ALPM_ENABLE
  36313         /* If ALPM is enabled */
  36314         if (soc_feature(unit, soc_feature_alpm) &&
  36315             soc_property_get(unit, spn_L3_ALPM_ENABLE, 0)) {
  36316 #if defined(BCM_TOMAHAWK_SUPPORT)
  36317             if (soc_feature(unit, soc_feature_alpm2)) {
  36318                 if (SOC_IS_TOMAHAWK3(unit)) {
  36319                     td2_hw_call[unit].lpm_add       = bcm_th3_alpm_add;
  36320                     td2_hw_call[unit].lpm_get       = bcm_th3_alpm_get;
  36321                     td2_hw_call[unit].lpm_del       = bcm_th3_alpm_del;
  36322                     td2_hw_call[unit].lpm_update_match =
  36323                                              bcm_th3_alpm_update_match;
  36324                 } else {
  36325                 td2_hw_call[unit].lpm_add       = bcm_th_alpm_add;
  36326                 td2_hw_call[unit].lpm_get       = bcm_th_alpm_get;
  36327                 td2_hw_call[unit].lpm_del       = bcm_th_alpm_del;
  36328                     td2_hw_call[unit].lpm_update_match =
  36329                                              bcm_th_alpm_update_match;
  36330                 }
  36331             } else
  36332 #endif
  36333             {
  36334                 td2_hw_call[unit].lpm_add       = _bcm_td2_alpm_add;
  36335                 td2_hw_call[unit].lpm_get       = _bcm_td2_alpm_get;
  36336                 td2_hw_call[unit].lpm_del       = _bcm_td2_alpm_del;
  36337                 if (SOC_IS_TRIDENT2(unit) || SOC_IS_TRIDENT2PLUS(unit)) {
  36338                     td2_hw_call[unit].lpm_update_match  = _bcm_td2_alpm_update_match;
  36339                 } else {
  36340 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT)
  36341                     td2_hw_call[unit].lpm_update_match  = _bcm_th_alpm_update_match;
  36342 #endif
  36343                 }
  36344             }
  36345         }
  36346 #endif
  36347 
  36348         td2_hw_call[unit].ipmc_get     = _bcm_td2_l3_ipmc_get;
  36349         td2_hw_call[unit].ipmc_add     = _bcm_td2_l3_ipmc_add;
  36350         td2_hw_call[unit].ipmc_del     = _bcm_td2_l3_ipmc_del;
  36351         td2_hw_call[unit].ipmc_get_by_idx   = _bcm_td2_l3_ipmc_get_by_idx;
  36352 
  36353         td2_hw_call[unit].proxy_nh_add = _bcm_td2_proxy_nh_add;
  36354         td2_hw_call[unit].proxy_nh_get = _bcm_td2_proxy_nh_get;
  36355 
  36356 #endif /* BCM_TRIDENT2_SUPPORT */
  36357 #if defined(BCM_TRIUMPH3_SUPPORT)
  36358         sal_memcpy(&tr3_hw_call[unit], &td_hw_call[unit], sizeof(_bcm_l3_hw_calls_t));
  36359         tr3_hw_call[unit].l3_add       = _bcm_tr3_l3_add;
  36360         tr3_hw_call[unit].l3_get       = _bcm_tr3_l3_get;
  36361         tr3_hw_call[unit].l3_del       = _bcm_tr3_l3_del;
  36362         tr3_hw_call[unit].l3_traverse  = _bcm_tr3_l3_traverse;
  36363         tr3_hw_call[unit].l3_del_match = _bcm_tr3_l3_del_match;
  36364         tr3_hw_call[unit].l3_get_by_idx = _bcm_tr3_l3_get_by_idx;
  36365         tr3_hw_call[unit].ipmc_get     = _bcm_tr3_l3_ipmc_get;
  36366         tr3_hw_call[unit].ipmc_add     = _bcm_tr3_l3_ipmc_add;
  36367         tr3_hw_call[unit].ipmc_del     = _bcm_tr3_l3_ipmc_del;
  36368         tr3_hw_call[unit].ecmp_grp_get  = _bcm_tr3_l3_ecmp_grp_get;
  36369         tr3_hw_call[unit].ecmp_grp_add  = _bcm_tr3_l3_ecmp_grp_add;
  36370         tr3_hw_call[unit].ecmp_grp_del  = _bcm_tr3_l3_ecmp_grp_del;
  36371         tr3_hw_call[unit].lpm_get       = _bcm_tr3_l3_lpm_get;
  36372         tr3_hw_call[unit].lpm_add       = _bcm_tr3_l3_lpm_add;
  36373         tr3_hw_call[unit].lpm_del       = _bcm_tr3_l3_lpm_del;
  36374         tr3_hw_call[unit].lpm_update_match  = _bcm_tr3_l3_lpm_update_match;
  36375         tr3_hw_call[unit].ipmc_get_by_idx   = _bcm_tr3_l3_ipmc_get_by_idx;
  36376         tr3_hw_call[unit].nh_update_match   = _bcm_tr3_nh_update_match;
  36377 #endif /* BCM_TRIUMPH3_SUPPORT */
  36378 #if defined(BCM_KATANA2_SUPPORT)
  36379         sal_memcpy(&kt2_hw_call[unit], &td_hw_call[unit], sizeof(_bcm_l3_hw_calls_t));
  36380         kt2_hw_call[unit].lpm_get           = _bcm_kt2_l3_lpm_get;
  36381         kt2_hw_call[unit].lpm_add           = _bcm_kt2_l3_lpm_add;
  36382         kt2_hw_call[unit].lpm_del           = _bcm_kt2_l3_lpm_del;
  36383         kt2_hw_call[unit].lpm_update_match  = _bcm_kt2_l3_lpm_update_match;
  36384 #endif /* BCM_KATANA2_SUPPORT */
  36385         /* Interface table common fields. */
  36386         fb_l3_intf_fields.vlan_id    = VIDf;
  36387         fb_l3_intf_fields.mac_addr   = MAC_ADDRESSf;
  36388         fb_l3_intf_fields.ttl        = TTL_THRESHOLDf;
  36389         fb_l3_intf_fields.tnl_id     = TUNNEL_INDEXf;
  36390         fb_l3_intf_fields.l2_switch  = L2_SWITCHf;
  36391 #if defined(BCM_KATANA2_SUPPORT)
  36392         fb_l3_intf_fields.class_id   = CLASS_IDf;
  36393 #endif /* BCM_KATANA2_SUPPORT */
  36394 
  36395         /* Next hop table common fields. */
  36396         fb_nh_fields.mac_addr        = MAC_ADDRESSf;
  36397         fb_nh_fields.module          = MODULE_IDf;
  36398         fb_nh_fields.port_tgid       = PORT_TGIDf;
  36399         fb_nh_fields.ifindex         = INTF_NUMf;
  36400 #if defined(BCM_TRIDENT3_SUPPORT)
  36401         fb_nh_fields.dest            = DESTINATIONf;
  36402 #endif
  36403         /* L3 ipv4 table common fields. */
  36404 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \
  36405     defined(BCM_TRX_SUPPORT)
  36406         fb_l3_v4_fields.vrf          = VRF_IDf;
  36407 #else /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */
  36408         fb_l3_v4_fields.vrf          = INVALIDf;
  36409 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_TRX_SUPPORT */
  36410         fb_l3_v4_fields.hit          = HITf;
  36411         fb_l3_v4_fields.rpe          = RPEf;
  36412         fb_l3_v4_fields.dst_discard  = DST_DISCARDf;
  36413         fb_l3_v4_fields.priority     = PRIf;
  36414         fb_l3_v4_fields.nh_idx       = NEXT_HOP_INDEXf;
  36415 #if defined(BCM_TRIDENT3_SUPPORT)
  36416         if (SOC_IS_TRIDENT3X(unit)) {
  36417             fb_l3_v4_fields.valid    = BASE_VALIDf;
  36418         } else
  36419 #endif
  36420         {
  36421         fb_l3_v4_fields.valid        = VALIDf;
  36422         }
  36423         fb_l3_v4_fields.l3mc_index   = L3MC_INDEXf;
  36424         fb_l3_v4_fields.v6_entry     = V6f;
  36425         fb_l3_v4_fields.ipmc_entry   = IPMCf;
  36426         fb_l3_v4_fields.vlan_id      = VLAN_IDf;
  36427 #if defined(BCM_TRX_SUPPORT)
  36428         fb_l3_v4_fields.class_id     = CLASS_IDf;
  36429 #endif /* BCM_TRX_SUPPORT */
  36430 
  36431         /* L3 ipv6 table common fields. */
  36432 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \
  36433     defined(BCM_SCORPION_SUPPORT)
  36434         fb_l3_v6_fields.vrf          = VRF_ID_0f;
  36435 #else /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_SCORPION_SUPPORT*/
  36436         fb_l3_v6_fields.vrf          = INVALIDf;
  36437 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT || BCM_SCORPION_SUPPORT*/
  36438         fb_l3_v6_fields.hit          = HIT_0f;
  36439         fb_l3_v6_fields.rpe          = RPE_0f;
  36440         fb_l3_v6_fields.dst_discard  = DST_DISCARD_0f;
  36441         fb_l3_v6_fields.priority     = PRI_0f;
  36442         fb_l3_v6_fields.nh_idx       = NEXT_HOP_INDEX_0f;
  36443 #if defined(BCM_TRX_SUPPORT)
  36444         if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) {
  36445             fb_l3_v6_fields.valid = BASE_VALID_0f;
  36446         } else 
  36447 #endif
  36448         {
  36449             fb_l3_v6_fields.valid = VALID_0f;
  36450         }
  36451         fb_l3_v6_fields.l3mc_index   = L3MC_INDEX_0f;
  36452         fb_l3_v6_fields.v6_entry     = V6_0f;
  36453         fb_l3_v6_fields.ipmc_entry   = IPMC_0f;
  36454         fb_l3_v6_fields.vlan_id      = VLAN_ID_0f;
  36455 #if defined(BCM_SCORPION_SUPPORT)
  36456         fb_l3_v6_fields.class_id     = CLASS_ID_0f;
  36457 #endif /* BCM_SCORPION_SUPPORT */
  36458 
  36459 #endif /* BCM_FIREBOLT_SUPPORT */
  36460         /* Next hop table common fields. */
  36461 #ifdef BCM_TRX_SUPPORT
  36462         trx_nh_fields.mac_addr        = MAC_ADDRESSf;
  36463         trx_nh_fields.module          = MODULE_IDf;
  36464         trx_nh_fields.port_tgid       = PORT_NUMf;
  36465         trx_nh_fields.ifindex         = INTF_NUMf;
  36466 #ifdef BCM_TRIDENT3_SUPPORT
  36467         trx_nh_fields.dest            = DESTINATIONf;
  36468 #endif
  36469 #endif /* BCM_TRX_SUPPORT */
  36470 #if defined(BCM_TRIDENT3_SUPPORT)
  36471         if (SOC_IS_TRIDENT3X(unit)) {
  36472             trx_nh_fields.dest            = DESTINATIONf;
  36473             trx_nh_fields.mac_addr        = L3__MAC_ADDRESSf;
  36474             trx_nh_fields.ifindex         = L3__INTF_NUMf;
  36475         }
  36476 #endif
  36477 
  36478 #if defined(BCM_TRIUMPH_SUPPORT)
  36479         /* L3 ipv6 table fields. */
  36480         tr_l3_v6_fields.vrf          = VRF_IDf;
  36481         tr_l3_v6_fields.hit          = HIT_0f;
  36482         tr_l3_v6_fields.rpe          = RPEf;
  36483         tr_l3_v6_fields.dst_discard  = DST_DISCARDf;
  36484         tr_l3_v6_fields.priority     = PRIf;
  36485         tr_l3_v6_fields.nh_idx       = NEXT_HOP_INDEXf;
  36486         tr_l3_v6_fields.valid        = VALID_0f;
  36487         tr_l3_v6_fields.l3mc_index   = INVALIDf;
  36488         tr_l3_v6_fields.v6_entry     = V6_0f;
  36489         tr_l3_v6_fields.ipmc_entry   = IPMC_0f;
  36490         tr_l3_v6_fields.vlan_id      = INVALIDf;
  36491         tr_l3_v6_fields.class_id     = CLASS_IDf;
  36492 #endif /* BCM_TRIUMPH_SUPPORT */
  36493 
  36494 #if defined(BCM_TRIUMPH3_SUPPORT)
  36495         /* v4 */
  36496         tr3_l3_v4_fields.vrf          = IPV4UC__VRF_IDf;
  36497         tr3_l3_v4_fields.rpe          = IPV4UC__RPEf;
  36498         tr3_l3_v4_fields.dst_discard  = IPV4UC__DST_DISCARDf;
  36499         tr3_l3_v4_fields.class_id     = IPV4UC__CLASS_IDf;
  36500         tr3_l3_v4_fields.priority     = IPV4UC__PRIf;
  36501         tr3_l3_v4_fields.nh_idx       = IPV4UC__NEXT_HOP_INDEXf;
  36502         tr3_l3_v4_fields.hit          = HIT_1f;
  36503         tr3_l3_v4_fields.valid        = VALIDf;
  36504         tr3_l3_v4_fields.ip4          = IPV4UC__IP_ADDRf;
  36505         tr3_l3_v4_fields.key_type     = KEY_TYPEf;
  36506         tr3_l3_v4_fields.local_addr   = IPV4UC__LOCAL_ADDRESSf;
  36507         /* v4_2 */
  36508         tr3_l3_v4_2_fields.vrf          = IPV4UC__VRF_IDf;
  36509         tr3_l3_v4_2_fields.rpe          = IPV4UC__RPEf;
  36510         tr3_l3_v4_2_fields.dst_discard  = IPV4UC__DST_DISCARDf;
  36511         tr3_l3_v4_2_fields.class_id     = IPV4UC__CLASS_IDf;
  36512         tr3_l3_v4_2_fields.priority     = IPV4UC__PRIf;
  36513         tr3_l3_v4_2_fields.l3_intf      = IPV4UC__L3_INTF_NUMf;
  36514         tr3_l3_v4_2_fields.mac_addr     = IPV4UC__MAC_ADDRf;
  36515         tr3_l3_v4_2_fields.hit          = HIT_1f;
  36516         tr3_l3_v4_2_fields.valid        = VALID_0f;
  36517         tr3_l3_v4_2_fields.ip4          = IPV4UC__IP_ADDRf;
  36518         tr3_l3_v4_2_fields.key_type     = KEY_TYPE_0f;
  36519         tr3_l3_v4_2_fields.l3_oif       = IPV4UC__L3_OIFf;
  36520         tr3_l3_v4_2_fields.glp          = IPV4UC__GLPf;
  36521         tr3_l3_v4_2_fields.local_addr   = IPV4UC__LOCAL_ADDRESSf;
  36522         /* v6 */
  36523         tr3_l3_v6_fields.vrf            = IPV6UC__VRF_IDf;
  36524         tr3_l3_v6_fields.rpe            = IPV6UC__RPEf;
  36525         tr3_l3_v6_fields.dst_discard    = IPV6UC__DST_DISCARDf;
  36526         tr3_l3_v6_fields.class_id       = IPV6UC__CLASS_IDf;
  36527         tr3_l3_v6_fields.priority       = IPV6UC__PRIf;
  36528         tr3_l3_v6_fields.nh_idx         = IPV6UC__NEXT_HOP_INDEXf;
  36529         tr3_l3_v6_fields.mac_addr       = IPV6UC__MAC_ADDRf;
  36530         tr3_l3_v6_fields.hit            = HIT_1f;
  36531         tr3_l3_v6_fields.valid          = VALID_0f;
  36532         tr3_l3_v6_fields.key_type       = KEY_TYPE_0f;
  36533         tr3_l3_v6_fields.local_addr     = IPV6UC__LOCAL_ADDRESSf;
  36534         /* v6_4 */
  36535         tr3_l3_v6_4_fields.vrf          = IPV6UC__VRF_IDf;
  36536         tr3_l3_v6_4_fields.rpe          = IPV6UC__RPEf;
  36537         tr3_l3_v6_4_fields.l3_intf      = IPV6UC__L3_INTF_NUMf;
  36538         tr3_l3_v6_4_fields.mac_addr     = IPV6UC__MAC_ADDRf;
  36539         tr3_l3_v6_4_fields.dst_discard  = IPV6UC__DST_DISCARDf;
  36540         tr3_l3_v6_4_fields.class_id     = IPV6UC__CLASS_IDf;
  36541         tr3_l3_v6_4_fields.priority     = IPV6UC__PRIf;
  36542         tr3_l3_v6_4_fields.hit          = HIT_1f;
  36543         tr3_l3_v6_4_fields.valid        = VALID_0f;
  36544         tr3_l3_v6_4_fields.key_type     = KEY_TYPE_0f;
  36545         tr3_l3_v6_4_fields.l3_oif       = IPV6UC__L3_OIFf;
  36546         tr3_l3_v6_4_fields.glp          = IPV6UC__GLPf;
  36547         tr3_l3_v6_4_fields.local_addr   = IPV6UC__LOCAL_ADDRESSf;
  36548         /* v4_esm */
  36549         tr3_l3_v4esm_fields.vrf          = VRF_IDf;
  36550         tr3_l3_v4esm_fields.rpe          = RPEf;
  36551         tr3_l3_v4esm_fields.dst_discard  = DST_DISCARDf;
  36552         tr3_l3_v4esm_fields.class_id     = CLASS_IDf;
  36553         tr3_l3_v4esm_fields.priority     = PRIf;
  36554         tr3_l3_v4esm_fields.nh_idx       = NEXT_HOP_INDEXf;
  36555         tr3_l3_v4esm_fields.hit          = SRC_HITf;
  36556         tr3_l3_v4esm_fields.ip4          = IP_ADDRf;
  36557         tr3_l3_v4esm_fields.local_addr   = LOCAL_ADDRESSf;
  36558         /* v4_esm_wide */
  36559         tr3_l3_v4esm_w_fields.vrf          = VRF_IDf;
  36560         tr3_l3_v4esm_w_fields.rpe          = RPEf;
  36561         tr3_l3_v4esm_w_fields.dst_discard  = DST_DISCARDf;
  36562         tr3_l3_v4esm_w_fields.class_id     = CLASS_IDf;
  36563         tr3_l3_v4esm_w_fields.priority     = PRIf;
  36564         tr3_l3_v4esm_w_fields.l3_intf      = L3_INTF_NUMf;
  36565         tr3_l3_v4esm_w_fields.mac_addr     = MAC_ADDRf;
  36566         tr3_l3_v4esm_w_fields.hit          = SRC_HITf;
  36567         tr3_l3_v4esm_w_fields.ip4          = IP_ADDRf;
  36568         tr3_l3_v4esm_w_fields.l3_oif       = L3_OIFf;
  36569         tr3_l3_v4esm_w_fields.glp          = GLPf;
  36570         tr3_l3_v4esm_w_fields.local_addr   = LOCAL_ADDRESSf;
  36571         /* v6_esm */
  36572         tr3_l3_v6esm_fields.vrf            = VRF_IDf;
  36573         tr3_l3_v6esm_fields.rpe            = RPEf;
  36574         tr3_l3_v6esm_fields.dst_discard    = DST_DISCARDf;
  36575         tr3_l3_v6esm_fields.class_id       = CLASS_IDf;
  36576         tr3_l3_v6esm_fields.priority       = PRIf;
  36577         tr3_l3_v6esm_fields.nh_idx         = NEXT_HOP_INDEXf;
  36578         tr3_l3_v6esm_fields.hit            = SRC_HITf;
  36579         tr3_l3_v6esm_fields.local_addr     = LOCAL_ADDRESSf;
  36580         /* v6_esm_wide */
  36581         tr3_l3_v6esm_w_fields.vrf          = VRF_IDf;
  36582         tr3_l3_v6esm_w_fields.rpe          = RPEf;
  36583         tr3_l3_v6esm_w_fields.l3_intf      = L3_INTF_NUMf;
  36584         tr3_l3_v6esm_w_fields.mac_addr     = MAC_ADDRf;
  36585         tr3_l3_v6esm_w_fields.dst_discard  = DST_DISCARDf;
  36586         tr3_l3_v6esm_w_fields.class_id     = CLASS_IDf;
  36587         tr3_l3_v6esm_w_fields.priority     = PRIf;
  36588         tr3_l3_v6esm_w_fields.hit          = SRC_HITf;
  36589         tr3_l3_v6esm_w_fields.l3_oif       = L3_OIFf;
  36590         tr3_l3_v6esm_w_fields.glp          = GLPf;
  36591         tr3_l3_v6esm_w_fields.local_addr   = LOCAL_ADDRESSf;
  36592         /* intf fields */
  36593         tr3_l3_intf_fields.vlan_id    = VIDf;
  36594         tr3_l3_intf_fields.mac_addr   = MAC_ADDRESSf;
  36595         tr3_l3_intf_fields.ttl        = TTL_THRESHOLDf;
  36596         tr3_l3_intf_fields.tnl_id     = TUNNEL_INDEXf;
  36597         tr3_l3_intf_fields.l2_switch  = L2_SWITCHf;
  36598         tr3_l3_intf_fields.class_id   = CLASS_IDf;
  36599 
  36600 #endif /* BCM_TRIUMPH3_SUPPORT */
  36601 #if defined(BCM_TRIDENT2_SUPPORT)
  36602         /* v4 */
  36603         td2_l3_v4_fields.vrf                      = IPV4UC__VRF_IDf;
  36604         td2_l3_v4_fields.rpe                      = IPV4UC__RPEf;
  36605         td2_l3_v4_fields.dst_discard              = IPV4UC__DST_DISCARDf;
  36606         td2_l3_v4_fields.class_id                 = IPV4UC__CLASS_IDf;
  36607         td2_l3_v4_fields.priority                 = IPV4UC__PRIf;
  36608         /* td2_l3_v4_fields.mac_addr              = IPV4UC__MAC_ADDRf; */
  36609         td2_l3_v4_fields.nh_idx                   = IPV4UC__NEXT_HOP_INDEXf;
  36610         td2_l3_v4_fields.hit                      = HITf;
  36611         td2_l3_v4_fields.valid                    = VALIDf;
  36612         td2_l3_v4_fields.ip4                      = IPV4UC__IP_ADDRf;
  36613         td2_l3_v4_fields.key_type                 = KEY_TYPEf;
  36614         td2_l3_v4_fields.local_addr               = IPV4UC__LOCAL_ADDRESSf;
  36615 #ifdef BCM_MONTEREY_SUPPORT
  36616         td2_l3_v4_fields.roe_decap                = IPV4UC__ROE_DECAPf;
  36617 #endif
  36618         /* v4_2 */
  36619         td2_l3_v4_2_fields.vrf                    = IPV4UC_EXT__VRF_IDf;
  36620         td2_l3_v4_2_fields.rpe                    = RPEf;
  36621         td2_l3_v4_2_fields.dst_discard            = IPV4UC_EXT__DST_DISCARDf;
  36622         td2_l3_v4_2_fields.class_id               = IPV4UC_EXT__CLASS_IDf;
  36623         td2_l3_v4_2_fields.priority               = IPV4UC_EXT__PRIf;
  36624         td2_l3_v4_2_fields.l3_intf                = IPV4UC_EXT__L3_INTF_NUMf;
  36625         td2_l3_v4_2_fields.mac_addr               = IPV4UC_EXT__MAC_ADDRf;
  36626         td2_l3_v4_2_fields.hit                    = HIT_1f;
  36627         td2_l3_v4_2_fields.valid                  = VALID_0f;
  36628         td2_l3_v4_2_fields.ip4                    = IPV4UC_EXT__IP_ADDRf;
  36629         td2_l3_v4_2_fields.key_type               = KEY_TYPE_0f;
  36630         td2_l3_v4_2_fields.glp                    = IPV4UC_EXT__GLPf;
  36631         td2_l3_v4_2_fields.local_addr             = IPV4UC_EXT__LOCAL_ADDRESSf;
  36632         td2_l3_v4_2_fields.eh_tag_type            = IPV4UC_EXT__EH_TAG_TYPEf;
  36633         td2_l3_v4_2_fields.eh_queue_tag           = IPV4UC_EXT__EH_QUEUE_TAGf;
  36634         td2_l3_v4_2_fields.copy_to_cpu            = IPV4UC_EXT__COPY_TO_CPUf;
  36635 #ifdef BCM_TOMAHAWK_SUPPORT
  36636         td2_l3_v4_2_fields.macda_low              = IPV4UC_EXT__MAC_DA_LOWf;
  36637         td2_l3_v4_2_fields.dst_vif                = IPV4UC_EXT__VNTAG_DST_VIFf;
  36638         td2_l3_v4_2_fields.oui_profile_id         = IPV4UC_EXT__MAC_DA_OUI_PROFILE_IDf;
  36639         td2_l3_v4_2_fields.vntag_etag_profile_id  = IPV4UC_EXT__VNTAG_ETAG_PROFILE_IDf;
  36640 #endif
  36641 #ifdef BCM_TRIDENT3_SUPPORT
  36642         if (SOC_IS_TRIDENT3X(unit)) {
  36643             td2_l3_v4_2_fields.macda_low              = IPV4UC_EXT__MACDA_LSBf;
  36644             td2_l3_v4_2_fields.dst_vif                = IPV4UC_EXT__NIV_DEST_VIFf;
  36645             td2_l3_v4_2_fields.oui_profile_id         = IPV4UC_EXT__MACDA_OUI_PROFILE_INDEXf;
  36646             td2_l3_v4_2_fields.vntag_etag_profile_id  = IPV4UC_EXT__VNTAG_ETAG_PROFILE_IDf;
  36647             td2_l3_v4_2_fields.glp                    = IPV4UC_EXT__DESTINATIONf;
  36648             td2_l3_v4_2_fields.key_type               = KEY_TYPEf;
  36649         }
  36650 #endif
  36651 #ifdef BCM_MONTEREY_SUPPORT
  36652         td2_l3_v4_2_fields.roe_decap              = IPV4MC__ROE_DECAPf;
  36653 #endif
  36654 
  36655 #ifdef BCM_TRIDENT2PLUS_SUPPORT
  36656         td2_l3_v4_2_fields.dest_type              = IPV4UC_EXT__DEST_TYPEf;
  36657         td2_l3_v4_2_fields.destination            = IPV4UC_EXT__DESTINATIONf;
  36658         td2_l3_v4_2_fields.macda_lsb              = IPV4UC_EXT__MACDA_LSBf;
  36659         td2_l3_v4_2_fields.oui_profile_index      = IPV4UC_EXT__MACDA_OUI_PROFILE_INDEXf;
  36660         td2_l3_v4_2_fields.oui_profile_valid      = IPV4UC_EXT__MACDA_OUI_PROFILE_VALIDf;
  36661 #endif
  36662         /* v6 */
  36663         td2_l3_v6_fields.vrf                      = VRF_IDf;
  36664         td2_l3_v6_fields.rpe                      = RPEf;
  36665         td2_l3_v6_fields.dst_discard              = DST_DISCARDf;
  36666         td2_l3_v6_fields.class_id                 = CLASS_IDf;
  36667         td2_l3_v6_fields.priority                 = PRIf;
  36668         td2_l3_v6_fields.nh_idx                   = NEXT_HOP_INDEXf;
  36669         td2_l3_v6_fields.mac_addr                 = MAC_ADDRf;
  36670         td2_l3_v6_fields.hit                      = HIT_1f;
  36671         td2_l3_v6_fields.valid                    = VALID_0f;
  36672         td2_l3_v6_fields.key_type                 = KEY_TYPE_0f;
  36673         td2_l3_v6_fields.local_addr               = LOCAL_ADDRESSf;
  36674 #ifdef BCM_MONTEREY_SUPPORT
  36675         td2_l3_v6_fields.roe_decap                = ROE_DECAPf;
  36676 #endif
  36677         /* v6_4 */
  36678         td2_l3_v6_4_fields.vrf                    = IPV6UC_EXT__VRF_IDf;
  36679         td2_l3_v6_4_fields.rpe                    = IPV6UC_EXT__RPEf;
  36680         td2_l3_v6_4_fields.l3_intf                = IPV6UC_EXT__L3_INTF_NUMf;
  36681         td2_l3_v6_4_fields.mac_addr               = IPV6UC_EXT__MAC_ADDRf;
  36682         td2_l3_v6_4_fields.dst_discard            = IPV6UC_EXT__DST_DISCARDf;
  36683         td2_l3_v6_4_fields.class_id               = IPV6UC_EXT__CLASS_IDf;
  36684         td2_l3_v6_4_fields.priority               = IPV6UC_EXT__PRIf;
  36685         td2_l3_v6_4_fields.hit                    = HIT_1f;
  36686         td2_l3_v6_4_fields.valid                  = VALID_0f;
  36687         td2_l3_v6_4_fields.key_type               = KEY_TYPE_0f;
  36688         td2_l3_v6_4_fields.glp                    = IPV6UC_EXT__GLPf;
  36689         td2_l3_v6_4_fields.local_addr             = IPV6UC_EXT__LOCAL_ADDRESSf;
  36690         td2_l3_v6_4_fields.eh_tag_type            = IPV6UC_EXT__EH_TAG_TYPEf;
  36691         td2_l3_v6_4_fields.eh_queue_tag           = IPV6UC_EXT__EH_QUEUE_TAGf;
  36692         td2_l3_v6_4_fields.copy_to_cpu            = IPV6UC_EXT__COPY_TO_CPUf;
  36693 #ifdef BCM_TOMAHAWK_SUPPORT
  36694         td2_l3_v6_4_fields.macda_low              = IPV6UC_EXT__MAC_DA_LOWf;
  36695         td2_l3_v6_4_fields.dst_vif                = IPV6UC_EXT__VNTAG_DST_VIFf;
  36696         td2_l3_v6_4_fields.oui_profile_id         = IPV6UC_EXT__MAC_DA_OUI_PROFILE_IDf;
  36697         td2_l3_v6_4_fields.vntag_etag_profile_id  = IPV6UC_EXT__VNTAG_ETAG_PROFILE_IDf;
  36698 #endif
  36699 #ifdef BCM_TRIDENT3_SUPPORT
  36700         if (SOC_IS_TRIDENT3X(unit)) {
  36701             td2_l3_v6_4_fields.macda_low              = IPV6UC_EXT__MACDA_LSBf;
  36702             td2_l3_v6_4_fields.dst_vif                = IPV6UC_EXT__NIV_DEST_VIFf;
  36703             td2_l3_v6_4_fields.oui_profile_id         = IPV6UC_EXT__MACDA_OUI_PROFILE_INDEXf;
  36704             td2_l3_v6_4_fields.vntag_etag_profile_id  = IPV6UC_EXT__VNTAG_ETAG_PROFILE_IDf;
  36705             td2_l3_v6_4_fields.glp                    = IPV6UC_EXT__DESTINATIONf;
  36706             td2_l3_v6_4_fields.key_type               = KEY_TYPEf;
  36707         }
  36708 #endif
  36709 #ifdef BCM_MONTEREY_SUPPORT
  36710         td2_l3_v6_4_fields.roe_decap              = IPV6MC__ROE_DECAPf;
  36711 #endif
  36712 
  36713 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
  36714         if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) {
  36715             fb_nh_fields.mac_addr                      = L3__MAC_ADDRESSf;
  36716             fb_nh_fields.ifindex                       = L3__INTF_NUMf;
  36717             td2_l3_v4_fields.valid                     = BASE_VALIDf;
  36718             td2_l3_v4_2_fields.base_valid0             = BASE_VALID_0f;
  36719             td2_l3_v4_2_fields.base_valid1             = BASE_VALID_1f;
  36720             td2_l3_v4_2_fields.valid                   = BASE_VALID_0f;
  36721             td2_l3_v6_fields.valid                     = BASE_VALID_0f;
  36722             td2_l3_v6_fields.base_valid0               = BASE_VALID_0f;
  36723             td2_l3_v6_fields.base_valid1               = BASE_VALID_1f;
  36724             td2_l3_v6_4_fields.valid                   = BASE_VALID_0f;
  36725             td2_l3_v6_fields.base_valid0               = BASE_VALID_0f;
  36726             td2_l3_v6_fields.base_valid1               = BASE_VALID_1f;
  36727         }
  36728 
  36729         if (SOC_IS_TRIDENT3X(unit)) {
  36730             td2_l3_v6_fields.vrf                       = IPV6UC__VRF_IDf;
  36731             td2_l3_v4_2_fields.dest                    = DESTINATIONf;
  36732             td2_l3_v4_fields.dest                      = DESTINATIONf;
  36733             td2_l3_v4_2_fields.dest                    = IPV4UC_EXT__DESTINATIONf;
  36734             td2_l3_v6_fields.dest                      = IPV6UC__DESTINATIONf;
  36735             td2_l3_v6_4_fields.dest                    = IPV6UC_EXT__DESTINATIONf;
  36736             td2_l3_v6_fields.rpe                       = IPV6UC__RPEf;
  36737             td2_l3_v6_fields.local_addr                = IPV6UC__LOCAL_ADDRESSf;
  36738             td2_l3_v6_fields.key_type                  = KEY_TYPEf;
  36739             td2_l3_v6_4_fields.key_type                = KEY_TYPEf;
  36740             td2_l3_v4_2_fields.key_type                = KEY_TYPEf;
  36741             td2_l3_v6_fields.class_id                  = IPV6UC__CLASS_IDf;
  36742             td2_l3_v6_fields.priority                  = IPV6UC__PRIf;
  36743             td2_l3_v4_2_fields.class_id                = IPV4UC_EXT__CLASS_IDf;
  36744             td2_l3_v4_2_fields.priority                = IPV4UC_EXT__PRIf;
  36745             td2_l3_v6_4_fields.class_id                = IPV6UC_EXT__CLASS_IDf;
  36746             td2_l3_v6_4_fields.priority                = IPV6UC_EXT__PRIf;
  36747             td2_l3_v6_fields.dst_discard               = IPV6UC__DST_DISCARDf;
  36748         } else if (SOC_IS_TOMAHAWK3(unit)) {
  36749             td2_l3_v6_fields.vrf                       = IPV6UC__VRF_IDf;
  36750             td2_l3_v6_fields.dest                      = IPV6UC__DESTINATIONf;
  36751             td2_l3_v6_fields.rpe                       = IPV6UC__RPEf;
  36752             td2_l3_v6_fields.local_addr                = IPV6UC__LOCAL_ADDRESSf;
  36753             td2_l3_v6_fields.key_type                  = KEY_TYPEf;
  36754             td2_l3_v6_4_fields.key_type                = KEY_TYPEf;
  36755             td2_l3_v4_2_fields.key_type                = KEY_TYPEf;
  36756             td2_l3_v6_fields.class_id                  = IPV6UC__CLASS_IDf;
  36757             td2_l3_v6_fields.priority                  = IPV6UC__PRIf;
  36758         }
  36759 
  36760 #endif
  36761 #ifdef BCM_TRIDENT2PLUS_SUPPORT
  36762         td2_l3_v6_4_fields.dest_type              = IPV6UC_EXT__DEST_TYPEf;
  36763         td2_l3_v6_4_fields.destination            = IPV6UC_EXT__DESTINATIONf;
  36764         td2_l3_v6_4_fields.macda_lsb              = IPV6UC_EXT__MACDA_LSBf;
  36765         td2_l3_v6_4_fields.oui_profile_index      = IPV6UC_EXT__MACDA_OUI_PROFILE_INDEXf;
  36766         td2_l3_v6_4_fields.oui_profile_valid      = IPV6UC_EXT__MACDA_OUI_PROFILE_VALIDf;
  36767 #endif
  36768         /* intf fields */
  36769         td2_l3_intf_fields.vlan_id    = VIDf;
  36770         td2_l3_intf_fields.mac_addr   = MAC_ADDRESSf;
  36771         td2_l3_intf_fields.ttl        = TTL_THRESHOLDf;
  36772         td2_l3_intf_fields.tnl_id     = TUNNEL_INDEXf;
  36773         td2_l3_intf_fields.l2_switch  = L2_SWITCHf;
  36774         td2_l3_intf_fields.class_id   = CLASS_IDf;
  36775 #endif /* BCM_TRIDENT2_SUPPORT */
  36776 
  36777         hw_call_initialized[unit] = TRUE;
  36778     }
  36779 
  36780 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT
  36781 #if defined(BCM_TRIDENT3_SUPPORT)
  36782     if (soc_feature(unit, soc_feature_l3_ecmp_protected_access)) {
  36783         if (soc_esw_ecmp_protected_enabled(unit)) {
  36784             td2_hw_call[unit].ecmp_grp_get  = bcm_td3x_l3_ecmp_protected_grp_get;
  36785             td2_hw_call[unit].ecmp_grp_add  = bcm_td3x_l3_ecmp_protected_grp_add;
  36786             td2_hw_call[unit].ecmp_grp_del  = bcm_td3x_l3_ecmp_protected_grp_del;
  36787         } else {
  36788             td2_hw_call[unit].ecmp_grp_get  = _bcm_td_l3_ecmp_grp_get;
  36789             td2_hw_call[unit].ecmp_grp_add  = _bcm_td_l3_ecmp_grp_add;
  36790             td2_hw_call[unit].ecmp_grp_del  = _bcm_td_l3_ecmp_grp_del;
  36791         }
  36792     }
  36793 #endif /* BCM_TRIDENT3_SUPPORT */
  36794 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */
  36795 
  36796 #ifdef BCM_FIREBOLT_SUPPORT
  36797     if (SOC_IS_FBX(unit)) {
  36798 #if defined(BCM_RAPTOR_SUPPORT) || defined(BCM_MIRAGE_SUPPORT) || \
  36799     defined(BCM_HAWKEYE_SUPPORT)
  36800     if (soc_feature(unit, soc_feature_fp_based_routing)) {
  36801             BCM_XGS3_L3_HW_CALL(unit)          = &rp_hw_call[unit];
  36802             BCM_XGS3_L3_MEM_FIELDS(unit, intf) = (void *)&fb_l3_intf_fields;
  36803             BCM_XGS3_L3_MEM_FIELDS(unit, nh)   = (void *)&fb_nh_fields;
  36804         } else
  36805 #endif /* BCM_RAPTOR_SUPPORT || BCM_MIRAGE_SUPPORT || BCM_HAWKEYE_SUPPORT */
  36806 
  36807 #ifdef BCM_TRX_SUPPORT
  36808             if (SOC_IS_TRX(unit)) {
  36809 #ifdef BCM_TRIUMPH2_SUPPORT
  36810                 if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) ||
  36811                     SOC_IS_VALKYRIE2(unit)){
  36812                       BCM_XGS3_L3_HW_CALL(unit)          = &tr2_hw_call[unit];
  36813                       BCM_XGS3_L3_MEM_FIELDS(unit, v6)   = (void *)&tr_l3_v6_fields;
  36814                 } else
  36815 #endif /* BCM_TRIUMPH2_SUPPORT */
  36816 #ifdef BCM_TRIDENT_SUPPORT
  36817                 if (SOC_IS_TRIDENT(unit) || SOC_IS_KATANA(unit)) {
  36818                       BCM_XGS3_L3_HW_CALL(unit)          = &td_hw_call[unit];
  36819                       BCM_XGS3_L3_MEM_FIELDS(unit, v6)   = (void *)&tr_l3_v6_fields;
  36820                 } else
  36821 #endif
  36822 #ifdef BCM_KATANA2_SUPPORT
  36823                 if (SOC_IS_KATANA2(unit)) {
  36824                       BCM_XGS3_L3_HW_CALL(unit)          = &kt2_hw_call[unit];
  36825                       BCM_XGS3_L3_MEM_FIELDS(unit, v6)   = (void *)&tr_l3_v6_fields;
  36826                 } else
  36827 #endif
  36828 #ifdef BCM_TRIUMPH_SUPPORT
  36829                 if (SOC_IS_TR_VL(unit)) {
  36830                     BCM_XGS3_L3_HW_CALL(unit)          = &tr_hw_call[unit];
  36831                     BCM_XGS3_L3_MEM_FIELDS(unit, v6)   = (void *)&tr_l3_v6_fields;
  36832                 } else
  36833 #endif /* BCM_TRIUMPH_SUPPORT */
  36834                 {
  36835                     BCM_XGS3_L3_HW_CALL(unit)          = &fb_hw_call[unit];
  36836                     BCM_XGS3_L3_MEM_FIELDS(unit, v6)   = (void *)&fb_l3_v6_fields;
  36837                 }
  36838                 BCM_XGS3_L3_MEM_FIELDS(unit, intf) = (void *)&fb_l3_intf_fields;
  36839                 BCM_XGS3_L3_MEM_FIELDS(unit, v4)   = (void *)&fb_l3_v4_fields;
  36840                 BCM_XGS3_L3_MEM_FIELDS(unit, ipmc_v4) = (void *)&fb_l3_v4_fields;
  36841                 BCM_XGS3_L3_MEM_FIELDS(unit, ipmc_v6) = (void *)&fb_l3_v6_fields;
  36842                 BCM_XGS3_L3_MEM_FIELDS(unit, nh)   = (void *)&trx_nh_fields;
  36843 #ifdef BCM_TRIUMPH3_SUPPORT
  36844                 if (SOC_IS_TRIUMPH3(unit)) {
  36845                     BCM_XGS3_L3_HW_CALL(unit) = &tr3_hw_call[unit];
  36846                     BCM_XGS3_L3_MEM_FIELDS(unit, v4)   = (void *)&tr3_l3_v4_fields;
  36847                     BCM_XGS3_L3_MEM_FIELDS(unit, v4_2) = (void *)&tr3_l3_v4_2_fields;
  36848                     BCM_XGS3_L3_MEM_FIELDS(unit, v6)   = (void *)&tr3_l3_v6_fields;
  36849                     BCM_XGS3_L3_MEM_FIELDS(unit, v6_4) = (void *)&tr3_l3_v6_4_fields;
  36850                     BCM_XGS3_L3_MEM_FIELDS(unit, intf) = (void *)&tr3_l3_intf_fields;
  36851                     if (soc_feature(unit, soc_feature_esm_support)) {
  36852                         BCM_XGS3_L3_MEM_FIELDS(unit, v4_esm)      =
  36853                                                    (void *)&tr3_l3_v4esm_fields;
  36854                         BCM_XGS3_L3_MEM_FIELDS(unit, v4_esm_wide) =
  36855                                                  (void *)&tr3_l3_v4esm_w_fields;
  36856                         BCM_XGS3_L3_MEM_FIELDS(unit, v6_esm)      =
  36857                                                    (void *)&tr3_l3_v6esm_fields;
  36858                         BCM_XGS3_L3_MEM_FIELDS(unit, v6_esm_wide) =
  36859                                                  (void *)&tr3_l3_v6esm_w_fields;
  36860                     }
  36861                 }
  36862 #endif
  36863 #ifdef BCM_TRIDENT2_SUPPORT
  36864                 if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) || (SOC_IS_TRIDENT3X(unit))) {
  36865                     BCM_XGS3_L3_HW_CALL(unit) = &td2_hw_call[unit];
  36866                     BCM_XGS3_L3_MEM_FIELDS(unit, v4)   = (void *)&td2_l3_v4_fields;
  36867                     BCM_XGS3_L3_MEM_FIELDS(unit, v4_2) = (void *)&td2_l3_v4_2_fields;
  36868                     BCM_XGS3_L3_MEM_FIELDS(unit, v6)   = (void *)&td2_l3_v6_fields;
  36869                     BCM_XGS3_L3_MEM_FIELDS(unit, v6_4) = (void *)&td2_l3_v6_4_fields;
  36870                     BCM_XGS3_L3_MEM_FIELDS(unit, intf) = (void *)&td2_l3_intf_fields;
  36871                 }
  36872 #endif /* BCM_TRIDENT2_SUPPORT */
  36873             }  else
  36874 #endif /* BCM_TRX_SUPPORT */
  36875             {
  36876                 BCM_XGS3_L3_HW_CALL(unit)          = &fb_hw_call[unit];
  36877                 BCM_XGS3_L3_MEM_FIELDS(unit, nh)   = (void *)&fb_nh_fields;
  36878                 BCM_XGS3_L3_MEM_FIELDS(unit, v6)   = (void *)&fb_l3_v6_fields;
  36879                 BCM_XGS3_L3_MEM_FIELDS(unit, ipmc_v6)   = (void *)&fb_l3_v6_fields;
  36880                 BCM_XGS3_L3_MEM_FIELDS(unit, intf) = (void *)&fb_l3_intf_fields;
  36881                 BCM_XGS3_L3_MEM_FIELDS(unit, v4)   = (void *)&fb_l3_v4_fields;
  36882                 BCM_XGS3_L3_MEM_FIELDS(unit, ipmc_v4)   = (void *)&fb_l3_v4_fields;
  36883             }
  36884     }
  36885 #endif /* BCM_FIREBOLT_SUPPORT */
  36886     return (BCM_E_NONE);
  36887 }
  36888 
  36889 /*
  36890  * Function:
  36891  *      _bcm_xgs3_l3_hw_op_init
  36892  * Purpose:
  36893  *      Initialize L3 hardware operations memories & callbacks.
  36894  * Parameters:
  36895  *      unit - SOC unit number.
  36896  * Returns:
  36897  *      BCM_E_XXX
  36898  */
  36899 STATIC int
  36900 _bcm_xgs3_l3_hw_op_init(int unit)
  36901 {
  36902     /* Identical memories. */
  36903     /* Ecmp table. */
  36904     if (SOC_MEM_IS_VALID(unit, L3_ECMPm)) {
  36905         BCM_XGS3_L3_MEM(unit, ecmp) = L3_ECMPm;
  36906         BCM_XGS3_L3_ENT_SZ(unit, ecmp) =
  36907              BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, ecmp));
  36908     }  else {
  36909         BCM_XGS3_L3_MEM(unit, ecmp) = INVALIDm;
  36910     }
  36911 
  36912     if (soc_feature(unit, soc_feature_l3_no_ecmp)) {
  36913         BCM_XGS3_L3_MEM(unit, ecmp) = INVALIDm;
  36914     }
  36915 
  36916     if (SOC_IS_TRIDENT3X(unit)) {
  36917          nh_entry_type_field[unit] = DATA_TYPEf;
  36918     } else {
  36919          nh_entry_type_field[unit] = ENTRY_TYPEf;
  36920     }
  36921 
  36922     BCM_XGS3_L3_MEM(unit, ing_intf) = INVALIDm;
  36923 
  36924     /* Tunnel terminator table. */
  36925     if (SOC_MEM_IS_VALID(unit, L3_TUNNELm)) {
  36926         BCM_XGS3_L3_MEM(unit, tnl_term) = L3_TUNNELm;
  36927         BCM_XGS3_L3_ENT_SZ(unit, tnl_term) =
  36928                  BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, tnl_term));
  36929     } else if (soc_feature(unit, soc_feature_tunnel_term_hash_table)) {
  36930         BCM_XGS3_L3_MEM(unit, tnl_term) = L3_TUNNEL_DOUBLEm;
  36931         BCM_XGS3_L3_ENT_SZ(unit, tnl_term) =
  36932                  BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, tnl_term));
  36933     } else {
  36934         BCM_XGS3_L3_MEM(unit, tnl_term) = INVALIDm;
  36935     }
  36936 
  36937     /* Chip specific memories. */
  36938 #ifdef BCM_FIREBOLT_SUPPORT
  36939     if (SOC_IS_FBX(unit)) {
  36940         /* L3 interface table. */
  36941         BCM_XGS3_L3_MEM(unit, intf) = EGR_L3_INTFm;
  36942         BCM_XGS3_L3_ENT_SZ(unit, intf) =
  36943                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, intf));
  36944 
  36945 #if defined(BCM_TRIUMPH_SUPPORT)
  36946         /* L3 ingress interface table. */
  36947         if (SOC_MEM_IS_VALID(unit, L3_IIFm)) {
  36948             BCM_XGS3_L3_MEM(unit, ing_intf) = L3_IIFm;
  36949             BCM_XGS3_L3_ENT_SZ(unit, ing_intf) =
  36950                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, ing_intf));
  36951         } else {
  36952                 BCM_XGS3_L3_MEM(unit, ing_intf) = INVALIDm;
  36953         }
  36954 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */
  36955 
  36956         /* L3 ipv4 table. */
  36957         if (SOC_MEM_IS_VALID(unit, L3_ENTRY_IPV4_UNICASTm)) {
  36958             BCM_XGS3_L3_MEM(unit, v4) = L3_ENTRY_IPV4_UNICASTm;
  36959             BCM_XGS3_L3_ENT_SZ(unit, v4) =
  36960                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v4));
  36961         } else {
  36962             BCM_XGS3_L3_MEM(unit, v4) = INVALIDm;
  36963 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
  36964             if (SOC_MEM_IS_VALID(unit, L3_ENTRY_SINGLEm)) {
  36965                 BCM_XGS3_L3_MEM(unit, v4) = L3_ENTRY_SINGLEm;
  36966                 BCM_XGS3_L3_ENT_SZ(unit, v4) =
  36967                     BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v4));
  36968             }
  36969 #endif
  36970 
  36971         }
  36972 
  36973         /* L3 ipv6 table. */
  36974         if (SOC_MEM_IS_VALID(unit, L3_ENTRY_IPV6_UNICASTm)) {
  36975             BCM_XGS3_L3_MEM(unit, v6) = L3_ENTRY_IPV6_UNICASTm;
  36976             BCM_XGS3_L3_ENT_SZ(unit, v6) =
  36977                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6));
  36978         }  else {
  36979             BCM_XGS3_L3_MEM(unit, v6) = INVALIDm;
  36980 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
  36981             if (SOC_MEM_IS_VALID(unit, L3_ENTRY_DOUBLEm)) {
  36982                 BCM_XGS3_L3_MEM(unit, v6) = L3_ENTRY_DOUBLEm;
  36983                 BCM_XGS3_L3_ENT_SZ(unit, v6) =
  36984                     BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6));
  36985             }
  36986 #endif
  36987         }
  36988 
  36989         /* L3 ipv4 ipmc table. */
  36990         if (SOC_MEM_IS_VALID(unit, L3_ENTRY_IPV4_MULTICASTm)) {
  36991             BCM_XGS3_L3_MEM(unit, ipmc_v4) = L3_ENTRY_IPV4_MULTICASTm;
  36992             BCM_XGS3_L3_ENT_SZ(unit, ipmc_v4) =
  36993                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, ipmc_v4));
  36994         }  else {
  36995             BCM_XGS3_L3_MEM(unit, ipmc_v4) = INVALIDm;
  36996 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
  36997             if (SOC_MEM_IS_VALID(unit, L3_ENTRY_DOUBLEm)) {
  36998                 BCM_XGS3_L3_MEM(unit, v6) = L3_ENTRY_DOUBLEm;
  36999                 BCM_XGS3_L3_ENT_SZ(unit, v6) =
  37000                     BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6));
  37001             }
  37002 #endif
  37003         }
  37004 
  37005         /* L3 ipv6 table. */
  37006         if (SOC_MEM_IS_VALID(unit, L3_ENTRY_IPV6_MULTICASTm)) {
  37007             BCM_XGS3_L3_MEM(unit, ipmc_v6) = L3_ENTRY_IPV6_MULTICASTm;
  37008             BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6) =
  37009                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, ipmc_v6));
  37010         }  else {
  37011             BCM_XGS3_L3_MEM(unit, ipmc_v6) = INVALIDm;
  37012 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
  37013             if (SOC_MEM_IS_VALID(unit, L3_ENTRY_QUADm)) {
  37014                 BCM_XGS3_L3_MEM(unit, ipmc_v6) = L3_ENTRY_QUADm;
  37015                 BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6) =
  37016                     BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, ipmc_v6));
  37017             }
  37018 #endif
  37019         }
  37020 
  37021         /* Defip table. */
  37022         if (SOC_MEM_IS_VALID(unit, L3_DEFIPm)) {
  37023             BCM_XGS3_L3_MEM(unit, defip) = L3_DEFIPm;
  37024             BCM_XGS3_L3_ENT_SZ(unit, defip) =
  37025                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, defip));
  37026         } else if (SOC_MEM_IS_VALID(unit, L3_DEFIP_TCAM_LEVEL1m)) {
  37027             BCM_XGS3_L3_MEM(unit, defip) = L3_DEFIP_LEVEL1m;
  37028             BCM_XGS3_L3_ENT_SZ(unit, defip) =
  37029                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, defip));
  37030         }  else {
  37031             BCM_XGS3_L3_MEM(unit, defip) = INVALIDm;
  37032         }
  37033 
  37034 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_TRX_SUPPORT)
  37035         /* IPv6 prefix map table. */
  37036         if (SOC_MEM_IS_VALID(unit, IPV4_IN_IPV6_PREFIX_MATCH_TABLEm)) {
  37037             BCM_XGS3_L3_MEM(unit, v6_prefix_map) =
  37038                 IPV4_IN_IPV6_PREFIX_MATCH_TABLEm;
  37039             BCM_XGS3_L3_ENT_SZ(unit, v6_prefix_map) =
  37040                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6_prefix_map));
  37041         } else if (SOC_MEM_IS_VALID(unit, PARSER1_IPV4_IN_IPV6_PREFIX_MATCH_TABLEm)) {
  37042             BCM_XGS3_L3_MEM(unit, v6_prefix_map) =
  37043                 PARSER1_IPV4_IN_IPV6_PREFIX_MATCH_TABLEm;
  37044             BCM_XGS3_L3_ENT_SZ(unit, v6_prefix_map) =
  37045                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6_prefix_map));
  37046         }  else
  37047 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_TRX_SUPPORT */
  37048         {
  37049             BCM_XGS3_L3_MEM(unit, v6_prefix_map) = INVALIDm;
  37050         }
  37051 
  37052         /* IPv4 Tunnel initiator table. */
  37053         if (SOC_MEM_IS_VALID(unit, EGR_IP_TUNNELm)) {
  37054             BCM_XGS3_L3_MEM(unit, tnl_init_v4) = EGR_IP_TUNNELm;
  37055             BCM_XGS3_L3_ENT_SZ(unit, tnl_init_v4) =
  37056                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, tnl_init_v4));
  37057         }  else {
  37058             BCM_XGS3_L3_MEM(unit, tnl_init_v4) = INVALIDm;
  37059         }
  37060 #if defined(BCM_TRX_SUPPORT)
  37061         /* IPv6 Tunnel initiator table. */
  37062         if (SOC_MEM_IS_VALID(unit, EGR_IP_TUNNEL_IPV6m)) {
  37063             BCM_XGS3_L3_MEM(unit, tnl_init_v6) = EGR_IP_TUNNEL_IPV6m;
  37064             BCM_XGS3_L3_ENT_SZ(unit, tnl_init_v6) =
  37065                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, tnl_init_v6));
  37066         }  else
  37067 #endif /* BCM_TRX_SUPPORT */
  37068         {
  37069             BCM_XGS3_L3_MEM(unit, tnl_init_v6) = INVALIDm;
  37070         }
  37071 
  37072 #if defined(BCM_TRX_SUPPORT)
  37073         /* MPLS Tunnel initiator table. */
  37074         if (SOC_MEM_IS_VALID(unit, EGR_IP_TUNNEL_MPLSm)) {
  37075             if (SOC_IS_TRIDENT3X(unit)) {
  37076                 BCM_XGS3_L3_MEM(unit, tnl_init_mpls) =
  37077                     EGR_IP_TUNNEL_MPLS_DOUBLE_WIDEm;
  37078             } else {
  37079                 BCM_XGS3_L3_MEM(unit, tnl_init_mpls) =
  37080                     EGR_IP_TUNNEL_MPLSm;
  37081             }
  37082             BCM_XGS3_L3_ENT_SZ(unit, tnl_init_mpls) =
  37083                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, tnl_init_mpls));
  37084         }  else
  37085 #endif /* BCM_TRX_SUPPORT */
  37086         {
  37087             BCM_XGS3_L3_MEM(unit, tnl_init_mpls) = INVALIDm;
  37088         }
  37089 
  37090         /* Next hop table. */
  37091         BCM_XGS3_L3_MEM(unit, nh) = ING_L3_NEXT_HOPm;
  37092         BCM_XGS3_L3_ENT_SZ(unit, nh) =
  37093                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, nh));
  37094 
  37095         /* Egress Tunnel DSCP table. */
  37096         if (SOC_IS_TRIDENT3X(unit)) {
  37097             BCM_XGS3_L3_MEM(unit, tnl_dscp) = EGR_ZONE_2_QOS_MAPPING_TABLEm;
  37098         } else {
  37099             BCM_XGS3_L3_MEM(unit, tnl_dscp) = EGR_DSCP_TABLEm;
  37100         }
  37101 
  37102         BCM_XGS3_L3_ENT_SZ(unit, tnl_dscp) =
  37103                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, tnl_dscp));
  37104 #ifdef BCM_TRIUMPH3_SUPPORT
  37105         if (SOC_MEM_IS_VALID(unit, L3_ENTRY_1m) &&
  37106             SOC_MEM_IS_VALID(unit, L3_ENTRY_2m)) {
  37107             BCM_XGS3_L3_MEM(unit, v4) = L3_ENTRY_1m;
  37108             BCM_XGS3_L3_ENT_SZ(unit, v4) =
  37109                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v4));
  37110             BCM_XGS3_L3_MEM(unit, v4_2) = L3_ENTRY_2m;
  37111             BCM_XGS3_L3_ENT_SZ(unit, v4_2) =
  37112                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v4_2));
  37113             BCM_XGS3_L3_MEM(unit, v6) = L3_ENTRY_2m;
  37114             BCM_XGS3_L3_ENT_SZ(unit, v6) =
  37115                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6));
  37116             BCM_XGS3_L3_MEM(unit, v6_4) = L3_ENTRY_4m;
  37117             BCM_XGS3_L3_ENT_SZ(unit, v6_4) =
  37118                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6_4));
  37119             BCM_XGS3_L3_MEM(unit, ipmc_v4) = L3_ENTRY_2m;
  37120             BCM_XGS3_L3_ENT_SZ(unit, ipmc_v4) =
  37121                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, ipmc_v4));
  37122             BCM_XGS3_L3_MEM(unit, ipmc_v6) = L3_ENTRY_4m;
  37123             BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6) =
  37124                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, ipmc_v6));
  37125         } 
  37126 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
  37127         else if (SOC_MEM_IS_VALID(unit, L3_ENTRY_SINGLEm)) {
  37128             BCM_XGS3_L3_MEM(unit, v4) = L3_ENTRY_SINGLEm;
  37129             BCM_XGS3_L3_ENT_SZ(unit, v4) =
  37130                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v4));
  37131             BCM_XGS3_L3_MEM(unit, v4_2) = L3_ENTRY_DOUBLEm;
  37132             BCM_XGS3_L3_ENT_SZ(unit, v4_2) =
  37133                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v4_2));
  37134             BCM_XGS3_L3_MEM(unit, v6) = L3_ENTRY_DOUBLEm;
  37135             BCM_XGS3_L3_ENT_SZ(unit, v6) =
  37136                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6));
  37137             BCM_XGS3_L3_MEM(unit, v6_4) = L3_ENTRY_QUADm;
  37138             BCM_XGS3_L3_ENT_SZ(unit, v6_4) =
  37139                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6_4));
  37140             BCM_XGS3_L3_MEM(unit, ipmc_v4) = L3_ENTRY_DOUBLEm;
  37141             BCM_XGS3_L3_ENT_SZ(unit, ipmc_v4) =
  37142                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, ipmc_v4));
  37143             BCM_XGS3_L3_MEM(unit, ipmc_v6) = L3_ENTRY_QUADm;
  37144             BCM_XGS3_L3_ENT_SZ(unit, ipmc_v6) =
  37145                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, ipmc_v6));
  37146         }
  37147 #endif
  37148 
  37149         if (SOC_MEM_IS_VALID(unit, EXT_IPV4_UCAST_WIDEm) &&
  37150             SOC_MEM_IS_VALID(unit, EXT_IPV6_128_UCAST_WIDEm)) {
  37151             BCM_XGS3_L3_MEM(unit, v4_esm) = EXT_IPV4_UCASTm;
  37152             BCM_XGS3_L3_ENT_SZ(unit, v4_esm) =
  37153                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v4_esm));
  37154             BCM_XGS3_L3_MEM(unit, v4_esm_wide) = EXT_IPV4_UCAST_WIDEm;
  37155             BCM_XGS3_L3_ENT_SZ(unit, v4_esm_wide) =
  37156                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v4_esm_wide));
  37157             BCM_XGS3_L3_MEM(unit, v6_esm) = EXT_IPV6_128_UCASTm;
  37158             BCM_XGS3_L3_ENT_SZ(unit, v6_esm) =
  37159                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6_esm));
  37160             BCM_XGS3_L3_MEM(unit, v6_esm_wide) = EXT_IPV6_128_UCAST_WIDEm;
  37161             BCM_XGS3_L3_ENT_SZ(unit, v6_esm_wide) =
  37162                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6_esm_wide));
  37163         }
  37164 #endif
  37165 #ifdef BCM_TRIDENT2_SUPPORT
  37166         if (SOC_MEM_IS_VALID(unit, L3_ENTRY_IPV4_MULTICASTm)) {
  37167             BCM_XGS3_L3_MEM(unit, v4_2) = L3_ENTRY_IPV4_MULTICASTm;
  37168             BCM_XGS3_L3_ENT_SZ(unit, v4_2) =
  37169                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v4_2));
  37170         }
  37171         if (SOC_MEM_IS_VALID(unit, L3_ENTRY_IPV6_MULTICASTm)) {
  37172             BCM_XGS3_L3_MEM(unit, v6_4) = L3_ENTRY_IPV6_MULTICASTm;
  37173             BCM_XGS3_L3_ENT_SZ(unit, v6_4) =
  37174                 BCM_L3_MEM_ENT_SIZE(unit, BCM_XGS3_L3_MEM(unit, v6_4));
  37175         }
  37176 #endif
  37177 #ifdef BCM_HURRICANE3_SUPPORT
  37178         if (soc_feature(unit, soc_feature_miml_no_l3)) {
  37179             /*
  37180              * Buckhound doesn't support L3 feature but MiML reuses some L3 functions
  37181              * for resource management.
  37182              */
  37183             /* To set all L3 memories as INVALIDm except for intf and nh for MiML usage */
  37184             BCM_XGS3_L3_MEM(unit, ecmp) = INVALIDm;
  37185             BCM_XGS3_L3_MEM(unit, ing_intf) = INVALIDm;
  37186             BCM_XGS3_L3_MEM(unit, tnl_term) = INVALIDm;
  37187             BCM_XGS3_L3_MEM(unit, v4) = INVALIDm;
  37188             BCM_XGS3_L3_MEM(unit, v6) = INVALIDm;
  37189             BCM_XGS3_L3_MEM(unit, ipmc_v4) = INVALIDm;
  37190             BCM_XGS3_L3_MEM(unit, ipmc_v6) = INVALIDm;
  37191             BCM_XGS3_L3_MEM(unit, defip) = INVALIDm;
  37192             BCM_XGS3_L3_MEM(unit, v6_prefix_map) = INVALIDm;
  37193             BCM_XGS3_L3_MEM(unit, tnl_init_v4) = INVALIDm;
  37194             BCM_XGS3_L3_MEM(unit, tnl_init_v6) = INVALIDm;
  37195             BCM_XGS3_L3_MEM(unit, tnl_init_mpls) = INVALIDm;
  37196             BCM_XGS3_L3_MEM(unit, tnl_dscp) = INVALIDm;
  37197         }
  37198 #endif /* BCM_HURRICANE3_SUPPORT */
  37199     }
  37200 #endif /* BCM_FIREBOLT_SUPPORT */
  37201     _bcm_xgs3_l3_hw_call_init(unit);
  37202     return (BCM_E_NONE);
  37203 }
  37204 
  37205 void dump_ecmp_info(int unit)
  37206 {
  37207     _bcm_l3_tbl_t *tbl_ptr;
  37208     _bcm_l3_ecmp_info_t *ptr;
  37209 
  37210      int idx = 0;
  37211      int member_count = 0;
  37212      int rv;
  37213 
  37214      LOG_CLI((BSL_META_U(unit,
  37215                          "Dumping ecmp_info\n")));
  37216      ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_info);
  37217      if (ptr) {
  37218          LOG_CLI((BSL_META_U(unit,
  37219                              "ecmp_max_paths - %d ecmp_inuse - %d\n"),
  37220                   ptr->ecmp_max_paths, ptr->ecmp_inuse));
  37221      }
  37222 
  37223      tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  37224      if (tbl_ptr) {
  37225          LOG_CLI((BSL_META_U(unit,
  37226                              "ECMP GROUP INFO:\n")));
  37227          LOG_CLI((BSL_META_U(unit,
  37228                              "idx_min: %d idx_max: %d idx_maxused: %d\n"),
  37229                   tbl_ptr->idx_min, tbl_ptr->idx_max,
  37230                   tbl_ptr->idx_maxused));
  37231          LOG_CLI((BSL_META_U(unit,
  37232                              "HASH and REFCOUNT for each ECMP GROUP\n")));
  37233 
  37234          for (idx = tbl_ptr->idx_min; idx < tbl_ptr->idx_max; idx++) {
  37235              if (tbl_ptr->ext_arr[idx].ref_count != 0) {
  37236                  LOG_CLI((BSL_META_U(unit,
  37237                                      "[idx: %d ref: %d, hash: %d],"), idx,
  37238                           tbl_ptr->ext_arr[idx].ref_count,
  37239                           tbl_ptr->ext_arr[idx].data_hash));
  37240                  if (idx % 4 == 0)  {
  37241                      LOG_CLI((BSL_META_U(unit,
  37242                                          "\n")));
  37243                  }
  37244              }
  37245          }
  37246     }
  37247 
  37248      LOG_CLI((BSL_META_U(unit,
  37249                          "\nECMP GROUP MEMBER COUNT INFO:\n")));
  37250      for (idx = tbl_ptr->idx_min; idx < tbl_ptr->idx_maxused; idx++) {
  37251          rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, idx, &member_count);
  37252          LOG_CLI((BSL_META_U(unit,
  37253                              "groud id - %d  count - %d rv - %d\n"),
  37254                   idx, member_count, rv));
  37255      }
  37256 
  37257      tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp);
  37258      if (tbl_ptr) {
  37259          LOG_CLI((BSL_META_U(unit,
  37260                              "\nECMP INFO:\n")));
  37261          LOG_CLI((BSL_META_U(unit,
  37262                              "idx_min: %d idx_max: %d idx_maxused: %d\n"),
  37263                   tbl_ptr->idx_min, tbl_ptr->idx_max,
  37264                   tbl_ptr->idx_maxused));
  37265          LOG_CLI((BSL_META_U(unit,
  37266                              "HASH and REFCOUNT for each ECMP \n")));
  37267 
  37268          for (idx = tbl_ptr->idx_min; idx < tbl_ptr->idx_max; idx++) {
  37269              if (tbl_ptr->ext_arr[idx].ref_count != 0) {
  37270                  LOG_CLI((BSL_META_U(unit,
  37271                                      "[idx: %d ref: %d, hash: %d],"), idx,
  37272                           tbl_ptr->ext_arr[idx].ref_count,
  37273                           tbl_ptr->ext_arr[idx].data_hash));
  37274                  if (idx % 4 == 0)  {
  37275                      LOG_CLI((BSL_META_U(unit,
  37276                                          "\n")));
  37277                  }
  37278              }
  37279          }
  37280      }
  37281      LOG_CLI((BSL_META_U(unit,
  37282                          "\n")));
  37283 }
  37284 
  37285 int
  37286 _bcm_xgs3_route_tables_resize(int unit,  int arg)
  37287 {
  37288     int rv = BCM_E_NONE;
  37289 #if defined(BCM_TRIUMPH3_SUPPORT)
  37290     int cache_on = 0;
  37291 #endif
  37292 #ifdef ALPM_ENABLE
  37293 #if defined(BCM_TOMAHAWK_SUPPORT)
  37294     int hitbit_interval = 0;
  37295 #endif
  37296 #endif
  37297     soc_mem_t defip_mem = L3_DEFIPm, defip_pair_mem = L3_DEFIP_PAIR_128m;
  37298 
  37299     if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) {
  37300         defip_mem = L3_DEFIP_LEVEL1m;
  37301         defip_pair_mem = L3_DEFIP_PAIR_LEVEL1m;
  37302     }
  37303 
  37304     if (soc_feature(unit, soc_feature_l3_shared_defip_table)) {
  37305         if (!(SOC_IS_TD2_TT2(unit) || SOC_IS_TRIUMPH3(unit))) {
  37306             return BCM_E_UNAVAIL;
  37307         }
  37308     } else {
  37309         return BCM_E_UNAVAIL;
  37310     }
  37311 
  37312 #ifdef ALPM_ENABLE
  37313 #if defined(BCM_TOMAHAWK_SUPPORT)
  37314     if (soc_property_get(unit, spn_L3_ALPM_ENABLE, 0) &&
  37315         soc_feature(unit, soc_feature_alpm2) && ALPMC(unit) && !ALPM_HIT_SKIP(unit)) {
  37316         hitbit_interval = alpm_dist_hitbit_interval_get(unit);
  37317         if (hitbit_interval) {
  37318             alpm_dist_hitbit_enable_set(unit, 0);
  37319         }
  37320     }
  37321 #endif
  37322 #endif
  37323     /* State changed -> Delete all the routes. */
  37324     if (!(SOC_IS_TRIDENT3X(unit)) || (SOC_IS_TRIDENT3X(unit) &&
  37325         (BCM_XGS3_L3_INITIALIZED(unit)))) {
  37326         BCM_IF_ERROR_RETURN(bcm_xgs3_defip_del_all(unit));
  37327     }
  37328 
  37329     /* Destroy Hash/Avl quick lookup structure. */
  37330     BCM_IF_ERROR_RETURN(bcm_xgs3_l3_fbx_defip_deinit(unit));
  37331 
  37332     /* Lock the DEFIP tables so the SOC TCAM scanning logic doesn't
  37333      * trip up on the URPF reconfiguration.
  37334      */
  37335     soc_mem_lock(unit, defip_mem);
  37336     if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
  37337         if (SOC_MEM_IS_ENABLED(unit, defip_pair_mem)) {
  37338             soc_mem_lock(unit, defip_pair_mem);
  37339         }
  37340     }
  37341 
  37342     /* resize the DEFIP table */
  37343     rv = soc_defip_tables_resize(unit, arg);
  37344     if (BCM_FAILURE(rv)) {
  37345         /* Must release the locks before return. */
  37346         if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
  37347             if (SOC_MEM_IS_ENABLED(unit, defip_pair_mem)) {
  37348                 soc_mem_unlock(unit, defip_pair_mem);
  37349             }
  37350         }
  37351         soc_mem_unlock(unit, defip_mem);
  37352         return rv;
  37353     }
  37354 
  37355     /* reallocate DEFIP table cache memory (cache and vmap) as per
  37356      * calculated new indexes - TD2 it is disabled since cache is
  37357      * not enabled for TD2. It is only enabled for TR3
  37358      */
  37359 #if defined(BCM_TRIUMPH3_SUPPORT)
  37360     if (SOC_IS_TRIUMPH3(unit)) {
  37361         cache_on = 1;
  37362     } else if (SOC_IS_TD2_TT2(unit)) {
  37363         cache_on = soc_mem_cache_get(unit, defip_mem, MEM_BLOCK_ALL);
  37364     }
  37365 
  37366     if (cache_on) {
  37367         if (SOC_MEM_IS_ENABLED(unit, defip_mem)) {
  37368             if (BCM_SUCCESS(rv)) {
  37369                 rv = soc_mem_cache_set(unit, defip_mem, MEM_BLOCK_ALL, TRUE);
  37370             }
  37371         }
  37372         if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
  37373             if (SOC_MEM_IS_ENABLED(unit, defip_pair_mem)) {
  37374                 if (BCM_SUCCESS(rv)) {
  37375                     rv = soc_mem_cache_set(unit, defip_pair_mem,
  37376                                            MEM_BLOCK_ALL, TRUE);
  37377                 }
  37378             }
  37379         }
  37380     }
  37381 #endif
  37382 
  37383 
  37384     /* Clear h/w memory before use */
  37385     if (SOC_MEM_IS_ENABLED(unit, defip_mem)) {
  37386         if (BCM_SUCCESS(rv)) {
  37387             rv = soc_mem_clear(unit, defip_mem, MEM_BLOCK_ALL, 0);
  37388         }
  37389     }
  37390     if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
  37391         if (SOC_MEM_IS_ENABLED(unit, defip_pair_mem)) {
  37392             if (BCM_SUCCESS(rv)) {
  37393                 rv = soc_mem_clear(unit, defip_pair_mem,
  37394                                    MEM_BLOCK_ALL, 0);
  37395                 if (BCM_FAILURE(rv)) {
  37396                     if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
  37397                         if (SOC_MEM_IS_ENABLED(unit, defip_pair_mem)) {
  37398                             soc_mem_unlock(unit, defip_pair_mem);
  37399                         }
  37400                     }
  37401                     soc_mem_unlock(unit, defip_mem);
  37402                     return rv;
  37403                 }
  37404             }
  37405         }
  37406     }
  37407 
  37408     /* Reinit Hash/Avl quick lookup structure. */
  37409     rv = bcm_xgs3_l3_fbx_defip_init(unit);
  37410     if (BCM_FAILURE(rv)) {
  37411         /* Must release the locks before return. */
  37412         if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
  37413             if (SOC_MEM_IS_ENABLED(unit, defip_pair_mem)) {
  37414                 soc_mem_unlock(unit, defip_pair_mem);
  37415             }
  37416         }
  37417         soc_mem_unlock(unit, defip_mem);
  37418         return rv;
  37419     }
  37420 
  37421     /* Now check if urpf is enable */
  37422     if (SOC_URPF_STATUS_GET(unit)) {
  37423         #ifdef BCM_TRIUMPH3_SUPPORT
  37424             if (SOC_IS_TRIUMPH3(unit) &&
  37425                !BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV4_DEFIPm)) {
  37426                 rv = _bcm_tr3_l3_defip_urpf_enable(unit, 1);
  37427             }
  37428         #endif
  37429 
  37430         #ifdef BCM_TRIDENT2_SUPPORT
  37431             if (BCM_SUCCESS(rv) && (SOC_IS_TRIDENT2X(unit) ||
  37432                                     SOC_IS_TOMAHAWKX(unit) ||
  37433                                     SOC_IS_TRIDENT3X(unit))) {
  37434                 /* BCM_SUCCESS test not needed, but likely to avoid
  37435                  * Coverity complaints */
  37436                 rv = _bcm_l3_defip_urpf_enable(unit, 1);
  37437             }
  37438         #endif
  37439 
  37440     }
  37441 
  37442     BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) =
  37443         soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, defip));
  37444 
  37445     /* Must release the locks before return. */
  37446     if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
  37447         if (SOC_MEM_IS_ENABLED(unit, defip_pair_mem)) {
  37448             soc_mem_unlock(unit, defip_pair_mem);
  37449         }
  37450     }
  37451     soc_mem_unlock(unit, defip_mem);
  37452 #ifdef ALPM_ENABLE
  37453 #if defined(BCM_TOMAHAWK_SUPPORT)
  37454     if (soc_property_get(unit, spn_L3_ALPM_ENABLE, 0) &&
  37455         soc_feature(unit, soc_feature_alpm2) && ALPMC(unit) && !ALPM_HIT_SKIP(unit)) {
  37456         if (hitbit_interval) {
  37457             alpm_dist_hitbit_enable_set(unit, hitbit_interval);
  37458         }
  37459     }
  37460 #endif
  37461 #endif
  37462     return rv;
  37463 }
  37464 
  37465 int
  37466 _bcm_fb_lpm_defip_cfg_get(int unit, int ipv6, void *defip_lpm_entry,
  37467                          _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx)
  37468 {
  37469     int idx = 0; /* ipv4 entries iterator.*/
  37470     uint32 lpm_entry[SOC_MAX_MEM_WORDS];
  37471 
  37472     if (lpm_cfg == NULL || defip_lpm_entry == NULL) {
  37473         return BCM_E_PARAM;
  37474     }
  37475     sal_memcpy(&lpm_entry, defip_lpm_entry,
  37476                BCM_XGS3_L3_ENT_SZ(unit, defip));
  37477 
  37478     for (idx = 0; idx < (ipv6 ? 1 : 2); idx++) {
  37479         if (idx) {
  37480             /* Check second part of the entry. */
  37481             soc_fb_lpm_ip4entry1_to_0(unit, (void*)lpm_entry,
  37482                                       (void*)lpm_entry, TRUE);
  37483         }
  37484         /* Parse  the entry. */
  37485         BCM_IF_ERROR_RETURN(
  37486             _bcm_fb_lpm_ent_parse(unit, &lpm_cfg[idx], &nh_ecmp_idx[idx],
  37487                               (uint32 *)lpm_entry, NULL));
  37488         BCM_IF_ERROR_RETURN(
  37489             _bcm_fb_lpm_ent_get_key(unit, &lpm_cfg[idx], (uint32 *)lpm_entry));
  37490     }
  37491     lpm_cfg->defip_index = BCM_XGS3_L3_INVALID_INDEX;
  37492     return SOC_E_NONE;
  37493 }
  37494 
  37495 /*
  37496  * Function:
  37497  *      bcmi_l3_egress_multi_alloc
  37498  * Purpose:
  37499  *      Allocates multiple egress objects.
  37500  * Parameters:
  37501  *      unit              - (IN)SOC unit number.
  37502  *      info              - (IN)Info to allocates egress objects.
  37503  *      base_egress_id    - (OUT) base egress object id.
  37504  * Returns:
  37505  *      BCM_E_XXX
  37506  */
  37507 int
  37508 bcmi_l3_egress_multi_alloc(int unit,
  37509         bcm_l3_egress_multi_info_t info,
  37510         bcm_if_t *base_egress_id)
  37511 {
  37512     int rv = BCM_E_NONE;
  37513     uint32 flags = 0;
  37514     uint32 *nh_multi_count;
  37515     _bcm_l3_tbl_op_t data;        /* Operation data. */
  37516     bcm_l3_egress_t nh_info;
  37517     _bcm_l3_tbl_t *tbl_ptr;                   /* Software table pointer. */
  37518     int backup_min_index;
  37519     ing_l3_next_hop_entry_t ing_nh;
  37520     int i = 0;
  37521     bcm_if_t nh_index = 0;
  37522 
  37523     if ((info.number_of_elements < 1) || 
  37524         (info.number_of_elements > 4)) {
  37525         return BCM_E_PARAM;
  37526     }
  37527     if (base_egress_id == NULL) {
  37528         return BCM_E_PARAM;
  37529     }
  37530 
  37531     if (!(soc_feature(unit, soc_feature_hierarchical_protection))) {
  37532         return BCM_E_UNAVAIL;
  37533     } else {
  37534         /*
  37535          * Currently settingnumber of elements to 4.
  37536          * in future if someone wants to extend this API,
  37537          * then they may have to send some flag/source in
  37538          * info structure and based on that allocate number of
  37539          * elements.
  37540          */
  37541         info.number_of_elements = _BCM_QUAD_WIDE;
  37542     }
  37543 
  37544     if (info.flags & BCM_L3_EGRESS_MULTI_WITH_ID) {
  37545         if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, *base_egress_id)) {
  37546             nh_index = *base_egress_id - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  37547         } else {
  37548             nh_index = *base_egress_id - BCM_XGS3_EGRESS_IDX_MIN(unit);
  37549         }
  37550 
  37551         flags |= _BCM_L3_SHR_WITH_ID;
  37552     }
  37553 
  37554     sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t));
  37555     sal_memset(&nh_info, 0, sizeof(bcm_l3_egress_t));
  37556     data.tbl_ptr =  BCM_XGS3_L3_TBL_PTR(unit, next_hop);
  37557     data.width = info.number_of_elements;
  37558     data.oper_flags = flags | _BCM_L3_SHR_MATCH_DISABLE |
  37559         _BCM_L3_SHR_WRITE_DISABLE;
  37560     data.entry_buffer = (void *)(&(nh_info));
  37561     data.hash_func = _bcm_xgs3_nh_hash_calc;
  37562     data.cmp_func  = _bcm_xgs3_nh_ent_cmp;
  37563     data.add_func  = BCM_XGS3_L3_HWCALL(unit, nh_add);
  37564     if (flags & _BCM_L3_SHR_WITH_ID) {
  37565         data.entry_index = nh_index;
  37566     }
  37567     tbl_ptr = data.tbl_ptr;
  37568     /* Set up the limits for indexes */
  37569     backup_min_index = tbl_ptr->idx_min;
  37570     tbl_ptr->idx_min = 4;
  37571 
  37572 
  37573     rv =  _bcm_xgs3_tbl_add(unit, &data);
  37574     if (rv != BCM_E_NONE) {
  37575         tbl_ptr->idx_min = backup_min_index;
  37576         return rv;
  37577     }
  37578 
  37579     *base_egress_id = data.entry_index + BCM_XGS3_EGRESS_IDX_MIN(unit);
  37580     tbl_ptr->idx_min = backup_min_index;
  37581     /* set up s/w state for 2-level protection */
  37582     if (soc_feature(unit, soc_feature_hierarchical_protection)) {
  37583         nh_multi_count = BCM_XGS3_L3_NH_MULTI_COUNT(unit);
  37584         nh_multi_count[data.entry_index] = _BCM_QUAD_WIDE;
  37585         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, DROPf, 1);
  37586         for (i=0; i<info.number_of_elements; i++) {
  37587             rv = soc_mem_write (unit, ING_L3_NEXT_HOPm,
  37588                             MEM_BLOCK_ALL, data.entry_index + i, &ing_nh);
  37589             if (BCM_FAILURE(rv)) {
  37590                 return rv;
  37591             }
  37592         }
  37593     }
  37594     return BCM_E_NONE;
  37595 }
  37596 
  37597 /*
  37598  * Function:
  37599  *      bcmi_l3_egress_multi_free
  37600  * Purpose:
  37601  *      Frees multiple egress objects.
  37602  * Parameters:
  37603  *      unit              - (IN)SOC unit number.
  37604  *      base_egress_id    - (OUT) base egress object id.
  37605  * Returns:
  37606  *      BCM_E_XXX
  37607  */
  37608 int
  37609 bcmi_l3_egress_multi_free(int unit, bcm_if_t base_egress_id)
  37610 {
  37611 
  37612     _bcm_l3_tbl_op_t data;        /* Operation data. */
  37613     int no_of_elements = 1;       /* by default set it to 1 */
  37614     uint32 *nh_multi_count;
  37615     bcm_if_t base_nh_id;
  37616     int i = 0;
  37617 
  37618     /*  Make sure module was initialized. */
  37619     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  37620         return (BCM_E_INIT);
  37621     }
  37622 
  37623     /* Input parameters check. */
  37624     if (!BCM_XGS3_L3_EGRESS_IDX_VALID(unit, base_egress_id) &&
  37625         !BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, base_egress_id)) {
  37626         return (BCM_E_PARAM);
  37627     }
  37628 
  37629     /* Calculate next hop index. */
  37630     if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, base_egress_id)) {
  37631         base_nh_id = base_egress_id - BCM_XGS3_EGRESS_IDX_MIN(unit);
  37632     } else {
  37633         base_nh_id = base_egress_id - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  37634     }
  37635 
  37636     if (soc_feature(unit, soc_feature_hierarchical_protection)) {
  37637         nh_multi_count = BCM_XGS3_L3_NH_MULTI_COUNT(unit);
  37638         no_of_elements = nh_multi_count[base_nh_id];;
  37639     }
  37640     no_of_elements = ((no_of_elements > 1)? no_of_elements : 1);
  37641 
  37642     /*  Make sure hw call is registred. */
  37643     if (!BCM_XGS3_L3_HWCALL_CHECK(unit, nh_del)) {
  37644         return (BCM_E_UNAVAIL);
  37645     }
  37646 
  37647     /* Initialization */
  37648     sal_memset(&data, 0, sizeof(_bcm_l3_tbl_op_t));
  37649     data.tbl_ptr =  BCM_XGS3_L3_TBL_PTR(unit, next_hop);
  37650     data.width = _BCM_SINGLE_WIDE;
  37651     /*     data.oper_flags = flags;*/
  37652     data.delete_func = BCM_XGS3_L3_HWCALL(unit, nh_del);
  37653 
  37654     for (; i < no_of_elements; i++) {
  37655 
  37656         data.entry_index = base_nh_id + i;
  37657 
  37658         /* Delete next hop table entry. */
  37659         if (BCM_XGS3_L3_ENT_REF_CNT(data.tbl_ptr, base_nh_id + i) == 1) {
  37660             BCM_XGS3_L3_NH_CNT(unit)--;
  37661         }
  37662 
  37663         /* Delete next hop table entry. */
  37664         BCM_IF_ERROR_RETURN(_bcm_xgs3_tbl_del(unit, &data));
  37665     }
  37666 
  37667     return BCM_E_NONE;
  37668 }
  37669 
  37670 /*
  37671  * Function:
  37672  *      bcmi_l3_nh_multi_count_get
  37673  * Purpose:
  37674  *      get number of nexthop allocated at this index..
  37675  * Parameters:
  37676  *      unit              - (IN)SOC unit number.
  37677  *      base_egress_id    - (OUT) base egress object id.
  37678  * Returns:
  37679  *      int
  37680  */
  37681 int
  37682 bcmi_l3_nh_multi_count_get(int unit, bcm_if_t nh_index)
  37683 {
  37684     uint32 *nh_multi_count;
  37685 
  37686     if (nh_index < 1) {
  37687         return 0;
  37688     }
  37689 
  37690     if (soc_feature(unit, soc_feature_hierarchical_protection)) {
  37691         nh_multi_count = BCM_XGS3_L3_NH_MULTI_COUNT(unit);
  37692         return nh_multi_count[nh_index];;
  37693     }
  37694 
  37695     return 0;
  37696 }
  37697 
  37698 #endif /* BCM_FIREBOLT_SUPPORT */
  37699 
  37700 #ifdef BCM_TRIDENT3_SUPPORT
  37701 /* Internal function to check the validity of overlay interface id range */
  37702 
  37703 STATIC int
  37704 _bcmi_l3_intf_overlay_valid(int unit, _bcm_l3_intf_cfg_t *intf_info)
  37705 {
  37706     int min_idx, max_idx;
  37707     _bcm_l3_bookkeeping_t *l3_bk = L3_INFO(unit);
  37708 
  37709     if (BCMI_L3_INTF_OVERLAY_VALID(unit)) {
  37710         if (l3_bk->l3_intf_overlay_alloc_mode > 0) {
  37711             min_idx = BCM_XGS3_L3_IF_TBL_SIZE(unit) -
  37712                 l3_bk->l3_intf_overlay_entries;
  37713             max_idx = BCM_XGS3_L3_IF_TBL_SIZE(unit) - 1;
  37714         } else {
  37715             min_idx = 0;
  37716             max_idx = l3_bk->l3_intf_overlay_entries -1;
  37717         }
  37718         if ((intf_info->l3i_index >= min_idx) &&
  37719                 (intf_info->l3i_index <= max_idx)) {
  37720             return BCM_E_NONE;
  37721         }
  37722     }
  37723     return BCM_E_PARAM;
  37724 }
  37725 
  37726 /*
  37727  * Function:
  37728  *      bcmi_l3_intf_vpn_set
  37729  * Purpose:
  37730  *      Set the VPN on a given L3 Egress interface.
  37731  *
  37732  * Parameters:
  37733  *      unit         - (IN) Unit number.
  37734  *      l3_intf_id   - (IN) Interface ID of an egress L3 object
  37735  *      bcm_vpn_t    - (IN) VPN_ID that needs to be set on this interface
  37736  *      flags        - (IN) Flags for future use
  37737  * Returns:
  37738  *      BCM_E_XXX
  37739  */
  37740 int
  37741 bcmi_l3_intf_vpn_set(int unit,
  37742         bcm_if_t l3_intf_id, bcm_vpn_t vpn,
  37743         uint32 flags)
  37744 {
  37745     _bcm_l3_intf_cfg_t intf_info;
  37746     egr_l3_intf_entry_t if_entry;
  37747     int vlan;
  37748     vlan = vpn;
  37749 
  37750     if ((vlan < BCM_VLAN_NONE) || (vlan >= BCM_VLAN_INVALID)) {
  37751         /* only vlan values are allowed */
  37752         return BCM_E_PARAM;
  37753     }
  37754 
  37755     if (BCM_L3_INTF_USED_GET(unit, l3_intf_id)) {
  37756         sal_memset(&intf_info, 0, sizeof(_bcm_l3_intf_cfg_t));
  37757         intf_info.l3i_index =  l3_intf_id;
  37758 
  37759         if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_get)) {
  37760             BCM_IF_ERROR_RETURN(BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit,
  37761                         &intf_info));
  37762             if (_bcmi_l3_intf_overlay_valid(unit, &intf_info) != BCM_E_NONE) {
  37763                return BCM_E_PARAM;
  37764             }
  37765             /* Allow valid Overlay Interface
  37766              * on which vfi value is set, otherwise
  37767              * throw error */
  37768             if (BCMI_RIOT_VPN_VFI_IS_SET(unit, intf_info.l3i_vid)) {
  37769                 BCM_IF_ERROR_RETURN(READ_EGR_L3_INTFm(unit, MEM_BLOCK_ANY, l3_intf_id,
  37770                             &if_entry));
  37771                 soc_EGR_L3_INTFm_field32_set(unit, &if_entry, VIDf, vpn);
  37772 
  37773                 BCM_IF_ERROR_RETURN(WRITE_EGR_L3_INTFm(unit, MEM_BLOCK_ANY,
  37774                             l3_intf_id, &if_entry));
  37775             } else {
  37776                 return BCM_E_PARAM;
  37777             }
  37778             return BCM_E_NONE;
  37779         }
  37780     }
  37781     return BCM_E_PARAM;
  37782 }
  37783 
  37784 /*
  37785  * Function:
  37786  *      bcmi_l3_intf_vpn_get
  37787  * Purpose:
  37788  *      Get the VPN on a given L3 Egress interface.
  37789  *
  37790  * Parameters:
  37791  *      unit         - (IN) Unit number.
  37792  *      l3_intf_id   - (IN) Interface ID of an egress L3 object
  37793  *      bcm_vpn_t    - (OUT) VPN_ID that needs to be set on this interface
  37794  *      flags        - (OUT) Flags for future use
  37795  * Returns:
  37796  *      BCM_E_XXX
  37797  */
  37798 int
  37799 bcmi_l3_intf_vpn_get(int unit,
  37800         bcm_if_t l3_intf_id, bcm_vpn_t *vpn,
  37801         uint32 *flags)
  37802 {
  37803     _bcm_l3_intf_cfg_t intf_info;
  37804     egr_l3_intf_entry_t if_entry;
  37805 
  37806     if (BCM_L3_INTF_USED_GET(unit, l3_intf_id)) {
  37807         sal_memset(&intf_info, 0, sizeof(_bcm_l3_intf_cfg_t));
  37808         intf_info.l3i_index = l3_intf_id;
  37809         if (BCM_XGS3_L3_HWCALL_CHECK(unit, if_get)) {
  37810             BCM_IF_ERROR_RETURN(BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit,
  37811                         &intf_info));
  37812             if (_bcmi_l3_intf_overlay_valid(unit, &intf_info) == BCM_E_NONE) {
  37813                 BCM_IF_ERROR_RETURN(READ_EGR_L3_INTFm(unit, MEM_BLOCK_ANY,
  37814                             l3_intf_id, &if_entry));
  37815                 *vpn = soc_EGR_L3_INTFm_field32_get(unit, &if_entry, VIDf);
  37816                 return BCM_E_NONE;
  37817             }
  37818         }
  37819     }
  37820     return BCM_E_PARAM;
  37821 }
  37822 
  37823 /*
  37824  * Function:
  37825  *      bcmi_ecmp_dlb_status_get
  37826  * Purpose:
  37827  *      Check if DLB hashing is enabled on any ECMP  group.
  37828  * Parameters:
  37829  *      unit  - (IN) SOC unit number.
  37830  *      dlb_status - (OUT) ECMP DLB hashing status
  37831  * Returns:
  37832  *      BCM_E_xxx
  37833  */
  37834 int
  37835 bcmi_ecmp_dlb_status_get(int unit, int *dlb_status)
  37836 {
  37837     int i;
  37838     uint32 rval = 0;
  37839     *dlb_status = FALSE;
  37840    /* Check for the global mode enhanced_hashing status */
  37841 
  37842     if (soc_reg_field_valid(unit, ENHANCED_HASHING_CONTROLr, RH_DLB_SELECTIONf)) {
  37843         SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROLr(unit, &rval));
  37844         if (1 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROLr, rval,
  37845                 RH_DLB_SELECTIONf)) {
  37846            /* ECMP DLB hashing is not enabled chip-wide. */
  37847             return BCM_E_NONE;
  37848         }
  37849     }
  37850     for (i = 0; i <=4095; i++) {
  37851         if (ecmp_grp_enhanced_hashing[unit][i] == 1) {
  37852             *dlb_status = TRUE;
  37853             break;
  37854         }
  37855     }
  37856     return BCM_E_NONE;
  37857 }
  37858 
  37859 /*
  37860  * Function:
  37861  *      bcmi_ecmp_rh_status_get
  37862  * Purpose:
  37863  *      Check if RH hashing is enabled on any ECMP  group.
  37864  * Parameters:
  37865  *      unit  - (IN) SOC unit number.
  37866  *      rh_status - (OUT) ECMP RH hashing status
  37867  * Returns:
  37868  *      BCM_E_xxx
  37869  */
  37870 int
  37871 bcmi_ecmp_rh_status_get(int unit, int *rh_status)
  37872 {
  37873     int i;
  37874     uint32 rval = 0;
  37875     *rh_status = FALSE;
  37876 /* Check for the global mode enhanced_hashing status */
  37877 
  37878     if (soc_reg_field_valid(unit, ENHANCED_HASHING_CONTROLr, RH_DLB_SELECTIONf)) {
  37879         SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROLr(unit, &rval));
  37880         if (0 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROLr, rval,
  37881                 RH_DLB_SELECTIONf)) {
  37882            /* ECMP RH hashing is not enabled chip-wide. */
  37883             return BCM_E_NONE;
  37884         }
  37885     }
  37886     for (i = 0; i <=4095; i++) {
  37887         if (ecmp_grp_enhanced_hashing[unit][i] == 1) {
  37888             *rh_status = TRUE;
  37889             break;
  37890         }
  37891     }
  37892     return BCM_E_NONE;
  37893 }
  37894 #endif
  37895 #ifndef BCM_SW_STATE_DUMP_DISABLE
  37896 /*
  37897  * Function:
  37898  *     _bcm_l3_sw_dump
  37899  * Purpose:
  37900  *     Displays L3 information maintained by software.
  37901  * Parameters:
  37902  *     unit - Device unit number
  37903  * Returns:
  37904  *     None
  37905  */
  37906 void
  37907 _bcm_l3_sw_dump(int unit)
  37908   {
  37909 #ifdef BCM_FIREBOLT_SUPPORT
  37910     
  37911     int                      i, j;
  37912     _bcm_l3_tbl_t 	     *tbl_ptr;     /* Generic table pointer     */
  37913 #ifdef BCM_RIOT_SUPPORT
  37914     _bcm_l3_bookkeeping_t *l3_bk_info = L3_INFO(unit);
  37915 #endif
  37916 
  37917     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
  37918         LOG_CLI((BSL_META_U(unit,
  37919                             "\nL3 data structure is not initialized\n")));
  37920         return;        
  37921     }
  37922 
  37923     LOG_CLI((BSL_META_U(unit,
  37924                         "\nSW Information L3 - Unit %d\n"), unit));
  37925     LOG_CLI((BSL_META_U(unit,
  37926                         "  Initialized : %d\n"), BCM_XGS3_L3_INITIALIZED(unit)));
  37927 
  37928     /* Interface table */
  37929     LOG_CLI((BSL_META_U(unit,
  37930                         "  L3 Interface Table Information -\n")));
  37931 #ifdef BCM_RIOT_SUPPORT
  37932     if ((BCMI_RIOT_IS_ENABLED(unit))
  37933         && (l3_bk_info->l3_intf_overlay_entries > 0)) {
  37934         if (l3_bk_info->l3_intf_overlay_alloc_mode > 0) {
  37935             LOG_CLI((BSL_META_U(unit,
  37936                             "  Overlay table size  : %d (%d - %d)\n"),
  37937                             l3_bk_info->l3_intf_overlay_entries,
  37938                              BCM_XGS3_L3_IF_TBL_SIZE(unit) -
  37939                              l3_bk_info->l3_intf_overlay_entries + 1,
  37940                            BCM_XGS3_L3_IF_TBL_SIZE(unit)));
  37941             LOG_CLI((BSL_META_U(unit,
  37942                             "  Underlay table size : %d (%d - %d)\n"),
  37943                             (BCM_XGS3_L3_IF_TBL_SIZE(unit) -
  37944                                 l3_bk_info->l3_intf_overlay_entries) + 1,
  37945                                 0,
  37946                                 BCM_XGS3_L3_IF_TBL_SIZE(unit) -
  37947                                 l3_bk_info->l3_intf_overlay_entries));
  37948         } else {
  37949             LOG_CLI((BSL_META_U(unit,
  37950                             "  Overlay table size  : %d (%d - %d)\n"),
  37951                             l3_bk_info->l3_intf_overlay_entries, 0,
  37952                             l3_bk_info->l3_intf_overlay_entries -1));
  37953             LOG_CLI((BSL_META_U(unit,
  37954                             "  Underlay table size : %d (%d - %d)\n"),
  37955                             (BCM_XGS3_L3_IF_TBL_SIZE(unit) -
  37956                                 l3_bk_info->l3_intf_overlay_entries) + 1,
  37957                                 l3_bk_info->l3_intf_overlay_entries,
  37958                                 BCM_XGS3_L3_IF_TBL_SIZE(unit)));
  37959         }
  37960     } else 
  37961 #endif
  37962     {
  37963         LOG_CLI((BSL_META_U(unit,
  37964                         "  table size : %d\n"), BCM_XGS3_L3_IF_TBL_SIZE(unit)));
  37965     }
  37966  
  37967     LOG_CLI((BSL_META_U(unit,
  37968                         "    count      : %d\n"), BCM_XGS3_L3_IF_COUNT(unit)));
  37969 
  37970     LOG_CLI((BSL_META_U(unit,
  37971                         "    Used index from bk info:")));
  37972     if (BCM_XGS3_L3_IF_INUSE(unit) != NULL) {
  37973         for (i = 0, j = 0; i < BCM_XGS3_L3_IF_TBL_SIZE(unit); i++) {
  37974             /* If not set, skip print */
  37975             if (!BCM_L3_INTF_USED_GET(unit, i)) {
  37976                 continue;
  37977             }
  37978             if (!(j % 10)) {
  37979                 LOG_CLI((BSL_META_U(unit,
  37980                                     "\n    ")));
  37981             }
  37982             LOG_CLI((BSL_META_U(unit,
  37983                                 "  %5d"), i));
  37984             j++;
  37985         }
  37986     }
  37987     LOG_CLI((BSL_META_U(unit,
  37988                         "\n")));
  37989 
  37990     LOG_CLI((BSL_META_U(unit,
  37991                         "    ARL  index :")));
  37992     if (BCM_XGS3_L3_IF_ADD2ARL(unit) != NULL) {
  37993         for (i = 0, j = 0; i < BCM_XGS3_L3_IF_TBL_SIZE(unit); i++) {
  37994             /* If not set, skip print */
  37995             if (!BCM_L3_INTF_ARL_GET(unit, i)) {
  37996                 continue;
  37997             }
  37998             if (!(j % 10)) {
  37999                 LOG_CLI((BSL_META_U(unit,
  38000                                     "\n    ")));
  38001             }
  38002             LOG_CLI((BSL_META_U(unit,
  38003                                 "  %5d"), i));
  38004             j++;
  38005         }
  38006     }
  38007     LOG_CLI((BSL_META_U(unit,
  38008                         "\n")));
  38009 
  38010     /* Defip table */
  38011     LOG_CLI((BSL_META_U(unit,
  38012                         "  DEF IP -\n")));
  38013     LOG_CLI((BSL_META_U(unit,
  38014                         "    table size : %d\n"), BCM_XGS3_L3_DEFIP_TBL_SIZE(unit)));
  38015     LOG_CLI((BSL_META_U(unit,
  38016                         "    IP4 count  : %d\n"), BCM_XGS3_L3_DEFIP_IP4_CNT(unit)));
  38017     LOG_CLI((BSL_META_U(unit,
  38018                         "    IP6 count  : %d\n"), BCM_XGS3_L3_DEFIP_IP6_CNT(unit)));
  38019     /* Skip 'strata_defip_info' since this is for Strata only */
  38020 
  38021     /* L3 Host table */
  38022     LOG_CLI((BSL_META_U(unit,
  38023                         "  L3 -\n")));
  38024     LOG_CLI((BSL_META_U(unit,
  38025                         "    table size     : %d\n"), BCM_XGS3_L3_TBL_SIZE(unit)));
  38026     LOG_CLI((BSL_META_U(unit,
  38027                         "    IP4 added      : %d\n"), BCM_XGS3_L3_IP4_CNT(unit)));
  38028     LOG_CLI((BSL_META_U(unit,
  38029                         "    IP6 added      : %d\n"), BCM_XGS3_L3_IP6_CNT(unit)));
  38030     LOG_CLI((BSL_META_U(unit,
  38031                         "    IP4 IPMC added : %d\n"), BCM_XGS3_L3_IP4_IPMC_CNT(unit)));
  38032     LOG_CLI((BSL_META_U(unit,
  38033                         "    IP6 IPMC added : %d\n"), BCM_XGS3_L3_IP6_IPMC_CNT(unit)));
  38034 
  38035     /* ECMP table */
  38036     LOG_CLI((BSL_META_U(unit,
  38037                         "  ECMP   table size : %d\n"),
  38038              BCM_XGS3_L3_ECMP_TBL_SIZE(unit)));
  38039     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp);
  38040     LOG_CLI((BSL_META_U(unit,
  38041                         "\n    L3 ECMP Table -\n")));
  38042 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
  38043     if (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) {
  38044 
  38045         LOG_CLI((BSL_META_U(unit, "==== Overlay table size ==== \n")));
  38046         LOG_CLI((BSL_META_U(unit,
  38047                         "    min              : %d\n"), tbl_ptr->idx_min));
  38048         LOG_CLI((BSL_META_U(unit, 
  38049                         "    max              : %d\n"), tbl_ptr->split_idx - 1));
  38050         LOG_CLI((BSL_META_U(unit,
  38051                         "   overlay  max used : %d\n"), tbl_ptr->split_maxused));
  38052 
  38053         LOG_CLI((BSL_META_U(unit, "==== Underlay table size ==== \n")));
  38054         LOG_CLI((BSL_META_U(unit,
  38055                         "  min                : %d\n"), tbl_ptr->split_idx));
  38056         LOG_CLI((BSL_META_U(unit,
  38057                         "  max                : %d\n"), tbl_ptr->idx_max));
  38058         LOG_CLI((BSL_META_U(unit,
  38059                         "  underlay max used  : %d\n"), tbl_ptr->idx_maxused));
  38060 
  38061     } else
  38062 #endif
  38063     {
  38064 
  38065         LOG_CLI((BSL_META_U(unit,
  38066                         "        min       : %d\n"), tbl_ptr->idx_min));
  38067         LOG_CLI((BSL_META_U(unit,
  38068                         "        max       : %d\n"), tbl_ptr->idx_max));
  38069         LOG_CLI((BSL_META_U(unit,
  38070                         "        max used  : %d\n"), tbl_ptr->idx_maxused));
  38071     }
  38072     LOG_CLI((BSL_META_U(unit,
  38073                         "        max paths : %d\n"), BCM_XGS3_L3_ECMP_MAX_PATHS(unit)));
  38074     LOG_CLI((BSL_META_U(unit,
  38075                         "        in use    : %d\n"), BCM_XGS3_L3_ECMP_IN_USE(unit)));
  38076 
  38077     if(!(tbl_ptr->idx_min == 0 && tbl_ptr->idx_max == 0)) { /* mem not valid */
  38078         LOG_CLI((BSL_META_U(unit,
  38079                             "        table index : hash : ref_count")));
  38080         for (i = tbl_ptr->idx_min, j = 0; i <= tbl_ptr->idx_max; i++) {
  38081             /* If zero, skip print */
  38082             if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, i)) {
  38083                 continue;
  38084             }
  38085             if (!(j % 4)) {
  38086                 LOG_CLI((BSL_META_U(unit,
  38087                                     "\n        ")));
  38088             }
  38089             LOG_CLI((BSL_META_U(unit,
  38090                                 "  %5d:%-5d:%-5d"), i, BCM_XGS3_L3_ENT_HASH(tbl_ptr, i),
  38091                      BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, i)));
  38092             j++;
  38093         }
  38094     }
  38095     LOG_CLI((BSL_META_U(unit,
  38096                         "\n")));
  38097 
  38098     /* Next hop table */
  38099     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, next_hop);
  38100     LOG_CLI((BSL_META_U(unit,
  38101                         "\n    L3 Next Hop Table -\n")));
  38102 #ifdef BCM_RIOT_SUPPORT
  38103     if (BCMI_RIOT_IS_ENABLED(unit) 
  38104         && (l3_bk_info->l3_nh_overlay_entries > 0)) {
  38105         if (l3_bk_info->l3_nh_overlay_alloc_mode > 0) {
  38106             LOG_CLI((BSL_META_U(unit, "==== Overlay table size ==== : \n")));
  38107             LOG_CLI((BSL_META_U(unit,
  38108                             "  min                : %d\n"), tbl_ptr->split_idx));
  38109             LOG_CLI((BSL_META_U(unit,
  38110                             "  max                : %d\n"), tbl_ptr->idx_max));
  38111             LOG_CLI((BSL_META_U(unit,
  38112                             "  overlay max used  : %d\n"), tbl_ptr->idx_maxused));
  38113 
  38114             LOG_CLI((BSL_META_U(unit, "==== Underlay table size ==== \n")));
  38115             LOG_CLI((BSL_META_U(unit,
  38116                             "   min               : %d\n"), tbl_ptr->idx_min));
  38117             LOG_CLI((BSL_META_U(unit,
  38118                             "   max               : %d\n"), tbl_ptr->split_idx - 1));
  38119             LOG_CLI((BSL_META_U(unit,
  38120                             "   underlay  max used : %d\n"), tbl_ptr->split_maxused));
  38121         } else {
  38122             LOG_CLI((BSL_META_U(unit, "==== Overlay table size ==== \n")));
  38123             LOG_CLI((BSL_META_U(unit,
  38124                             "   min               : %d\n"), tbl_ptr->idx_min));
  38125             LOG_CLI((BSL_META_U(unit,
  38126                             "   max               : %d\n"), tbl_ptr->split_idx - 1));
  38127             LOG_CLI((BSL_META_U(unit,
  38128                             "   overlay  max used : %d\n"), tbl_ptr->split_maxused));
  38129 
  38130             LOG_CLI((BSL_META_U(unit, "==== Underlay table size ==== : \n")));
  38131             LOG_CLI((BSL_META_U(unit,
  38132                             "  min                : %d\n"), tbl_ptr->split_idx));
  38133             LOG_CLI((BSL_META_U(unit,
  38134                             "  max                : %d\n"), tbl_ptr->idx_max));
  38135             LOG_CLI((BSL_META_U(unit,
  38136                             "  underlay max used  : %d\n"), tbl_ptr->idx_maxused));
  38137         }
  38138     } else
  38139 #endif
  38140     {
  38141         LOG_CLI((BSL_META_U(unit,
  38142                         "  NH      table size : %d\n"), BCM_XGS3_L3_NH_TBL_SIZE(unit)));
  38143         LOG_CLI((BSL_META_U(unit,
  38144                         "  NH      index min  : %d\n"), tbl_ptr->idx_min));
  38145         LOG_CLI((BSL_META_U(unit,
  38146                         "  NH index max used  : %d\n"), tbl_ptr->idx_maxused));
  38147     }
  38148     for (i = tbl_ptr->idx_min, j = 0; i <= tbl_ptr->idx_max; i++) {
  38149         if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, i)) {
  38150            continue;
  38151         }
  38152         if (!(j % 4)) {
  38153             LOG_CLI((BSL_META_U(unit,
  38154                                 "\n    ")));
  38155         }
  38156         LOG_CLI((BSL_META_U(unit,
  38157                             " %5d:%-5d:%-5d"), i, BCM_XGS3_L3_ENT_HASH(tbl_ptr, i),
  38158                  BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, i)));
  38159         j++;
  38160         soc_tunnel_term_sw_dump(unit);
  38161     }
  38162     /* Tunnel initiator table */
  38163     tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, tnl_init);
  38164     LOG_CLI((BSL_META_U(unit,
  38165                         "\n    L3 Tunnel Initiator Table -\n")));
  38166     LOG_CLI((BSL_META_U(unit,
  38167                         "        min     : %d\n"), tbl_ptr->idx_min));
  38168     LOG_CLI((BSL_META_U(unit,
  38169                         "        max     : %d\n"), tbl_ptr->idx_max));
  38170     LOG_CLI((BSL_META_U(unit,
  38171                         "        total   : %d\n"), BCM_XGS3_L3_TUNNEL_TBL_SIZE(unit)));
  38172 
  38173     if(!(tbl_ptr->idx_min == 0 && tbl_ptr->idx_max == 0)) { /* mem not valid */
  38174         LOG_CLI((BSL_META_U(unit,
  38175                             "        use count (index:hash:count) :")));
  38176         for (i = tbl_ptr->idx_min, j = 0; i <= tbl_ptr->idx_max; i++) {
  38177             /* If zero count, skip print */
  38178             if (!BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, i)) {
  38179                 continue;
  38180             }
  38181             if (!(j % 4)) {
  38182                 LOG_CLI((BSL_META_U(unit,
  38183                                     "\n        ")));
  38184             }
  38185             LOG_CLI((BSL_META_U(unit,
  38186                                 "  %5d:%-5d:%-5d"), i, BCM_XGS3_L3_ENT_HASH(tbl_ptr, i),
  38187                      BCM_XGS3_L3_ENT_REF_CNT(tbl_ptr, i)));
  38188             j++;
  38189         }
  38190     }
  38191     LOG_CLI((BSL_META_U(unit,
  38192                         "\n")));
  38193 #ifdef BCM_TRIUMPH2_SUPPORT
  38194     if (SOC_IS_TRIUMPH3(unit) || BCM_XGS3_L3_MAX_ECMP_MODE(unit)) {
  38195         LOG_CLI((BSL_META_U(unit,
  38196                             "\n    ECMP group id:max paths-\n")));
  38197         for (i=0, j=0; i<BCM_XGS3_L3_ECMP_MAX_GROUPS(unit); i++) {
  38198             if (BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[i] != 0) {
  38199                 LOG_CLI((BSL_META_U(unit,
  38200                                     "%d:%d "), i,
  38201                          BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[i]));
  38202                 j++;
  38203                 if (!(j%20)) {
  38204                     LOG_CLI((BSL_META_U(unit,
  38205                                         "\n")));
  38206                 }
  38207             }
  38208         }
  38209     }
  38210 #endif
  38211 
  38212 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  38213     if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
  38214         SHR_BITDCL *group_bitmap_ptr = NULL;
  38215         int bitmap_width = BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2;
  38216 
  38217         LOG_CLI((BSL_META_U(unit,
  38218                     "\n    ECMP group id: DLB bitmap-\n")));
  38219         for (i = 0; i < BCM_XGS3_L3_ECMP_MAX_GROUPS(unit); i++) {
  38220             group_bitmap_ptr =
  38221                 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, i);
  38222             if (!SHR_BITNULL_RANGE(group_bitmap_ptr, 0, bitmap_width)) {
  38223                 LOG_CLI((BSL_META_U(unit, "%d:"), i));
  38224                 for(j = 0; j < _SHR_BITDCLSIZE(bitmap_width); j++) {
  38225                     LOG_CLI((BSL_META_U(unit, " [%d]0x%x:"),
  38226                                         j, group_bitmap_ptr[j]));
  38227                 }
  38228                 LOG_CLI((BSL_META_U(unit, "\n")));
  38229             }
  38230         }
  38231     }
  38232 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT */
  38233 
  38234 
  38235 #ifdef ALPM_ENABLE
  38236     /* ALPM Mode */
  38237     if (soc_feature(unit, soc_feature_alpm)
  38238         && soc_property_get(unit, spn_L3_ALPM_ENABLE, 0)) {
  38239         if (SOC_IS_TRIDENT2(unit) || SOC_IS_TRIDENT2PLUS(unit)) {
  38240             soc_alpm_sw_dump(unit);
  38241         }
  38242 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT)
  38243         else {
  38244 #if defined(BCM_TOMAHAWK_SUPPORT)
  38245             if (soc_feature(unit, soc_feature_alpm2)) {
  38246                 bcm_esw_alpm_sw_dump(unit);
  38247             } else
  38248 #endif
  38249             {
  38250                 soc_th_alpm_sw_dump(unit);
  38251             }
  38252         }
  38253 #endif /* BCM_TOMAHAWK_SUPPORT || BCM_APACHE_SUPPORT */
  38254     } else
  38255 #endif /* ALPM_ENABLE */
  38256     {
  38257         /* Prefix trackers (FB only) */
  38258         if (SOC_IS_FBX(unit)) {
  38259             soc_fb_lpm_sw_dump(unit);
  38260         }
  38261     }
  38262 #ifdef BCM_TRIUMPH3_SUPPORT
  38263     if (soc_feature(unit, soc_feature_ecmp_dlb)) {
  38264 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  38265         if (soc_feature(unit, soc_feature_ecmp_dlb_optimized)) {
  38266             bcm_th2_ecmp_dlb_sw_dump(unit);
  38267         } else
  38268 #endif /* BCM_TOMAHAWK2_SUPPORT || BCM_TRIDENT3_SUPPORT*/
  38269         {
  38270             bcm_tr3_ecmp_dlb_sw_dump(unit);
  38271         }
  38272     }
  38273 
  38274     if (soc_feature(unit, soc_feature_esm_support)) {
  38275         _bcm_tr3_esm_host_tbl_sw_dump(unit);
  38276     }
  38277 #endif /* BCM_TRIUMPH3_SUPPORT */
  38278 
  38279 #ifdef BCM_TRIUMPH2_SUPPORT
  38280     if (soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTRf) ||
  38281         soc_mem_field_valid(unit, L3_ECMP_COUNTm, BASE_PTR_0f)) {
  38282          if (!soc_feature(unit, soc_feature_l3_no_ecmp)) {
  38283             bcm_tr2_l3_ecmp_defragment_buffer_sw_dump(unit);
  38284         }
  38285     }
  38286 #endif /* BCM_TRIUMPH2_SUPPORT */
  38287 
  38288 #ifdef BCM_TRIDENT2_SUPPORT
  38289     if (SOC_IS_TRIDENT2X(unit) &&
  38290         soc_feature(unit, soc_feature_ecmp_resilient_hash)) {
  38291         bcm_td2_ecmp_rh_sw_dump(unit);
  38292     }
  38293 #endif /* BCM_TRIDENT2_SUPPORT */
  38294 
  38295 #ifdef BCM_TOMAHAWK_SUPPORT
  38296     if (soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized)) {
  38297         bcm_opt_ecmp_rh_sw_dump(unit);
  38298     }
  38299 #endif /* BCM_TOMAHAWK_SUPPORT */
  38300 
  38301 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)
  38302     if (soc_feature(unit, soc_feature_dgm)) {
  38303         bcm_th2_dgm_sw_dump(unit);
  38304     }
  38305 #endif
  38306 
  38307 #endif /* BCM_FIREBOLT_SUPPORT */
  38308 
  38309     return;
  38310 }
  38311 
  38312 #endif /* BCM_SW_STATE_DUMP_DISABLE */
  38313 void
  38314 bcmi_l3_dependent_free_resources(int unit)
  38315 {
  38316     bcmi_esw_failover_dependent_free_resources(unit);
  38317     return;
  38318 }
  38319 
  38320 #else  /* INCLUDE_L3 */
  38321 int bcm_esw_firebolt_l3_not_empty;
  38322 #endif /* INCLUDE_L3 */