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


      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: Triumph3 L3 function implementations
      9  */
     10 
     11 #include <shared/bsl.h>
     12 
     13 #include <soc/defs.h>
     14 #if defined(INCLUDE_L3) && defined(BCM_TRIDENT2_SUPPORT) 
     15 
     16 #include <soc/drv.h>
     17 #include <soc/scache.h>
     18 #include <bcm/vlan.h>
     19 #include <bcm/error.h>
     20 
     21 #include <bcm/l3.h>
     22 #include <soc/l3x.h>
     23 #include <soc/lpm.h>
     24 #ifdef ALPM_ENABLE
     25 #include <soc/alpm.h>
     26 #include <soc/esw/alpm_int.h>
     27 #endif
     28 #include <bcm/tunnel.h>
     29 #include <bcm/debug.h>
     30 #include <bcm/error.h>
     31 #include <bcm/stack.h>
     32 #include <soc/trident2.h>
     33 #if defined(BCM_TOMAHAWK_SUPPORT) 
     34 #include <soc/tomahawk.h>
     35 #endif /* BCM_TOMAHAWK_SUPPORT */
     36 #if defined(BCM_TOMAHAWK3_SUPPORT)
     37 #include <soc/tomahawk3.h>
     38 #endif /* BCM_TOMAHAWK3_SUPPORT */
     39 #if defined(BCM_MONTEREY_SUPPORT) 
     40 #include <soc/monterey.h>
     41 #include <bcm_int/esw/monterey.h>
     42 #endif /* BCM_MONTEREY_SUPPORT */
     43 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
     44 #include <soc/trident3.h>
     45 #include <bcm_int/esw/trident3.h>
     46 #endif /* BCM_TRIDENT3_SUPPORT */
     47 #if defined(BCM_APACHE_SUPPORT) 
     48 #include <soc/apache.h>
     49 #endif /* BCM_APACHE_SUPPORT */
     50 #if defined(BCM_HELIX5_SUPPORT) 
     51 #include <soc/helix5.h>
     52 #include <bcm_int/esw/helix5.h>
     53 #endif /* BCM_HELIX5_SUPPORT */
     54 #if defined(BCM_TRIDENT3_SUPPORT)
     55 #include <bcm_int/esw/flow.h>
     56 #include <soc/esw/flow_db.h>
     57 #endif /* BCM_TRIDENT3_SUPPORT*/
     58 #include <bcm_int/esw/tomahawk.h>
     59 #include <bcm_int/esw/trident2.h>
     60 #include <bcm_int/esw/firebolt.h>
     61 #include <bcm_int/esw/triumph.h>
     62 #include <bcm_int/esw/triumph2.h>
     63 #include <bcm_int/esw/stack.h>
     64 #include <bcm_int/esw/flex_ctr.h>
     65 #include <bcm_int/esw_dispatch.h>
     66 #include <bcm_int/esw/flex_ctr.h>
     67 #include <bcm_int/esw/virtual.h>
     68 
     69 #ifdef ALPM_ENABLE
     70 #include <bcm_int/esw/alpm.h>
     71 #include <bcm_int/esw/alpm_util.h>
     72 #endif
     73 
     74 #if defined(BCM_TRX_SUPPORT) 
     75 #include <bcm_int/esw/trx.h>
     76 #endif /* BCM_TRX_SUPPORT */
     77 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
     78 #include <bcm_int/esw/trident2plus.h>
     79 #endif /* BCM_TRIDENT2PLUS_SUPPORT */
     80 
     81 #define TH_IPMC_NO_SRC_CHECK_PORT      0xFF
     82 
     83 /* NH nat id update key type*/
     84 #define _BCM_NH_UPDATE_KEY_L3_INTF      0
     85 #define _BCM_NH_UPDATE_KEY_L3_IIF       1
     86 #define _BCM_NH_UPDATE_KEY_VLAN         2
     87 
     88 /* IP Options Handling */
     89 #define L3_INFO(_unit_) (&_bcm_l3_bk_info[_unit_])
     90 #define _BCM_IP_OPTION_PROFILE_CHUNK 256
     91 #define _BCM_IP4_OPTIONS_LEN    \
     92             (soc_mem_index_count(unit, IP_OPTION_CONTROL_PROFILE_TABLEm)/ \
     93              _BCM_IP_OPTION_PROFILE_CHUNK)
     94 
     95 /* Add mutex semaphore to protect "L3_INFO(unit)->ip4_profiles_hw_idx" */
     96 STATIC sal_mutex_t ip4_profiles_hw_idx_lock[BCM_MAX_NUM_UNITS];
     97 
     98 #define HW_IDX_LOCK(unit) \
     99     do { \
    100         if (ip4_profiles_hw_idx_lock[unit] != NULL) { \
    101             sal_mutex_take(ip4_profiles_hw_idx_lock[unit], sal_mutex_FOREVER); \
    102         } \
    103     } while (0)
    104 
    105 #define HW_IDX_UNLOCK(unit) \
    106     do { \
    107         if (ip4_profiles_hw_idx_lock[unit] != NULL) { \
    108             sal_mutex_give(ip4_profiles_hw_idx_lock[unit]); \
    109         } \
    110     } while (0)
    111 
    112 #define GET_HW_IDX(unit, idx, id) \
    113     do { \
    114         HW_IDX_LOCK(unit); \
    115         idx = L3_INFO(unit)->ip4_profiles_hw_idx[id]; \
    116         HW_IDX_UNLOCK(unit); \
    117     } while (0)                        
    118 
    119 #define SET_HW_IDX(unit, id, idx) \
    120     do { \
    121         HW_IDX_LOCK(unit); \
    122         L3_INFO(unit)->ip4_profiles_hw_idx[id] = idx; \
    123         HW_IDX_UNLOCK(unit); \
    124     } while (0)
    125 
    126 /*
    127  * IP_OPTIONS_PROFILE usage bitmap operations
    128  */
    129 #define _BCM_IP4_OPTIONS_USED_GET(_u_, _identifier_) \
    130         SHR_BITGET(L3_INFO(_u_)->ip4_options_bitmap, (_identifier_))
    131 #define _BCM_IP4_OPTIONS_USED_SET(_u_, _identifier_) \
    132         SHR_BITSET(L3_INFO((_u_))->ip4_options_bitmap, (_identifier_))
    133 #define _BCM_IP4_OPTIONS_USED_CLR(_u_, _identifier_) \
    134         SHR_BITCLR(L3_INFO((_u_))->ip4_options_bitmap, (_identifier_))
    135 
    136 #define _BCM_IP_OPTION_REINIT_INVALID_HW_IDX 0xffff
    137 
    138 /* Bookkeeping info for ECMP resilient hashing */
    139 typedef struct _td2_ecmp_rh_info_s {
    140     int num_ecmp_rh_flowset_blocks;
    141     SHR_BITDCL *ecmp_rh_flowset_block_bitmap; /* Each block corresponds to
    142                                                  64 entries, 8 for monterey */
    143     uint32 ecmp_rh_rand_seed; /* The seed for pseudo-random number generator */
    144     uint8  ecmp_block_size;    /* Block size in bits
    145                                 * 6 for TD2/+/Apache
    146                                 * 3 for Monterey */
    147     uint8  ecmp_rand_seed_shift;
    148 } _td2_ecmp_rh_info_t;
    149 
    150 STATIC _td2_ecmp_rh_info_t *_td2_ecmp_rh_info[BCM_MAX_NUM_UNITS];
    151 
    152 /* per ecmp group enhanced hashing enabled info  */
    153 #ifdef BCM_TRIDENT3_SUPPORT
    154 extern uint8  ecmp_grp_enhanced_hashing[BCM_MAX_NUM_UNITS][4096];
    155 #endif
    156 
    157 #define _BCM_ECMP_RH_FLOWSET_BLOCK_USED_GET(_u_, _idx_) \
    158     SHR_BITGET(_td2_ecmp_rh_info[_u_]->ecmp_rh_flowset_block_bitmap, _idx_)
    159 #define _BCM_ECMP_RH_FLOWSET_BLOCK_USED_SET(_u_, _idx_) \
    160     SHR_BITSET(_td2_ecmp_rh_info[_u_]->ecmp_rh_flowset_block_bitmap, _idx_)
    161 #define _BCM_ECMP_RH_FLOWSET_BLOCK_USED_CLR(_u_, _idx_) \
    162     SHR_BITCLR(_td2_ecmp_rh_info[_u_]->ecmp_rh_flowset_block_bitmap, _idx_)
    163 #define _BCM_ECMP_RH_FLOWSET_BLOCK_USED_SET_RANGE(_u_, _idx_, _count_) \
    164     SHR_BITSET_RANGE(_td2_ecmp_rh_info[_u_]->ecmp_rh_flowset_block_bitmap, \
    165             _idx_, _count_)
    166 #define _BCM_ECMP_RH_FLOWSET_BLOCK_USED_CLR_RANGE(_u_, _idx_, _count_) \
    167     SHR_BITCLR_RANGE(_td2_ecmp_rh_info[_u_]->ecmp_rh_flowset_block_bitmap, \
    168             _idx_, _count_)
    169 #define _BCM_ECMP_RH_FLOWSET_BLOCK_TEST_RANGE(_u_, _idx_, _count_, _result_) \
    170     SHR_BITTEST_RANGE(_td2_ecmp_rh_info[_u_]->ecmp_rh_flowset_block_bitmap, \
    171             _idx_, _count_, _result_)
    172 
    173 typedef struct _td2_ecmp_rh_member_s {
    174     int nh_index; /* Next hop index of the member */
    175     int member_id; /* Member ID */
    176     int num_replica; /* Number of members with the same next hop index as
    177                         this member. Valid only for the first replica. */
    178     int replica_id; /* Index among members with the same next hop index as
    179                        this member. Valid for every replica. */
    180     int next_replica_id; /* Index of the next replica to be assigned to
    181                             a flow set entry containing the next hop index
    182                             shared by replicas. Valid only for the first
    183                             replica. */
    184 } _td2_ecmp_rh_member_t;
    185 
    186 /*----- STATIC FUNCS ----- */
    187 int
    188 _bcm_td2_l3_ipmc_ent_init(int unit, uint32 *buf_p, _bcm_l3_cfg_t *l3cfg);
    189 
    190 
    191 /*
    192  * Function:
    193  *      _bcm_td2_l3_ent_init
    194  * Purpose:
    195  *      TD2 helper routine used to init l3 host entry buffer
    196  * Parameters:
    197  *      unit      - (IN) SOC unit number. 
    198  *      mem       - (IN) L3 table memory.
    199  *      l3cfg     - (IN/OUT) l3 entry  lookup key & search result.
    200  *      l3x_entry - (IN) hw buffer.
    201  * Returns:
    202  *      void
    203  */
    204 int
    205 _bcm_td2_l3_ent_init(int unit, soc_mem_t mem, 
    206                       _bcm_l3_cfg_t *l3cfg, void *l3x_entry)
    207 {
    208     int ipv6;                     /* Entry is IPv6 flag.         */
    209     uint32 *buf_p;                /* HW buffer address.          */ 
    210 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
    211     uint32 base_valid0, base_valid1;
    212 #endif
    213 
    214 
    215     /* Get entry type. */
    216     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
    217 
    218     /* Zero destination buffer. */
    219     buf_p = (uint32 *)l3x_entry;
    220     sal_memset(buf_p, 0, BCM_L3_MEM_ENT_SIZE(unit, mem)); 
    221 
    222     if (ipv6) { /* ipv6 entry */
    223         if (BCM_XGS3_L3_MEM(unit, v6) == mem) {
    224 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
    225             if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) {
    226                 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6UC__IP_ADDR_LWR_64f,
    227                                  l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY);
    228                 soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6UC__IP_ADDR_UPR_64f,
    229                                  l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY);
    230                 soc_mem_field32_set(unit, mem, buf_p, IPV6UC__VRF_IDf,
    231                                                       l3cfg->l3c_vrf);
    232 
    233             } else
    234 #endif
    235             {
    236             soc_mem_ip6_addr_set(unit, mem, buf_p, IP_ADDR_LWR_64f,
    237                              l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY);
    238             soc_mem_ip6_addr_set(unit, mem, buf_p, IP_ADDR_UPR_64f,
    239                              l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY);
    240             soc_mem_field32_set(unit, mem, buf_p, VRF_IDf,
    241                                                   l3cfg->l3c_vrf);
    242             }
    243 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
    244             if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit))
    245             {
    246                 if (SOC_IS_TRIDENT3X(unit))
    247                 {
    248                 soc_mem_field32_set(unit, mem, buf_p, DATA_TYPEf, TD3_L3_HASH_DATA_TYPE_V6UC);
    249                     base_valid0 = 3;
    250                     base_valid1 = 4;
    251                 }
    252                 else
    253                 {
    254                     base_valid0 = 1;
    255                     base_valid1 = 2;
    256                 }
    257                 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf, TD3_L3_HASH_KEY_TYPE_V6UC);
    258                 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_0f, base_valid0);
    259                 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_1f, base_valid1);
    260             }
    261             else
    262 #endif
    263             {
    264             soc_mem_field32_set(unit, mem, buf_p, VALID_0f, 1); 
    265             soc_mem_field32_set(unit, mem, buf_p, VALID_1f, 1); 
    266             soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_0f, 2);
    267             soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_1f, 2);
    268             }
    269         } else if (BCM_XGS3_L3_MEM(unit, v6_4) == mem) { 
    270             soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6UC_EXT__IP_ADDR_LWR_64f,
    271                              l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY);
    272             soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6UC_EXT__IP_ADDR_UPR_64f,
    273                              l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY);
    274             soc_mem_field32_set(unit, mem, buf_p, IPV6UC_EXT__VRF_IDf,
    275                                                   l3cfg->l3c_vrf);
    276             /* ipv6 extended host entry */
    277 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
    278             if (SOC_IS_TRIDENT3X(unit))
    279             {
    280                 if (SOC_IS_TRIDENT3X(unit))
    281                 {
    282                 soc_mem_field32_set(unit, mem, buf_p, DATA_TYPEf, TD3_L3_HASH_DATA_TYPE_V6UC_EXT);
    283                 }
    284                 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf, TD3_L3_HASH_KEY_TYPE_V6UC_EXT);
    285                 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_0f, 3);
    286                 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_1f, 4);
    287                 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_2f, 7);
    288                 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_3f, 7);
    289             } else
    290 #endif
    291             {
    292             soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_0f, 3);
    293             soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_1f, 3);
    294             soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_2f, 3);
    295             soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_3f, 3);
    296 
    297             soc_mem_field32_set(unit, mem, buf_p, VALID_0f, 1); 
    298             soc_mem_field32_set(unit, mem, buf_p, VALID_1f, 1); 
    299             soc_mem_field32_set(unit, mem, buf_p, VALID_2f, 1); 
    300             soc_mem_field32_set(unit, mem, buf_p, VALID_3f, 1); 
    301             }
    302         } else {
    303             return BCM_E_NOT_FOUND;
    304         }
    305     } else { /* ipv4 entry */                /* if uC is still not ready, return timeout */
    306         if (BCM_XGS3_L3_MEM(unit, v4) == mem) {
    307 #if defined(BCM_TOMAHAWK3_SUPPORT)
    308             if (SOC_IS_TOMAHAWK3(unit))
    309             {
    310                 soc_mem_field32_set(unit, mem, buf_p, IPV4UC__IP_ADDRf, 
    311 												l3cfg->l3c_ip_addr);
    312                 soc_mem_field32_set(unit, mem, buf_p, IPV4UC__VRF_IDf, 
    313 												l3cfg->l3c_vrf);
    314             } else
    315 #endif
    316             {
    317             soc_mem_field32_set(unit, mem, buf_p, IP_ADDRf,
    318                                                l3cfg->l3c_ip_addr);
    319             soc_mem_field32_set(unit, mem, buf_p, VRF_IDf,
    320                                                   l3cfg->l3c_vrf);
    321             }
    322             /* ipv4 unicast */
    323             soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf, 0); 
    324 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
    325             if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) {
    326                 soc_mem_field32_set(unit, mem, buf_p, BASE_VALIDf, 1);
    327             } else 
    328 #endif
    329             {
    330             soc_mem_field32_set(unit, mem, buf_p, VALIDf, 1); 
    331             }
    332         } else if (BCM_XGS3_L3_MEM(unit, v4_2) == mem) { 
    333             soc_mem_field32_set(unit, mem, buf_p, IPV4UC_EXT__IP_ADDRf,
    334                                                l3cfg->l3c_ip_addr);
    335             soc_mem_field32_set(unit, mem, buf_p, IPV4UC_EXT__VRF_IDf,
    336                                                   l3cfg->l3c_vrf);
    337             /* ipv4 extended host entry */
    338 #ifdef BCM_TRIDENT3_SUPPORT
    339             if (SOC_IS_TRIDENT3X(unit)) {
    340                 /* TD3 is different from previous chips. 0 in KEY_TYPE was used to distinguish regular from extended
    341                  * entries in previous chips. In TD3 DATA_TYPE is 1 for extended entries 
    342                  */
    343                 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf, TD3_L3_HASH_KEY_TYPE_V4UC_EXT);
    344                 if (soc_mem_field_valid(unit, mem, DATA_TYPEf)) {
    345                 soc_mem_field32_set(unit, mem, buf_p, DATA_TYPEf, TD3_L3_HASH_DATA_TYPE_V4UC_EXT);
    346                 }
    347                 base_valid0 = 1;
    348                 if (SOC_IS_TOMAHAWK3(unit)) {
    349                     base_valid1 = 2;
    350                 } else {
    351                     base_valid1 = 7;
    352                 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_1f, 7); 
    353                 }
    354                 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_1f, base_valid1);
    355                 soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_0f, base_valid0);
    356             } else
    357 #endif
    358             {
    359             soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_0f, 1);
    360             soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_1f, 1);
    361             soc_mem_field32_set(unit, mem, buf_p, VALID_1f, 1); 
    362             soc_mem_field32_set(unit, mem, buf_p, VALID_0f, 1); 
    363             }
    364         } else {
    365             return BCM_E_NOT_FOUND;
    366         }
    367     }
    368     return BCM_E_NONE;
    369 }
    370 
    371 /*----- STATIC FUNCS ----- */
    372 /*
    373  * Function:
    374  *      _bcm_td2_l3_ent_parse
    375  * Purpose:
    376  *      TD2 helper routine used to parse hw l3 entry to api format.
    377  * Parameters:
    378  *      unit      - (IN) SOC unit number. 
    379  *      mem       - (IN) L3 table memory.
    380  *      l3cfg     - (IN/OUT) l3 entry key & parse result.
    381  *      nh_idx    - (IN/OUT) Next hop index. 
    382  *      l3x_entry - (IN) hw buffer.
    383  * Returns:
    384  *      void
    385  */
    386 STATIC int
    387 _bcm_td2_l3_ent_parse(int unit, soc_mem_t mem, _bcm_l3_cfg_t *l3cfg,
    388                                         int *nh_idx, void *l3x_entry, int key_type)
    389 {
    390     int ipv6;                     /* Entry is IPv6 flag.         */
    391     uint32 hit = 0;               /* composite hit = hit_x|hit_y */
    392     uint32 *buf_p;                /* HW buffer address.          */
    393     uint32 glp;                   /* Global port. */
    394     _bcm_l3_fields_t *fld;        /* L3 table common fields.     */
    395     int embedded_nh = FALSE;
    396     l3_entry_hit_only_x_entry_t hit_x;
    397     l3_entry_hit_only_y_entry_t hit_y;
    398     l3_entry_hit_only_entry_t hit_default;
    399     int idx, idx_max, idx_offset, hit_idx_shift;
    400     soc_field_t hitf[] = { HIT_0f, HIT_1f, HIT_2f, HIT_3f};
    401 
    402     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
    403     buf_p = (uint32 *)l3x_entry;
    404 
    405 #ifdef BCM_TRIDENT3_SUPPORT
    406     if (soc_feature(unit, soc_feature_flex_flow) &&
    407         l3cfg->l3c_flow_handle != 0) {
    408 
    409         return _bcm_td3_l3_flex_ent_parse(unit, mem, l3cfg, nh_idx, l3x_entry);
    410     }
    411 #endif
    412 
    413     /*
    414      * Set table fields 
    415      */
    416 #ifdef BCM_TOMAHAWK3_SUPPORT
    417     if (SOC_IS_TOMAHAWK3(unit))
    418     {
    419         BCM_TH3_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
    420         /*
    421          * Check if embedded NH table is being used 
    422          */
    423         embedded_nh = 0;
    424 
    425     } else
    426 #endif
    427 #ifdef BCM_TRIDENT3_SUPPORT
    428     if (SOC_IS_TRIDENT3X(unit)) {
    429         BCM_TD3_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);  
    430         /* Check if embedded NH table is being used */
    431         embedded_nh = (mem == L3_ENTRY_DOUBLEm && !ipv6) || 
    432                       (mem == L3_ENTRY_QUADm && ipv6);
    433 
    434     } else 
    435 #endif
    436     {
    437     BCM_TD2_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);  
    438     /* Check if embedded NH table is being used */
    439     embedded_nh = (mem == L3_ENTRY_IPV4_MULTICASTm && !ipv6) || 
    440                   (mem == L3_ENTRY_IPV6_MULTICASTm && ipv6);
    441 
    442     }
    443 
    444     /* Reset entry flags */
    445     l3cfg->l3c_flags = (ipv6) ? BCM_L3_IP6 : 0;
    446 
    447     idx_max = 1;
    448     idx_offset = (l3cfg->l3c_hw_index & 0x3);
    449     hit_idx_shift = 2;
    450     if (mem == L3_ENTRY_IPV4_MULTICASTm || 
    451         mem == L3_ENTRY_IPV6_UNICASTm ||
    452         (mem == L3_ENTRY_DOUBLEm)) {
    453         idx_max = 2;
    454         hit_idx_shift = 1;
    455         idx_offset = (l3cfg->l3c_hw_index & 0x1) << 1;
    456     } else if ((mem == L3_ENTRY_IPV6_MULTICASTm) ||
    457                (mem == L3_ENTRY_QUADm)) {
    458         idx_max = 4;
    459         hit_idx_shift = 0;
    460         idx_offset = 0;
    461     }
    462 
    463     if (soc_feature(unit, soc_feature_multi_pipe_mapped_ports)) {
    464         /* SOC_IS_TOMAHAWKX(unit) */
    465         /* Get info from L3 and next hop table */
    466         BCM_IF_ERROR_RETURN(
    467             BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLYm,
    468               (l3cfg->l3c_hw_index >> hit_idx_shift), &hit_x));
    469 
    470         hit = 0;
    471         for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) {
    472             hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLYm,
    473                                        &hit_x, hitf[idx]);
    474         }
    475     } else if (soc_feature(unit, soc_feature_two_ingress_pipes)) {
    476         /* Get info from L3 and next hop table */
    477         BCM_IF_ERROR_RETURN(
    478             BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLY_Xm,
    479               (l3cfg->l3c_hw_index >> hit_idx_shift), &hit_x));
    480 
    481         BCM_IF_ERROR_RETURN(
    482             BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLY_Ym,
    483               (l3cfg->l3c_hw_index >> hit_idx_shift), &hit_y));
    484 
    485         hit = 0;
    486         for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) {
    487             hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLY_Xm,
    488                                        &hit_x, hitf[idx]);
    489         }
    490 
    491         for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) {
    492             hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLY_Ym,
    493                                        &hit_y, hitf[idx]);
    494         }
    495     } else {
    496         /* Get info from L3 and next hop table */
    497         BCM_IF_ERROR_RETURN(
    498             BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLYm,
    499               (l3cfg->l3c_hw_index >> hit_idx_shift), &hit_default));
    500 
    501         hit = 0;
    502         for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) {
    503             hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLYm,
    504                                        &hit_default, hitf[idx]);
    505         }
    506     }
    507 
    508     soc_mem_field32_set(unit, mem, buf_p, fld->hit, hit);
    509 
    510     if (hit) {
    511         l3cfg->l3c_flags |= BCM_L3_HIT;
    512     }
    513     /* Get priority override flag. */
    514     if (soc_mem_field32_get(unit, mem, buf_p, fld->rpe)) {
    515         l3cfg->l3c_flags |= BCM_L3_RPE;
    516     }
    517 
    518     /* Get destination discard flag. */
    519     if (soc_mem_field32_get(unit, mem, buf_p, fld->dst_discard)) {
    520         l3cfg->l3c_flags |= BCM_L3_DST_DISCARD;
    521     }
    522 
    523     /* Get local addr bit. */
    524     if (soc_mem_field32_get(unit, mem, buf_p, fld->local_addr)) {
    525         l3cfg->l3c_flags |= BCM_L3_HOST_LOCAL;
    526     }
    527 
    528 #ifdef BCM_MONTEREY_SUPPORT
    529     /* Get Roe Header Decap Control */
    530     if (soc_feature(unit, soc_feature_roe) ||
    531         soc_feature(unit, soc_feature_roe_custom)) {
    532         if (soc_mem_field32_get(unit, mem, buf_p, fld->roe_decap)) {
    533             l3cfg->l3c_flags2 |= BCM_L3_FLAGS2_DECAP_ROE_HEADER;
    534         }
    535     }
    536 #endif
    537 
    538     /* Get classification group id. */
    539     l3cfg->l3c_lookup_class = 
    540         soc_mem_field32_get(unit, mem, buf_p, fld->class_id);
    541 
    542     /* Get priority. */
    543     l3cfg->l3c_prio = soc_mem_field32_get(unit, mem, buf_p, fld->priority);
    544 
    545     /* Get virtual router id. */
    546     l3cfg->l3c_vrf = soc_mem_field32_get(unit, mem, buf_p, fld->vrf);
    547 
    548     if (embedded_nh) {
    549         uint32 port_addr_max = 0, modid_max  = 0;
    550 #ifdef BCM_RIOT_SUPPORT
    551         int dest_type = 0, dvp = -1;
    552 #endif
    553 
    554         l3cfg->l3c_flags |= BCM_L3_DEREFERENCED_NEXTHOP;
    555         if (nh_idx) {
    556             *nh_idx = BCM_XGS3_L3_INVALID_INDEX; /* Embedded NH */
    557         }
    558         l3cfg->l3c_intf = soc_mem_field32_get(unit, mem, buf_p,
    559                                            fld->l3_intf);
    560 #ifdef BCM_TOMAHAWK_SUPPORT
    561         if (BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) {
    562             BCM_IF_ERROR_RETURN
    563                 (_bcm_th_l3_vp_ent_parse(unit, mem, l3cfg, buf_p));
    564         } else
    565 #endif
    566         {
    567 #if defined(BCM_RIOT_SUPPORT)
    568             if ((soc_feature(unit, soc_feature_riot)) &&
    569                 (_bcm_vp_is_vfi_type(unit, l3cfg->l3c_port_tgid))) {
    570                 /* Derive MAC address using profile table */
    571                 BCM_IF_ERROR_RETURN
    572                     (_bcm_td2p_l3_macda_oui_profile_entry_parse(unit, mem, l3cfg, buf_p));
    573             } else
    574 #endif
    575             {
    576                 soc_mem_mac_addr_get(unit, mem, buf_p,
    577                                     fld->mac_addr, l3cfg->l3c_mac_addr);
    578             }
    579             
    580 #ifdef BCM_TRIDENT3_SUPPORT
    581             if (SOC_IS_TRIDENT3X(unit)) {
    582                 uint32 dtype;
    583                 glp = soc_mem_field32_dest_get(unit, mem, buf_p, fld->dest, &dtype);
    584                 dest_type = dtype;
    585             } else
    586 #endif
    587             {
    588             glp = soc_mem_field32_get(unit, mem, buf_p, fld->glp);
    589             }
    590 
    591             port_addr_max = SOC_PORT_ADDR_MAX(unit) + 1;
    592             modid_max = SOC_MODID_MAX(unit) + 1;
    593 
    594 #ifdef BCM_RIOT_SUPPORT
    595             if (BCMI_RIOT_IS_ENABLED(unit)) {
    596                 if (SOC_IS_TRIDENT3X(unit)) {
    597                     if (dest_type == SOC_MEM_FIF_DEST_DVP) {
    598                         dvp = glp; /*glp already holds the DEST value from earlier call */
    599                         _bcm_vp_encode_gport(unit, dvp, &(l3cfg->l3c_port_tgid));
    600                         l3cfg->l3c_modid = 0;
    601                     }
    602                 } else {
    603 
    604                 dest_type = soc_mem_field32_get(unit, mem, buf_p, fld->dest_type);
    605                 if (dest_type == 1) {
    606                     dvp = soc_mem_field32_get(unit, mem, buf_p, fld->destination);
    607                     _bcm_vp_encode_gport(unit, dvp, &(l3cfg->l3c_port_tgid));
    608                     l3cfg->l3c_modid = 0;
    609                 }
    610             }
    611             }
    612             if (dvp == -1)
    613 #endif
    614             {
    615                 if ((glp & (port_addr_max * modid_max))
    616 #if defined(BCM_TRIDENT3_SUPPORT)
    617                     || (SOC_IS_TRIDENT3X(unit) && (dest_type == SOC_MEM_FIF_DEST_LAG))
    618 #endif
    619                     ) {
    620                     l3cfg->l3c_flags |= BCM_L3_TGID;
    621                     l3cfg->l3c_port_tgid = glp & BCM_TGID_PORT_TRUNK_MASK(unit);
    622                     l3cfg->l3c_modid = 0;
    623                 } else {
    624                     l3cfg->l3c_port_tgid = glp & SOC_PORT_ADDR_MAX(unit);
    625                     l3cfg->l3c_modid = (glp / port_addr_max) & SOC_MODID_MAX(unit);
    626                 }
    627             }
    628 
    629         }
    630         l3cfg->l3c_eh_q_tag_type = soc_mem_field32_get(unit, mem, buf_p, 
    631                                                        fld->eh_tag_type);
    632         l3cfg->l3c_eh_q_tag = soc_mem_field32_get(unit, mem, buf_p,
    633                                                   fld->eh_queue_tag);
    634         /* Get copy_to_cpu bit. */
    635         if (SOC_MEM_FIELD_VALID(unit, mem, fld->copy_to_cpu)) {
    636             if (soc_mem_field32_get(unit, mem, buf_p, fld->copy_to_cpu)) {
    637                 l3cfg->l3c_flags |= BCM_L3_COPY_TO_CPU;
    638             }
    639         }
    640     } else {
    641         /* Get next hop info. */
    642         if (nh_idx) {
    643 #ifdef BCM_TRIDENT3_SUPPORT
    644             if (SOC_IS_TRIDENT3X(unit)) {
    645                     uint32 dest_type;
    646                     *nh_idx = soc_mem_field32_dest_get(unit, mem, buf_p, fld->dest, &dest_type);
    647                     if (dest_type != SOC_MEM_FIF_DEST_NEXTHOP) {
    648                         /* Mark entry as ecmp */
    649                         l3cfg->l3c_ecmp = TRUE;
    650                         l3cfg->l3c_flags |= BCM_L3_MULTIPATH;
    651                     }
    652             } else
    653 #endif
    654             {
    655             *nh_idx = soc_mem_field32_get(unit, mem, buf_p, fld->nh_idx);
    656                 if (soc_mem_field32_get(unit, mem, buf_p, ECMPf)) {
    657                 /* Mark entry as ecmp */
    658                 l3cfg->l3c_ecmp = TRUE;
    659                 l3cfg->l3c_flags |= BCM_L3_MULTIPATH;
    660         }
    661             }
    662         }
    663 #ifdef BCM_TRIDENT3_SUPPORT
    664         if (!SOC_IS_TRIDENT3X(unit)) {
    665 #endif
    666         if (soc_mem_field32_get(unit, mem, buf_p, ECMPf)) {
    667             /* Mark entry as ecmp */
    668             l3cfg->l3c_ecmp  = TRUE;
    669             l3cfg->l3c_flags |= BCM_L3_MULTIPATH;
    670         } else {
    671             l3cfg->l3c_ecmp  = FALSE;
    672             l3cfg->l3c_flags &= ~BCM_L3_MULTIPATH;
    673         }
    674 #ifdef BCM_TRIDENT3_SUPPORT
    675         }
    676 #endif
    677     }
    678 
    679     return BCM_E_NONE;
    680 }
    681 
    682 /*
    683  * Function:
    684  *      _bcm_td2_l3_clear_hit
    685  * Purpose:
    686  *      Clear hit bit on l3 entry
    687  * Parameters:
    688  *      unit      - (IN)SOC unit number.
    689  *      mem       - (IN)L3 table memory.
    690  *      l3cfg     - (IN)l3 entry info. 
    691  *      l3x_entry - (IN)l3 entry filled hw buffer.
    692  * Returns:
    693  *      BCM_E_XXX
    694  */
    695 STATIC int
    696 _bcm_td2_l3_clear_hit(int unit, soc_mem_t mem, _bcm_l3_cfg_t *l3cfg,
    697                                    void *l3x_entry, int l3_entry_idx)
    698 {
    699     int ipv6;                     /* Entry is IPv6 flag.      */
    700     int mcast;                    /* Entry is multicast flag. */ 
    701     uint32 *buf_p;                /* HW buffer address.       */ 
    702     _bcm_l3_fields_t *fld;        /* L3 table common fields.  */
    703     soc_field_t hitf[] = { HIT_0f, HIT_1f, HIT_2f, HIT_3f };
    704     int idx;
    705 
    706     /* Input parameters check */
    707     if ((NULL == l3cfg) || (NULL == l3x_entry)) {
    708         return (BCM_E_PARAM);
    709     }
    710 
    711     /* Get entry type. */
    712     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
    713     mcast = (l3cfg->l3c_flags & BCM_L3_IPMC);
    714 
    715     /* Set table fields */
    716 #ifdef BCM_TOMAHAWK3_SUPPORT
    717     if (SOC_IS_TOMAHAWK3(unit)) {
    718         BCM_TH3_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
    719     } else
    720 #endif
    721     if (SOC_IS_TRIDENT3X(unit)) {
    722         BCM_TD3_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
    723     } else {
    724     BCM_TD2_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
    725     }
    726 
    727     /* Init memory pointers. */ 
    728     buf_p = (uint32 *)l3x_entry;
    729 
    730     /* If entry was not hit  there is nothing to clear */
    731     if (!(l3cfg->l3c_flags & BCM_L3_HIT)) {
    732         return (BCM_E_NONE);
    733     }
    734 
    735     /* Reset hit bit. */
    736     soc_mem_field32_set(unit, mem, buf_p, fld->hit, 0);
    737 
    738     if (ipv6 && mcast) {
    739         /* IPV6 multicast entry hit reset. */
    740         for (idx = 0; idx < 4; idx++) {
    741             soc_mem_field32_set(unit, mem, buf_p, hitf[idx], 0);
    742         }
    743     } else if (ipv6 || mcast) {
    744         /* Reset IPV6 unicast and IPV4 multicast hit bits. */
    745         for (idx = 0; idx < 2; idx++) {
    746             soc_mem_field32_set(unit, mem, buf_p, hitf[idx], 0);
    747         }
    748     }
    749 
    750     /* Write entry back to hw. */
    751     return BCM_XGS3_MEM_WRITE(unit, mem, l3_entry_idx, buf_p);
    752 }
    753 
    754 /*
    755  * Function:
    756  *      _bcm_td2_l3_entry_add
    757  * Purpose:
    758  *      Add and entry to TD2 L3 host table.
    759  * Parameters:
    760  *      unit   - (IN) SOC unit number.
    761  *      l3cfg  - (IN) L3 entry info.
    762  *      nh_idx - (IN) Next hop index.
    763  * Returns:
    764  *      BCM_E_XXX
    765  */
    766 STATIC int
    767 _bcm_td2_l3_entry_add(int unit, _bcm_l3_cfg_t *l3cfg, int nh_idx)
    768 {
    769 
    770     int ipv6;
    771     uint32 *bufp;             /* Hardware buffer ptr     */
    772     soc_mem_t mem;            /* L3 table memory.        */  
    773     int rv = BCM_E_NONE;      /* Operation status.       */
    774     _bcm_l3_fields_t *fld;    /* L3 table common fields. */
    775     int embedded_nh = FALSE;
    776     uint32 glp = 0, port_id = 0, modid = 0;
    777     _bcm_l3_intf_cfg_t l3_intf;
    778     l3_entry_ipv4_unicast_entry_t l3v4_entry;       /* IPv4 */
    779     l3_entry_ipv4_multicast_entry_t l3v4_ext_entry;   /* IPv4-Embedded */
    780     l3_entry_ipv6_unicast_entry_t l3v6_entry;       /* IPv6 */
    781     l3_entry_ipv6_multicast_entry_t l3v6_ext_entry;   /* IPv6-Embedded */
    782     uint32 port_addr_max = 0, modid_max  = 0;
    783 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_RIOT_SUPPORT)
    784     int macda_oui_profile_index = -1;
    785 #endif
    786 #ifdef BCM_TOMAHAWK_SUPPORT
    787     int macda_oui_profile_index1 = -1;
    788     int vntag_etag_profile_index = 0;
    789     int vntag_etag_profile_index1 = 0;
    790     int ref_count = 0;
    791 #endif
    792 #ifdef BCM_RIOT_SUPPORT
    793     int dvp = -1;
    794 #endif
    795 
    796     /* Get entry type. */
    797     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
    798 
    799     /* Check if embedded NH table is being used */
    800     embedded_nh = BCM_TD2_L3_USE_EMBEDDED_NEXT_HOP(unit, l3cfg->l3c_intf, nh_idx);
    801 #ifdef BCM_TOMAHAWK3_SUPPORT
    802     if (SOC_IS_TOMAHAWK3(unit))
    803     {
    804         int ipmc = 0;
    805         ipmc = (l3cfg->l3c_flags & BCM_L3_IPMC);
    806         /*
    807          * Get table memory. 
    808          */
    809         BCM_TH3_L3_HOST_TABLE_MEM(unit, l3cfg->l3c_intf, ipv6, ipmc, mem, nh_idx);
    810 
    811         /*
    812          * Set table fields 
    813          */
    814         BCM_TH3_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
    815 
    816         /*
    817          * Assign entry buf based on table being used 
    818          */
    819         BCM_TH3_L3_HOST_ENTRY_BUF(ipv6, mem, bufp, l3v4_entry, l3v4_ext_entry, l3v6_entry, l3v6_ext_entry);
    820     }
    821     else
    822 #endif
    823 #ifdef BCM_TRIDENT3_SUPPORT
    824     if (SOC_IS_TRIDENT3X(unit))
    825     {
    826     if (soc_feature(unit, soc_feature_flex_flow) &&
    827         (l3cfg->l3c_flow_handle != 0)) {
    828 
    829         return _bcm_td3_l3_flex_entry_add(unit, l3cfg, nh_idx);
    830     }
    831 
    832         /* Get table memory. */
    833         BCM_TD3_L3_HOST_TABLE_MEM(unit, l3cfg->l3c_intf, ipv6, mem, nh_idx);
    834     
    835         /* Set table fields */
    836         BCM_TD3_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
    837 
    838         /* Assign entry buf based on table being used */
    839         BCM_TD3_L3_HOST_ENTRY_BUF(ipv6, mem, bufp,
    840                                       l3v4_entry,
    841                                       l3v4_ext_entry,
    842                                       l3v6_entry,
    843                                       l3v6_ext_entry);
    844     } else 
    845 #endif
    846     {
    847     /* Get table memory. */
    848     BCM_TD2_L3_HOST_TABLE_MEM(unit, l3cfg->l3c_intf, ipv6, mem, nh_idx);
    849 
    850     /* Set table fields */
    851     BCM_TD2_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
    852 
    853     /* Assign entry buf based on table being used */
    854     BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem, bufp,
    855                                   l3v4_entry,
    856                                   l3v4_ext_entry,
    857                                   l3v6_entry,
    858                                   l3v6_ext_entry);
    859     }
    860     /* Prepare host entry for addition. */
    861     BCM_IF_ERROR_RETURN(_bcm_td2_l3_ent_init(unit, mem, l3cfg, bufp));
    862 
    863     /* Set hit bit. */
    864     if (l3cfg->l3c_flags & BCM_L3_HIT) {
    865         soc_mem_field32_set(unit, mem, bufp, fld->hit, 1);
    866     }
    867 
    868     /* Set priority override bit. */
    869     if (l3cfg->l3c_flags & BCM_L3_RPE) {
    870         soc_mem_field32_set(unit, mem, bufp, fld->rpe, 1);
    871     }
    872 
    873     /* Set destination discard bit. */
    874     if (l3cfg->l3c_flags & BCM_L3_DST_DISCARD) {
    875         soc_mem_field32_set(unit, mem, bufp, fld->dst_discard, 1);
    876     }
    877 
    878     /* Set local addr bit. */
    879     if (l3cfg->l3c_flags & BCM_L3_HOST_LOCAL) {
    880         soc_mem_field32_set(unit, mem, bufp, fld->local_addr, 1);
    881     }
    882 
    883 #ifdef BCM_MONTEREY_SUPPORT
    884     /* Set Roe Header Decap control */
    885     if (soc_feature(unit, soc_feature_roe) ||
    886             soc_feature(unit, soc_feature_roe_custom)) {
    887         if (l3cfg->l3c_flags2 & BCM_L3_FLAGS2_DECAP_ROE_HEADER) {
    888             soc_mem_field32_set(unit, mem, bufp, fld->roe_decap, 1);
    889         }
    890     }
    891 #endif
    892 
    893     /* Set classification group id. */
    894     soc_mem_field32_set(unit, mem, bufp, fld->class_id, 
    895                         l3cfg->l3c_lookup_class);
    896     /*  Set priority. */
    897     soc_mem_field32_set(unit, mem, bufp, fld->priority, l3cfg->l3c_prio);
    898 
    899     if (embedded_nh) {
    900         sal_memset(&l3_intf, 0, sizeof(_bcm_l3_intf_cfg_t));
    901         BCM_XGS3_L3_INTF_IDX_SET(l3_intf, l3cfg->l3c_intf);
    902 
    903         BCM_XGS3_L3_MODULE_LOCK(unit);
    904         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, &l3_intf);
    905         BCM_XGS3_L3_MODULE_UNLOCK(unit);
    906 
    907         port_addr_max = SOC_PORT_ADDR_MAX(unit) + 1;
    908         modid_max = SOC_MODID_MAX(unit) + 1;
    909 #ifdef BCM_RIOT_SUPPORT
    910         if ((BCMI_RIOT_IS_ENABLED(unit))
    911             && (_bcm_vp_is_vfi_type(unit, l3cfg->l3c_port_tgid))) {
    912             _bcm_vp_vfi_type_vp_get(unit, l3cfg->l3c_port_tgid, &dvp);
    913         } else
    914 #endif
    915         {
    916             if (l3cfg->l3c_flags & BCM_L3_TGID) {
    917                 glp = (BCM_TGID_PORT_TRUNK_MASK(unit) & l3cfg->l3c_port_tgid);
    918 #if defined(BCM_TRIDENT3_SUPPORT)
    919                 if (!SOC_IS_TRIDENT3X(unit)) {
    920                     glp |= (port_addr_max * modid_max);
    921                 }
    922 #else
    923                     glp |= (port_addr_max * modid_max);
    924 #endif
    925             } else {
    926                 port_id = (SOC_PORT_ADDR_MAX(unit) & l3cfg->l3c_port_tgid);
    927                 modid = (SOC_MODID_MAX(unit) & l3cfg->l3c_modid) * port_addr_max;
    928                 glp = modid | port_id;
    929             }
    930         }
    931         soc_mem_field32_set(unit, mem, bufp, fld->l3_intf, l3cfg->l3c_intf);
    932 #ifdef BCM_TRIDENT3_SUPPORT
    933     if (SOC_IS_TRIDENT3X(unit)) {
    934         if (dvp != -1) {
    935             soc_mem_field32_dest_set(unit, mem, bufp, fld->dest, 
    936                                      SOC_MEM_FIF_DEST_DVP, dvp);
    937         } else {
    938             uint32 dest_type;
    939             if (l3cfg->l3c_flags & BCM_L3_TGID) {
    940                 dest_type = SOC_MEM_FIF_DEST_LAG;
    941             } else {
    942                 dest_type = SOC_MEM_FIF_DEST_DGPP;
    943             }
    944             soc_mem_field32_dest_set(unit, mem, bufp, fld->dest, 
    945                                      dest_type, glp);
    946         }
    947     } else
    948 #endif
    949     {
    950 #ifdef BCM_RIOT_SUPPORT
    951         if (dvp != -1) {
    952             soc_mem_field32_set(unit, mem, bufp, fld->dest_type, 1);
    953             soc_mem_field32_set(unit, mem, bufp, fld->destination, dvp);
    954         } else
    955 #endif
    956         {
    957             soc_mem_field32_set(unit, mem, bufp, fld->glp, glp);
    958         }
    959     }
    960 #ifdef BCM_TOMAHAWK_SUPPORT
    961         if (BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) {
    962             if (l3cfg->l3c_flags & BCM_L3_REPLACE) {
    963                 /* For BCM_L3_REPLACE, get profile index for EGR_MACDA_OUI_PROFILE
    964                  * and EGR_VNTAG_ETAG_PROFILE table. Delete the profile entry if
    965                  * it's not used by any other host.
    966                  */
    967                 rv = _bcm_th_get_extended_profile_index(unit, mem, l3cfg,
    968                                                     &macda_oui_profile_index,
    969                                                     &vntag_etag_profile_index,
    970                                                     &ref_count);
    971                 if (BCM_FAILURE(rv) && (rv!=BCM_E_NOT_FOUND)) {
    972                     return rv;
    973                 }
    974                 if (macda_oui_profile_index == -1) {
    975                     /* Host entry was done in regular L3_ENTRY table view */
    976                     BCM_IF_ERROR_RETURN
    977                     (_bcm_th_l3_vp_entry_add(unit, mem, l3cfg, bufp,
    978                                              &macda_oui_profile_index1,
    979                                              &vntag_etag_profile_index1));
    980                 } else {                                
    981                     if (ref_count > 1) {
    982                         rv = _bcm_th_l3_vp_entry_add(unit, mem, l3cfg, bufp,
    983                                                      &macda_oui_profile_index1,
    984                                                      &vntag_etag_profile_index1);
    985                         if (BCM_SUCCESS(rv)) {
    986                             BCM_IF_ERROR_RETURN
    987                             (_bcm_th_l3_vp_entry_del(unit, l3cfg, 
    988                                                     macda_oui_profile_index,
    989                                                     vntag_etag_profile_index));
    990                         } else {
    991                             return rv;
    992                         }
    993                     } else {
    994                         BCM_IF_ERROR_RETURN
    995                         (_bcm_th_l3_vp_entry_del(unit, l3cfg,
    996                                                 macda_oui_profile_index,
    997                                                 vntag_etag_profile_index));
    998                         BCM_IF_ERROR_RETURN
    999                         (_bcm_th_l3_vp_entry_add(unit, mem, l3cfg, bufp,
   1000                                                  &macda_oui_profile_index1,
   1001                                                  &vntag_etag_profile_index1));
   1002 
   1003                     }
   1004                 }
   1005 
   1006             } else {
   1007                 BCM_IF_ERROR_RETURN
   1008                 (_bcm_th_l3_vp_entry_add(unit, mem, l3cfg, bufp,
   1009                                          &macda_oui_profile_index1,
   1010                                          &vntag_etag_profile_index1));
   1011 
   1012             }
   1013 
   1014         } else
   1015 #endif
   1016 #if defined(BCM_RIOT_SUPPORT)
   1017         if ((soc_feature(unit, soc_feature_riot)) &&
   1018             (_bcm_vp_is_vfi_type(unit, l3cfg->l3c_port_tgid))) {
   1019             if (l3cfg->l3c_flags & BCM_L3_REPLACE) {
   1020                 BCM_IF_ERROR_RETURN
   1021                     (_bcm_td2p_l3_macda_oui_profile_entry_replace(unit, mem, l3cfg, bufp));
   1022             } else {
   1023                 BCM_IF_ERROR_RETURN
   1024                     (_bcm_td2p_l3_macda_oui_profile_entry_add(unit, mem, l3cfg, bufp,
   1025                                                               &macda_oui_profile_index));
   1026             }
   1027         } else
   1028 #endif
   1029         {
   1030             soc_mem_mac_addr_set(unit, mem, bufp,
   1031                                 fld->mac_addr, l3cfg->l3c_mac_addr);
   1032         }
   1033         soc_mem_field32_set(unit, mem, bufp, 
   1034                             fld->eh_tag_type, l3cfg->l3c_eh_q_tag_type);
   1035         soc_mem_field32_set(unit, mem, bufp, 
   1036                             fld->eh_queue_tag, l3cfg->l3c_eh_q_tag);
   1037 
   1038         /* Set copy_to_cpu bit. */
   1039         if (l3cfg->l3c_flags & BCM_L3_COPY_TO_CPU) {
   1040             if (SOC_MEM_FIELD_VALID(unit, mem, fld->copy_to_cpu)) {
   1041                 soc_mem_field32_set(unit, mem, bufp, fld->copy_to_cpu, 1);
   1042             }
   1043         }
   1044     } else {
   1045         /* Set next hop index. */
   1046         if (l3cfg->l3c_flags & BCM_L3_MULTIPATH) {
   1047 #ifdef BCM_TRIDENT3_SUPPORT
   1048             if (SOC_IS_TRIDENT3X(unit)) {
   1049                 soc_mem_field32_dest_set(unit, mem, bufp, fld->dest,
   1050                                         SOC_MEM_FIF_DEST_ECMP, nh_idx);
   1051             } else
   1052 #endif
   1053             {
   1054 
   1055             soc_mem_field32_set(unit, mem, bufp, ECMP_PTRf, nh_idx);
   1056             soc_mem_field32_set(unit, mem, bufp, ECMPf, 1);
   1057             }
   1058         } else {
   1059 #ifdef BCM_TRIDENT3_SUPPORT
   1060             if (SOC_IS_TRIDENT3X(unit)) {
   1061                soc_mem_field32_dest_set(unit, mem, bufp, fld->dest, 
   1062                                         SOC_MEM_FIF_DEST_NEXTHOP, nh_idx);
   1063             } else
   1064 #endif
   1065             {
   1066             soc_mem_field32_set(unit, mem, bufp, fld->nh_idx, nh_idx);
   1067         }
   1068     }
   1069     }
   1070 
   1071     /* Insert in table */
   1072     rv = soc_mem_insert(unit, mem, MEM_BLOCK_ANY, bufp);
   1073 
   1074     /* Handle host entry 'replace' actions */
   1075     if ((BCM_E_EXISTS == rv) && (l3cfg->l3c_flags & BCM_L3_REPLACE)) {
   1076         rv = BCM_E_NONE;
   1077     }
   1078 
   1079 
   1080 #ifdef BCM_TOMAHAWK_SUPPORT
   1081     if (BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) {
   1082         if (BCM_FAILURE(rv)) {
   1083             /* if host add is not successful, then corresponding entries in the
   1084              * profile table need to be removed for extended view hosts.
   1085              */
   1086             BCM_IF_ERROR_RETURN
   1087             (_bcm_th_l3_vp_entry_del(unit, l3cfg,
   1088                                      macda_oui_profile_index1,
   1089                                      vntag_etag_profile_index1));
   1090         }
   1091     }
   1092 #endif
   1093 #if defined(BCM_RIOT_SUPPORT)
   1094     if ((soc_feature(unit, soc_feature_riot)) &&
   1095         (_bcm_vp_is_vfi_type(unit, l3cfg->l3c_port_tgid))) {
   1096         if (BCM_FAILURE(rv)) {
   1097             /* if host add is not successful, then corresponding entries in the
   1098              * profile table need to be removed for extended view hosts.
   1099              */
   1100             BCM_IF_ERROR_RETURN
   1101                 (_bcm_td2p_l3_macda_oui_profile_entry_del(unit, l3cfg, macda_oui_profile_index));
   1102         }
   1103     }
   1104 #endif /* BCM_RIOT_SUPPORT */
   1105 
   1106     /* Write status check. */
   1107     if ((rv >= 0) && (BCM_XGS3_L3_INVALID_INDEX == l3cfg->l3c_hw_index)) {
   1108         (ipv6) ?  BCM_XGS3_L3_IP6_CNT(unit)++ : BCM_XGS3_L3_IP4_CNT(unit)++;
   1109     }
   1110 
   1111     return rv;
   1112 }
   1113 
   1114 
   1115 /*
   1116  * Function:
   1117  *      _bcm_td2_l3_entry_get
   1118  * Purpose:
   1119  *      Get an entry from TD2 3 host table.
   1120  * Parameters:
   1121  *      unit     - (IN) SOC unit number.
   1122  *      l3cfg    - (IN/OUT) L3 entry  lookup key & search result.
   1123  *      nh_index - (IN/OUT) Next hop index.
   1124  *      embd     - (OUT) If TRUE, entry was found as embedded NH.
   1125  * Returns:
   1126  *      BCM_E_XXX
   1127  */
   1128 STATIC int
   1129 _bcm_td2_l3_entry_get(int unit, _bcm_l3_cfg_t *l3cfg, int *nh_idx, int *embd)
   1130 {
   1131     int ipv6;                                   /* IPv6 entry indicator.    */
   1132     int clear_hit;                              /* Clear hit bit.           */
   1133     int rv = BCM_E_NONE;                        /* Operation return status. */
   1134     soc_mem_t mem, mem_ext;                     /* L3 table memories        */
   1135     uint32 *buf_key, *buf_entry;                /* Key and entry buffer ptrs*/
   1136     l3_entry_ipv4_unicast_entry_t l3v4_key, l3v4_entry;       /* IPv4 */
   1137     l3_entry_ipv4_multicast_entry_t l3v4_ext_key, l3v4_ext_entry;   /* IPv4-Embedded */
   1138     l3_entry_ipv6_unicast_entry_t l3v6_key, l3v6_entry;       /* IPv6 */
   1139     l3_entry_ipv6_multicast_entry_t l3v6_ext_key, l3v6_ext_entry;   /* IPv6-Embedded */
   1140 
   1141     /* Indexed NH entry */
   1142     *embd = _BCM_TD2_HOST_ENTRY_NOT_FOUND;
   1143 
   1144     /* Get entry type. */
   1145     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
   1146 
   1147     /* Preserve clear_hit value. */
   1148     clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR;
   1149 
   1150     /* Table memories */
   1151     if (ipv6) {
   1152         mem = BCM_XGS3_L3_MEM(unit, v6); mem_ext = BCM_XGS3_L3_MEM(unit, v6_4);
   1153     } else {
   1154         mem = BCM_XGS3_L3_MEM(unit, v4); mem_ext = BCM_XGS3_L3_MEM(unit, v4_2);
   1155     }
   1156 #ifdef BCM_TOMAHAWK3_SUPPORT
   1157     if (SOC_IS_TOMAHAWK3(unit)) {
   1158         /*
   1159          * Assign entry-key buf based on table being used 
   1160          */
   1161         BCM_TH3_L3_HOST_ENTRY_BUF(ipv6, mem, buf_key, l3v4_key, l3v4_ext_key, l3v6_key, l3v6_ext_key);
   1162 
   1163         /*
   1164          * Assign entry buf based on table being used 
   1165          */
   1166         BCM_TH3_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry, l3v4_entry, l3v4_ext_entry, l3v6_entry, l3v6_ext_entry);
   1167     } else
   1168 #endif
   1169 #ifdef BCM_TRIDENT3_SUPPORT
   1170     if (SOC_IS_TRIDENT3X(unit)) {
   1171     if (soc_feature(unit, soc_feature_flex_flow) &&
   1172         (l3cfg->l3c_flow_handle != 0)) {
   1173 
   1174         return _bcm_td3_l3_flex_entry_get(unit, l3cfg, nh_idx, embd);
   1175     }
   1176 
   1177          /* Assign entry-key buf based on table being used */
   1178         BCM_TD3_L3_HOST_ENTRY_BUF(ipv6, mem, buf_key,
   1179                                             l3v4_key,
   1180                                             l3v4_ext_key,
   1181                                             l3v6_key,
   1182                                             l3v6_ext_key);
   1183     
   1184         /* Assign entry buf based on table being used */
   1185         BCM_TD3_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry,
   1186                                             l3v4_entry,
   1187                                             l3v4_ext_entry,
   1188                                             l3v6_entry,
   1189                                             l3v6_ext_entry);
   1190     } else
   1191 #endif
   1192     {
   1193     /* Assign entry-key buf based on table being used */
   1194     BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem, buf_key,
   1195                                         l3v4_key,
   1196                                         l3v4_ext_key,
   1197                                         l3v6_key,
   1198                                         l3v6_ext_key);
   1199 
   1200     /* Assign entry buf based on table being used */
   1201     BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry,
   1202                                         l3v4_entry,
   1203                                         l3v4_ext_entry,
   1204                                         l3v6_entry,
   1205                                         l3v6_ext_entry);
   1206     }
   1207     /* Prepare lookup key. */
   1208     BCM_IF_ERROR_RETURN(_bcm_td2_l3_ent_init(unit, mem, l3cfg, buf_key));
   1209 
   1210     /* Perform lookup */
   1211     rv = soc_mem_generic_lookup(unit, mem, MEM_BLOCK_ANY,
   1212                                 _BCM_TD2_L3_MEM_BANKS_ALL,
   1213                                 buf_key, buf_entry, &l3cfg->l3c_hw_index);
   1214     if (BCM_SUCCESS(rv)) {
   1215         /* Indexed NH entry */
   1216         *embd = FALSE;
   1217         /* Extract entry info. */
   1218         BCM_IF_ERROR_RETURN(_bcm_td2_l3_ent_parse(unit, mem, l3cfg,
   1219                                                   nh_idx, buf_entry, 0));
   1220         /* Clear the HIT bit */
   1221         if (clear_hit) {
   1222             BCM_IF_ERROR_RETURN(_bcm_td2_l3_clear_hit(unit, mem,
   1223                                        l3cfg, buf_entry, l3cfg->l3c_hw_index));
   1224         }
   1225     } else if ((BCM_E_NOT_FOUND == rv) &&
   1226                (soc_feature(unit, soc_feature_l3_extended_host_entry))) {
   1227         /* Search in the extended tables only if the extended host entry
   1228          * feature is supported and if the entry was not found in the 
   1229          * regular host entry */
   1230 
   1231 #ifdef BCM_TOMAHAWK3_SUPPORT
   1232         if (SOC_IS_TOMAHAWK3(unit))
   1233         {
   1234             /*
   1235              * Assign entry-key buf based on table being used 
   1236              */
   1237             BCM_TH3_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_key, l3v4_key, l3v4_ext_key, l3v6_key, l3v6_ext_key);
   1238 
   1239             /*
   1240              * Assign entry buf based on table being used 
   1241              */
   1242             BCM_TH3_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_entry,
   1243                                       l3v4_entry, l3v4_ext_entry, l3v6_entry, l3v6_ext_entry);
   1244         }
   1245         else
   1246 #endif
   1247 #ifdef BCM_TRIDENT3_SUPPORT
   1248         if (SOC_IS_TRIDENT3X(unit))
   1249         {
   1250         /* Assign entry-key buf based on table being used */
   1251         BCM_TD3_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_key,
   1252                                         l3v4_key,
   1253                                         l3v4_ext_key,
   1254                                         l3v6_key,
   1255                                         l3v6_ext_key);
   1256 
   1257         /* Assign entry buf based on table being used */
   1258         BCM_TD3_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_entry,
   1259                                         l3v4_entry,
   1260                                         l3v4_ext_entry,
   1261                                         l3v6_entry,
   1262                                         l3v6_ext_entry);
   1263         } else
   1264 #endif
   1265         {
   1266         /* Assign entry-key buf based on table being used */
   1267         BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_key,
   1268                                         l3v4_key,
   1269                                         l3v4_ext_key,
   1270                                         l3v6_key,
   1271                                         l3v6_ext_key);
   1272 
   1273         /* Assign entry buf based on table being used */
   1274         BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_entry,
   1275                                         l3v4_entry,
   1276                                         l3v4_ext_entry,
   1277                                         l3v6_entry,
   1278                                         l3v6_ext_entry);
   1279 		}
   1280 
   1281         /* Prepare lookup key. */
   1282         BCM_IF_ERROR_RETURN(_bcm_td2_l3_ent_init(unit, mem_ext, l3cfg, buf_key));
   1283 
   1284         /* Perform lookup hw. */
   1285         rv = soc_mem_generic_lookup(unit, mem_ext, MEM_BLOCK_ANY,
   1286                                     _BCM_TD2_L3_MEM_BANKS_ALL,
   1287                                     buf_key, buf_entry, &l3cfg->l3c_hw_index);
   1288 
   1289         if (BCM_SUCCESS(rv)) {
   1290 
   1291             /* Embedded NH entry */
   1292             *embd = TRUE;
   1293             /* Extract entry info. */
   1294             BCM_IF_ERROR_RETURN(_bcm_td2_l3_ent_parse(unit, mem_ext, l3cfg,
   1295                                                           nh_idx, buf_entry, 0));
   1296             /* Clear the HIT bit */
   1297             if (clear_hit) {
   1298                 BCM_IF_ERROR_RETURN(_bcm_td2_l3_clear_hit(unit, mem_ext,
   1299                                               l3cfg, buf_entry, l3cfg->l3c_hw_index));
   1300             }
   1301         }
   1302     } 
   1303      
   1304     return rv;
   1305 }
   1306 
   1307 /*
   1308  * Function:
   1309  *      _bcm_td2_l3_entry_del
   1310  * Purpose:
   1311  *      Delete an entry from TD2 L3 host table.
   1312  * Parameters:
   1313  *      unit     - (IN) SOC unit number.
   1314  *      l3cfg    - (IN/OUT) L3 entry  lookup key & search result.
   1315  *      nh_index - (IN/OUT) Next hop index.
   1316  * Returns:
   1317  *      BCM_E_XXX
   1318  */
   1319 STATIC int
   1320 _bcm_td2_l3_entry_del(int unit, _bcm_l3_cfg_t *l3cfg)
   1321 {
   1322     int ipv6;                          /* IPv6 entry indicator.*/
   1323     soc_mem_t mem, mem_ext;            /* L3 table memory.     */  
   1324     int rv = BCM_E_NONE;               /* Operation status.    */
   1325     uint32 *buf_entry;                 /* Entry buffer ptrs    */
   1326     l3_entry_ipv4_unicast_entry_t l3v4_entry;       /* IPv4 */
   1327     l3_entry_ipv4_multicast_entry_t l3v4_ext_entry;   /* IPv4-Embedded */
   1328     l3_entry_ipv6_unicast_entry_t l3v6_entry;       /* IPv6 */
   1329     l3_entry_ipv6_multicast_entry_t l3v6_ext_entry;   /* IPv6-Embedded */
   1330 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_RIOT_SUPPORT)
   1331         int macda_oui_profile_index = -1;
   1332         int ref_count = 0;
   1333 #endif
   1334 
   1335 #ifdef BCM_TOMAHAWK_SUPPORT
   1336         int vntag_etag_profile_index = 0;
   1337 #endif
   1338 
   1339     /* Get entry type. */
   1340     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
   1341 
   1342     if (ipv6) {
   1343         mem = BCM_XGS3_L3_MEM(unit, v6); mem_ext = BCM_XGS3_L3_MEM(unit, v6_4);
   1344     } else {
   1345         mem = BCM_XGS3_L3_MEM(unit, v4); mem_ext = BCM_XGS3_L3_MEM(unit, v4_2);
   1346     }
   1347 
   1348 #ifdef BCM_TRIDENT3_SUPPORT
   1349     if (soc_feature(unit, soc_feature_flex_flow) &&
   1350         (l3cfg->l3c_flow_handle != 0)) {
   1351         return _bcm_td3_l3_flex_entry_del(unit, l3cfg);
   1352     }
   1353     /* Assign entry-key buf based on table being used */
   1354     if (SOC_IS_TRIDENT3X(unit)) {
   1355         BCM_TD3_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry,
   1356                                             l3v4_entry,
   1357                                             l3v4_ext_entry,
   1358                                             l3v6_entry,
   1359                                             l3v6_ext_entry);
   1360     } else
   1361 #endif
   1362     {
   1363         BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry,
   1364                                         l3v4_entry,
   1365                                         l3v4_ext_entry,
   1366                                         l3v6_entry,
   1367                                         l3v6_ext_entry);
   1368     }
   1369     /* Prepare lookup key. */
   1370     BCM_IF_ERROR_RETURN(_bcm_td2_l3_ent_init(unit, mem, l3cfg, buf_entry));
   1371 
   1372     rv = soc_mem_delete(unit, mem, MEM_BLOCK_ANY, (void*) buf_entry);
   1373 
   1374     if (rv >= 0) {
   1375         (ipv6) ?  BCM_XGS3_L3_IP6_CNT(unit)-- : BCM_XGS3_L3_IP4_CNT(unit)--;
   1376     }    
   1377 
   1378     if ((BCM_E_NOT_FOUND == rv) &&
   1379         (soc_feature(unit, soc_feature_l3_extended_host_entry))) { 
   1380         /* Delete from  the extended tables only if the extended host entry
   1381          * feature is supported and if the entry was not found in the 
   1382          * regular host entry */
   1383 
   1384 #ifdef BCM_TOMAHAWK_SUPPORT
   1385         if (BCM_L3_BK_FLAG_GET(unit, BCM_L3_BK_ENABLE_MACDA_OUI_PROFILE)) {
   1386             BCM_IF_ERROR_RETURN
   1387             (_bcm_th_get_extended_profile_index(unit, mem_ext, l3cfg,
   1388                                                 &macda_oui_profile_index,
   1389                                                 &vntag_etag_profile_index,
   1390                                                 &ref_count));
   1391        }
   1392 #endif
   1393 
   1394 #if defined(BCM_RIOT_SUPPORT)
   1395         if ((soc_feature(unit, soc_feature_riot)) &&
   1396             (_bcm_vp_is_vfi_type(unit, l3cfg->l3c_port_tgid))) {
   1397             BCM_IF_ERROR_RETURN
   1398                 (_bcm_td2p_l3_get_macda_oui_profile_index(unit, mem_ext, l3cfg,
   1399                                                           &macda_oui_profile_index,
   1400                                                           &ref_count));
   1401         }
   1402 #endif
   1403         /* Assign entry-key buf based on table being used */
   1404         BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_entry,
   1405                                   l3v4_entry,
   1406                                   l3v4_ext_entry,
   1407                                   l3v6_entry,
   1408                                   l3v6_ext_entry);
   1409         /* Prepare lookup key. */
   1410         BCM_IF_ERROR_RETURN(_bcm_td2_l3_ent_init(unit, mem_ext, l3cfg, buf_entry));
   1411 
   1412         rv = soc_mem_delete(unit, mem_ext, MEM_BLOCK_ANY, (void*) buf_entry);
   1413         
   1414         if (rv >= 0) {
   1415             (ipv6) ?  BCM_XGS3_L3_IP6_CNT(unit)-- : BCM_XGS3_L3_IP4_CNT(unit)--;
   1416             
   1417 #ifdef BCM_TOMAHAWK_SUPPORT            
   1418         BCM_IF_ERROR_RETURN
   1419             (_bcm_th_l3_vp_entry_del(unit, l3cfg, 
   1420                                      macda_oui_profile_index,
   1421                                      vntag_etag_profile_index));
   1422 #endif
   1423 #if defined(BCM_RIOT_SUPPORT)
   1424         if ((soc_feature(unit, soc_feature_riot)) &&
   1425             (_bcm_vp_is_vfi_type(unit, l3cfg->l3c_port_tgid))) {
   1426                 BCM_IF_ERROR_RETURN
   1427                     (_bcm_td2p_l3_macda_oui_profile_entry_del(unit, l3cfg,
   1428                                                               macda_oui_profile_index));
   1429             }
   1430 #endif
   1431         }
   1432     }
   1433 
   1434     return rv;
   1435 }
   1436 
   1437 int
   1438 _bcm_td2_ip_key_to_l3cfg(int unit, bcm_l3_key_t *ipkey, _bcm_l3_cfg_t *l3cfg)
   1439 {
   1440     int ipv6;           /* IPV6 key.                     */
   1441 
   1442     /* Input parameters check */
   1443     if ((NULL == ipkey) || (NULL == l3cfg)) {
   1444         return (BCM_E_PARAM);
   1445     }
   1446 
   1447     /* Reset destination buffer first. */
   1448     sal_memset(l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   1449 
   1450     l3cfg->l3c_rp_id = BCM_IPMC_RP_ID_INVALID;
   1451     l3cfg->l3c_ing_intf = BCM_IF_INVALID;
   1452 
   1453     ipv6 = (ipkey->l3k_flags & BCM_L3_IP6);
   1454 
   1455     /* Set vrf id. */
   1456     l3cfg->l3c_vrf = ipkey->l3k_vrf;
   1457     l3cfg->l3c_vid = ipkey->l3k_vid;
   1458 
   1459     if (ipv6) {
   1460         if (BCM_IP6_MULTICAST(ipkey->l3k_ip6_addr)) {
   1461             /* Copy ipv6 group, source & vid. */
   1462             sal_memcpy(l3cfg->l3c_ip6, ipkey->l3k_ip6_addr, sizeof(bcm_ip6_t));
   1463             sal_memcpy(l3cfg->l3c_sip6, ipkey->l3k_sip6_addr,
   1464                        sizeof(bcm_ip6_t));
   1465             l3cfg->l3c_vid = ipkey->l3k_vid;
   1466             l3cfg->l3c_flags = (BCM_L3_IP6 | BCM_L3_IPMC);
   1467         } else {
   1468             /* Copy ipv6 address. */
   1469             sal_memcpy(l3cfg->l3c_ip6, ipkey->l3k_ip6_addr, sizeof(bcm_ip6_t));
   1470             l3cfg->l3c_flags = BCM_L3_IP6;
   1471         }
   1472     } else {
   1473         if (BCM_IP4_MULTICAST(ipkey->l3k_ip_addr)) {
   1474             /* Copy ipv4 mcast group, source & vid. */
   1475             l3cfg->l3c_ip_addr = ipkey->l3k_ip_addr;
   1476             l3cfg->l3c_src_ip_addr = ipkey->l3k_sip_addr;
   1477             l3cfg->l3c_vid = ipkey->l3k_vid;
   1478             l3cfg->l3c_flags = BCM_L3_IPMC;
   1479         } else {
   1480             /* Copy ipv4 address . */
   1481             l3cfg->l3c_ip_addr = ipkey->l3k_ip_addr;
   1482         }
   1483     }
   1484     return (BCM_E_NONE);
   1485 }
   1486 
   1487 int
   1488 _bcm_td2_l3cfg_to_ipkey(int unit, bcm_l3_key_t *ipkey, _bcm_l3_cfg_t *l3cfg)
   1489 {
   1490     /* Input parameters check */
   1491     if ((NULL == ipkey) || (NULL == l3cfg)) {
   1492         return (BCM_E_PARAM);
   1493     }
   1494 
   1495     /* Reset destination buffer first. */
   1496     sal_memset(ipkey, 0, sizeof(bcm_l3_key_t));
   1497 
   1498     ipkey->l3k_vrf = l3cfg->l3c_vrf;
   1499     ipkey->l3k_vid = l3cfg->l3c_vid;
   1500 
   1501     if (l3cfg->l3c_flags & BCM_L3_IP6) {
   1502         if (l3cfg->l3c_flags & BCM_L3_IPMC) {
   1503             /* Copy ipv6 group, source & vid. */
   1504             sal_memcpy(ipkey->l3k_ip6_addr, l3cfg->l3c_ip6, sizeof(bcm_ip6_t));
   1505             sal_memcpy(ipkey->l3k_sip6_addr, l3cfg->l3c_sip6,
   1506                        sizeof(bcm_ip6_t));
   1507             ipkey->l3k_vid = l3cfg->l3c_vid;
   1508         } else {
   1509             /* Copy ipv6 address. */
   1510             sal_memcpy(ipkey->l3k_ip6_addr, l3cfg->l3c_ip6, sizeof(bcm_ip6_t));
   1511         }
   1512     } else {
   1513         if (l3cfg->l3c_flags & BCM_L3_IPMC) {
   1514             /* Copy ipv4 mcast group, source & vid. */
   1515             ipkey->l3k_ip_addr = l3cfg->l3c_ip_addr;
   1516             ipkey->l3k_sip_addr = l3cfg->l3c_src_ip_addr;
   1517             ipkey->l3k_vid = l3cfg->l3c_vid;
   1518         } else {
   1519             /* Copy ipv4 address . */
   1520             ipkey->l3k_ip_addr = l3cfg->l3c_ip_addr;
   1521         }
   1522     }
   1523     /* Store entry flags. */
   1524     ipkey->l3k_flags = l3cfg->l3c_flags;
   1525     return (BCM_E_NONE);
   1526 }
   1527 
   1528 int
   1529 bcm_td2_l3_conflict_get(int unit, bcm_l3_key_t *ipkey, bcm_l3_key_t *cf_array,
   1530                         int cf_max, int *cf_count)
   1531 {
   1532     _bcm_l3_cfg_t l3cfg;
   1533     uint32 *bufp;      /* Hardware buffer ptr     */
   1534     soc_mem_t mem;            /* L3 table memory type.   */  
   1535     int nh_idx, index, rv = BCM_E_NONE;      /* Operation status.       */
   1536     _bcm_l3_fields_t *fld;    /* L3 table common fields. */
   1537     l3_entry_ipv4_unicast_entry_t l3v4_entry;    
   1538     l3_entry_ipv4_multicast_entry_t l3v4_ext_entry;    
   1539     l3_entry_ipv6_unicast_entry_t l3v6_entry;
   1540     l3_entry_ipv6_multicast_entry_t l3v6_ext_entry;
   1541     uint8 i,num_ent;
   1542     uint32 l3_entry[SOC_MAX_MEM_WORDS];
   1543     uint32 ipmc, ipv6, embedded_nh;
   1544     uint32 bucket;   
   1545     int num_banks, max_bank = 9;
   1546     int hash_offset = 0, use_lsb = 0, bidx = 0;
   1547     
   1548     /*  Make sure module was initialized. */
   1549     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   1550         return (BCM_E_INIT);
   1551     }
   1552 
   1553     /* Input parameters check. */
   1554     if ((NULL == ipkey) || (NULL == cf_count) || 
   1555         (NULL == cf_array) || (cf_max <= 0)) {
   1556         return (BCM_E_PARAM);
   1557     }
   1558 
   1559     embedded_nh = ipkey->l3k_flags & BCM_L3_DEREFERENCED_NEXTHOP;
   1560     nh_idx = (embedded_nh) ? BCM_XGS3_L3_INVALID_INDEX : 0;
   1561 
   1562     /* Translate lookup key to l3cfg format. */
   1563     BCM_IF_ERROR_RETURN(_bcm_td2_ip_key_to_l3cfg(unit, ipkey, &l3cfg));
   1564     
   1565     /* Get entry type. */
   1566     ipv6 = (l3cfg.l3c_flags & BCM_L3_IP6);
   1567     ipmc = (l3cfg.l3c_flags & BCM_L3_IPMC);
   1568 
   1569 #ifdef BCM_TOMAHAWK3_SUPPORT
   1570     if (SOC_IS_TOMAHAWK3(unit))
   1571     {
   1572         /*
   1573          * Get table memory. 
   1574          */
   1575         BCM_TH3_L3_HOST_TABLE_MEM(unit, l3cfg.l3c_intf, ipv6, ipmc, mem, nh_idx);
   1576         BCM_TH3_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
   1577         BCM_TH3_L3_HOST_ENTRY_BUF(ipv6, mem, bufp, l3v4_entry, l3v4_ext_entry, l3v6_entry, l3v6_ext_entry);
   1578         max_bank = 3;
   1579     } else
   1580 #endif
   1581     {
   1582     /* Get table memory. */
   1583     BCM_TD2_L3_HOST_TABLE_MEM(unit, l3cfg.l3c_intf, ipv6, mem, nh_idx);
   1584 
   1585     /* Bump up the size conditionally */
   1586     mem = (embedded_nh || ipmc) ? (ipv6 ? L3_ENTRY_IPV6_MULTICASTm : L3_ENTRY_IPV4_MULTICASTm) : mem;
   1587     
   1588     /* Set table fields */
   1589     BCM_TD2_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
   1590 
   1591     /* Assign entry buf based on table being used */
   1592     BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem, bufp,
   1593                                     l3v4_entry,
   1594                                     l3v4_ext_entry,
   1595                                     l3v6_entry,
   1596                                     l3v6_ext_entry);
   1597     }
   1598     /* Prepare host entry for addition. */
   1599     if (ipmc) {
   1600         /*  Zero entry buffer. */
   1601         sal_memcpy(bufp, soc_mem_entry_null(unit, mem), 
   1602                    soc_mem_entry_words(unit,mem) * 4);
   1603         BCM_IF_ERROR_RETURN(_bcm_td2_l3_ipmc_ent_init(unit, bufp, &l3cfg));
   1604     } else {
   1605         BCM_IF_ERROR_RETURN(_bcm_td2_l3_ent_init(unit, mem, &l3cfg, bufp));
   1606     }   
   1607 
   1608     *cf_count = 0;
   1609 
   1610     /* Get entries of each banks */
   1611     switch (mem)
   1612     {
   1613     case L3_ENTRY_IPV4_UNICASTm:
   1614         case L3_ENTRY_SINGLEm:
   1615         num_ent =  4;
   1616         break;
   1617     case L3_ENTRY_IPV6_UNICASTm:
   1618     case L3_ENTRY_IPV4_MULTICASTm:
   1619         case L3_ENTRY_DOUBLEm:
   1620         num_ent =  2;
   1621         break;
   1622     case L3_ENTRY_IPV6_MULTICASTm:
   1623         case L3_ENTRY_QUADm:
   1624         num_ent =  1;
   1625         break;
   1626 
   1627     /* coverity[dead_error_begin] */
   1628     default:
   1629         return BCM_E_PARAM;        
   1630     }
   1631 
   1632     
   1633 
   1634     /* Get number of L3 banks */
   1635 #ifdef BCM_TOMAHAWK_SUPPORT
   1636 #ifdef BCM_TOMAHAWK3_SUPPORT
   1637     if (SOC_IS_TOMAHAWK3(unit)) {
   1638         SOC_IF_ERROR_RETURN(soc_tomahawk3_hash_bank_count_get(unit, mem, &num_banks));
   1639     } else
   1640 #endif /* BCM_TOMAHAWK3_SUPPORT */
   1641         if (SOC_IS_TOMAHAWKX(unit)) {
   1642         SOC_IF_ERROR_RETURN(soc_tomahawk_hash_bank_count_get(unit, mem, &num_banks));
   1643         } else
   1644 #endif /* BCM_TOMAHAWK_SUPPORT */
   1645 #ifdef BCM_APACHE_SUPPORT
   1646         if (SOC_IS_APACHE(unit)) {
   1647             SOC_IF_ERROR_RETURN
   1648                 (soc_apache_hash_bank_count_get(unit, mem, &num_banks));
   1649         } else
   1650 #endif /* BCM_TOMAHAWK_SUPPORT */
   1651 #ifdef BCM_HELIX5_SUPPORT
   1652         if (SOC_IS_HELIX5(unit)) {
   1653             SOC_IF_ERROR_RETURN
   1654                 (soc_helix5_hash_bank_count_get(unit, mem, &num_banks));
   1655         } else
   1656 #endif /* BCM_HELIX5_SUPPORT */
   1657 #ifdef BCM_TRIDENT3_SUPPORT
   1658         if (SOC_IS_TRIDENT3X(unit)) {
   1659             SOC_IF_ERROR_RETURN
   1660                 (soc_trident3_hash_bank_count_get(unit, mem, &num_banks));
   1661         } else
   1662 #endif /* BCM_TRIDENT3_SUPPORT */
   1663 
   1664         {
   1665             SOC_IF_ERROR_RETURN
   1666                 (soc_trident2_hash_bank_count_get(unit, mem, &num_banks));
   1667         }
   1668 
   1669     /* bank 9 to 6 are dedicated L3 banks, 5 to 3 are dedicated, depends on
   1670      * mode how many shared banks are assigned to l3 
   1671      */
   1672     for (bidx = max_bank; bidx >= (max_bank - num_banks + 1); bidx--) {
   1673         /* Calculate hash index */
   1674 #ifdef BCM_APACHE_SUPPORT
   1675         if (SOC_IS_APACHE(unit)) {
   1676             rv = soc_ap_hash_offset_get(unit, L3_ENTRY_ONLYm, bidx, &hash_offset,
   1677                                         &use_lsb);
   1678         } else
   1679 #endif /* BCM_APACHE_SUPPORT */
   1680 #ifdef BCM_TOMAHAWK_SUPPORT
   1681 #ifdef BCM_TOMAHAWK3_SUPPORT
   1682         if (SOC_IS_TOMAHAWK3(unit)) {
   1683             rv = soc_tomahawk3_hash_offset_get(unit, L3_ENTRY_ONLYm, bidx, &hash_offset, &use_lsb);
   1684         } else
   1685 #endif /* BCM_TOMAHAWK3_SUPPORT */
   1686 
   1687         if (SOC_IS_TOMAHAWKX(unit)) {
   1688             rv = soc_th_hash_offset_get(unit, L3_ENTRY_ONLYm, bidx, &hash_offset,
   1689                                         &use_lsb);
   1690         } else
   1691 #endif /* BCM_TOMAHAWK_SUPPORT */
   1692 #ifdef BCM_HELIX5_SUPPORT
   1693         if (SOC_IS_HELIX5(unit)) {
   1694             rv = soc_hx5_hash_offset_get(unit, L3_ENTRY_ONLYm, bidx, &hash_offset,
   1695                                          &use_lsb);
   1696         } else
   1697 #endif /* BCM_HELIX5_SUPPORT */
   1698 #ifdef BCM_TRIDENT3_SUPPORT
   1699         if (SOC_IS_TRIDENT3X(unit)) {
   1700             rv = soc_td3_hash_offset_get(unit, L3_ENTRY_ONLYm, bidx, &hash_offset,
   1701                                         &use_lsb);
   1702         } else
   1703 #endif /* BCM_TRIDENT3_SUPPORT */
   1704         {
   1705             rv = soc_td2_hash_offset_get(unit, L3_ENTRY_ONLYm, bidx, &hash_offset,
   1706                                          &use_lsb);
   1707         }
   1708 
   1709         if (BCM_FAILURE(rv)) {
   1710             return BCM_E_INTERNAL;
   1711         }
   1712         
   1713         /* coverity[overrun-buffer-val: FALSE] */
   1714 #ifdef BCM_APACHE_SUPPORT
   1715         if (SOC_IS_APACHE(unit)) {
   1716             bucket = soc_ap_l3x_entry_hash(unit, bidx, hash_offset, use_lsb, bufp);
   1717             index = soc_ap_hash_index_get(unit, mem, bidx, bucket);
   1718         } else
   1719 #endif /* BCM_APACHE_SUPPORT */
   1720 #ifdef BCM_TOMAHAWK3_SUPPORT
   1721         if (SOC_IS_TOMAHAWK3(unit)) {
   1722             bucket = soc_tomahawk3_l3x_entry_hash(unit, bidx, hash_offset, use_lsb, bufp);
   1723             index = soc_tomahawk3_hash_index_get(unit, mem, bidx, bucket);
   1724         } else
   1725 #endif /* BCM_TOMAHAWK3_SUPPORT */
   1726 #ifdef BCM_TOMAHAWK_SUPPORT
   1727         if (SOC_IS_TOMAHAWKX(unit)) {
   1728             bucket = soc_th_l3x_entry_hash(unit, bidx, hash_offset, use_lsb, bufp);
   1729             index = soc_th_hash_index_get(unit, mem, bidx, bucket);
   1730         } else
   1731 #endif /* BCM_TOMAHAWK_SUPPORT */
   1732 #ifdef BCM_HELIX5_SUPPORT
   1733         if (SOC_IS_HELIX5(unit)) {
   1734             bucket = soc_hx5_l3x_entry_hash(unit, bidx, hash_offset, use_lsb, bufp);
   1735             index = soc_hx5_hash_index_get(unit, mem, bidx, bucket);
   1736         } else
   1737 #endif /* BCM_HELIX5_SUPPORT */
   1738 #ifdef BCM_TRIDENT3_SUPPORT
   1739         if (SOC_IS_TRIDENT3X(unit)) {
   1740             bucket = soc_td3_l3x_entry_hash(unit, bidx, hash_offset, use_lsb, bufp);
   1741             index = soc_td3_hash_index_get(unit, mem, bidx, bucket);
   1742         } else
   1743 #endif /* BCM_TRIDENT3_SUPPORT */
   1744         {
   1745             bucket = soc_td2_l3x_entry_hash(unit, bidx, hash_offset, use_lsb, bufp);
   1746             index = soc_hash_index_get(unit, mem, bidx, bucket);
   1747         }
   1748 
   1749         /* Get conflicting IPs from all HW entries in current bank */
   1750         for (i = 0; (i < num_ent) && (*cf_count < cf_max);) {
   1751             rv = soc_mem_read(unit, mem, COPYNO_ALL, index + i, l3_entry);
   1752             if (SOC_FAILURE(rv)) {
   1753                 return BCM_E_MEMORY;
   1754             }
   1755             if (soc_mem_field32_get(unit, mem, &l3_entry, fld->valid)) {
   1756                 switch(soc_mem_field32_get(unit, mem, &l3_entry, fld->key_type)) {
   1757                 case TD2_L3_HASH_KEY_TYPE_V4UC:
   1758                       l3cfg.l3c_flags = 0;
   1759                       break;
   1760                 case TD2_L3_HASH_KEY_TYPE_V4UC_EXT:
   1761                       l3cfg.l3c_flags = BCM_L3_DEREFERENCED_NEXTHOP;
   1762                       break;
   1763                 case TD2_L3_HASH_KEY_TYPE_V4MC:
   1764                       l3cfg.l3c_flags = BCM_L3_IPMC;
   1765                       break;
   1766                 case TD2_L3_HASH_KEY_TYPE_V6UC:
   1767                       l3cfg.l3c_flags = BCM_L3_IP6;
   1768                       break;
   1769                 case TD2_L3_HASH_KEY_TYPE_V6UC_EXT:
   1770                       l3cfg.l3c_flags = BCM_L3_IP6 | BCM_L3_DEREFERENCED_NEXTHOP;
   1771                       break;
   1772                 case TD2_L3_HASH_KEY_TYPE_V6MC:
   1773                       l3cfg.l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC;
   1774                       break;
   1775                 case TD2_L3_HASH_KEY_TYPE_V4L2MC:
   1776                 case TD2_L3_HASH_KEY_TYPE_V4L2VPMC:
   1777                       l3cfg.l3c_flags = BCM_L3_IPMC | BCM_L3_L2ONLY;
   1778                       break;
   1779                 case TD2_L3_HASH_KEY_TYPE_V6L2MC:
   1780                 case TD2_L3_HASH_KEY_TYPE_V6L2VPMC:
   1781                       l3cfg.l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC | BCM_L3_L2ONLY;
   1782                 default:
   1783                       break;
   1784                 }
   1785                 /* Get host ip address. */                   		
   1786                 rv = _bcm_td2_l3_get_by_idx(unit, NULL, index + i, &l3cfg, &nh_idx);
   1787                 if (BCM_FAILURE(rv)) {
   1788                     continue;          
   1789                 }
   1790                                     
   1791                 BCM_IF_ERROR_RETURN
   1792                     (_bcm_td2_l3cfg_to_ipkey(unit, cf_array + (*cf_count), &l3cfg));
   1793                 if ((++(*cf_count)) >= cf_max) {
   1794                     break;
   1795                 }
   1796             }
   1797             /* increment based upon existing entry */
   1798             i += (mem == ((SOC_MEM_IS_VALID(unit, L3_ENTRY_IPV6_MULTICASTm))?L3_ENTRY_IPV6_MULTICASTm:L3_ENTRY_DOUBLEm)) ? 2 : 1;
   1799         }
   1800 
   1801         /* Stop loop if conflicting IPs got from HW is no less than cf_max. */
   1802         if ((*cf_count) >= cf_max) {
   1803             break;
   1804         }
   1805     } 
   1806     return BCM_E_NONE;
   1807 }
   1808 
   1809 
   1810 
   1811 /*
   1812  * Function:
   1813  *      _bcm_td2_l3_get_host_ent_by_idx
   1814  * Purpose:
   1815  * Parameters:
   1816  *      unit     - (IN)SOC unit number.
   1817  *      dma_ptr  - (IN)Table pointer in dma. 
   1818  *      soc_mem_ - (IN)Table memory.
   1819  *      idx      - (IN)Index to read.
   1820  *      l3cfg    - (OUT)l3 entry search result.
   1821  *      nh_index - (OUT)Next hop index.
   1822  * Returns:
   1823  *      BCM_E_XXX
   1824  */
   1825 STATIC int
   1826 _bcm_td2_l3_get_host_ent_by_idx(int unit, void *dma_ptr, soc_mem_t mem,
   1827                                 int idx, _bcm_l3_cfg_t *l3cfg, int *nh_idx)
   1828 {
   1829     uint32 ipv6;                       /* IPv6 entry indicator.   */
   1830     int key_type;
   1831     int clear_hit;                     /* Clear hit bit flag.     */
   1832     _bcm_l3_fields_t *fld;             /* L3 table common fields. */
   1833     uint32 valid, base_valid_bits = 1;
   1834     uint32 *buf_entry;                 /* Key and entry buffer ptrs*/
   1835     l3_entry_ipv4_unicast_entry_t l3v4_entry;       /* IPv4 */
   1836     l3_entry_ipv4_multicast_entry_t l3v4_ext_entry; /* IPv4-Embedded */
   1837     l3_entry_ipv6_unicast_entry_t l3v6_entry;       /* IPv6 */
   1838     l3_entry_ipv6_multicast_entry_t l3v6_ext_entry; /* IPv6-Embedded */
   1839     soc_field_t uc_ipv6_lwr = INVALIDf, uc_ipv6_upr = INVALIDf;
   1840     soc_field_t data_type = 44;
   1841 #ifdef BCM_TRIDENT3_SUPPORT
   1842     int rv = BCM_E_NOT_FOUND;
   1843     uint32 view_id = 0;
   1844 #endif
   1845     /* Get entry type. */
   1846     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
   1847     /* Get clear hit flag. */
   1848     clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR;
   1849 
   1850 #ifdef BCM_TOMAHAWK3_SUPPORT
   1851         if (SOC_IS_TOMAHAWK3(unit))
   1852         {
   1853             BCM_TH3_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
   1854             BCM_TH3_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry, l3v4_entry, l3v4_ext_entry, l3v6_entry, l3v6_ext_entry);
   1855         }
   1856         else
   1857 #endif
   1858 #ifdef BCM_TRIDENT3_SUPPORT
   1859     if (SOC_IS_TRIDENT3X(unit)) {
   1860         BCM_TD3_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
   1861         BCM_TD3_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry,
   1862                                         l3v4_entry,
   1863                                         l3v4_ext_entry,
   1864                                         l3v6_entry,
   1865                                         l3v6_ext_entry);
   1866     } else
   1867 
   1868 #endif
   1869     {
   1870 
   1871     BCM_TD2_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
   1872     BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry,
   1873                                     l3v4_entry,
   1874                                     l3v4_ext_entry,
   1875                                     l3v6_entry,
   1876                                     l3v6_ext_entry);
   1877     }
   1878     
   1879 
   1880     if (NULL == dma_ptr) { /* Read from hardware. */
   1881         /* Zero buffers. */
   1882         sal_memset(buf_entry, 0, BCM_L3_MEM_ENT_SIZE(unit, mem));
   1883 
   1884         /* Read entry from hw. */
   1885         BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, buf_entry)); 
   1886     } else { /* Read from dma. */
   1887         buf_entry = soc_mem_table_idx_to_pointer(unit, mem,
   1888                                    uint32 *, dma_ptr, idx);
   1889     }
   1890 
   1891     valid = soc_mem_field32_get(unit, mem, buf_entry, fld->valid);
   1892     key_type = soc_mem_field32_get(unit, mem, buf_entry, fld->key_type);
   1893     base_valid_bits = 1;
   1894 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
   1895     if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) {
   1896         if (soc_mem_field_valid(unit, mem, DATA_TYPEf)) {
   1897             data_type = soc_mem_field32_get(unit, mem, buf_entry, DATA_TYPEf);
   1898             switch(mem) {
   1899                 case L3_ENTRY_SINGLEm:
   1900                     base_valid_bits = 1;
   1901                     break;
   1902                 case L3_ENTRY_DOUBLEm:
   1903                     if ((key_type == 0) ||
   1904                         ((key_type == (int)TD2_L3_HASH_KEY_TYPE_V6UC) &&
   1905                                         (SOC_IS_TOMAHAWK3(unit)))) {
   1906                         base_valid_bits = 1;
   1907                     } else {
   1908                         base_valid_bits = 3;
   1909                     }
   1910                     break;
   1911                 case L3_ENTRY_QUADm:
   1912                     if (SOC_IS_TRIDENT3X(unit)) {
   1913                         if ((key_type == (int)TD3_L3_HASH_KEY_TYPE_V6UC_EXT) &&
   1914                                 (data_type == TD3_L3_HASH_DATA_TYPE_V6UC_EXT)) {
   1915                             base_valid_bits = 3;
   1916                         } else {
   1917                             base_valid_bits = 5;
   1918                         }
   1919                     } else if ((key_type == (int)TD2_L3_HASH_KEY_TYPE_V6MC) ||
   1920                               (SOC_IS_TOMAHAWK3(unit))) {
   1921                         base_valid_bits = 1;
   1922                     }
   1923                     break;
   1924                 default:
   1925                     break;
   1926             }
   1927         }
   1928     }
   1929 #endif
   1930 #if defined(BCM_TRIDENT3_SUPPORT)
   1931     if (soc_feature(unit, soc_feature_flex_flow)) {
   1932         soc_flow_db_ffo_t ffo[SOC_FLOW_DB_MAX_VIEW_FFO_TPL];
   1933         uint32 num_ffo = 0;
   1934 
   1935         rv = soc_flow_db_mem_to_view_id_get(unit,
   1936                 mem,
   1937                 SOC_FLOW_DB_KEY_TYPE_INVALID,
   1938                 data_type,
   1939                 0,
   1940                 NULL,
   1941                 &view_id);
   1942         if (rv == BCM_E_NONE) {
   1943             /* get the flow handle, function id, option id */
   1944             BCM_IF_ERROR_RETURN(
   1945                 soc_flow_db_mem_view_to_ffo_get(unit,
   1946                     view_id,
   1947                     SOC_FLOW_DB_MAX_VIEW_FFO_TPL,
   1948                     ffo,
   1949                     &num_ffo));
   1950             l3cfg->l3c_flow_handle = ffo[0].flow_handle;
   1951             l3cfg->l3c_flow_option_handle = ffo[0].option_id;
   1952         }
   1953     }
   1954 #endif
   1955     if(valid != base_valid_bits) {
   1956         if (valid) {
   1957            base_valid_bits = 1;
   1958         }
   1959         return (BCM_E_NOT_FOUND);
   1960     }
   1961 
   1962     l3cfg->l3c_flags = 0;
   1963     switch (mem) {
   1964     case L3_ENTRY_IPV4_UNICASTm:
   1965 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
   1966     case L3_ENTRY_SINGLEm:
   1967 #endif
   1968         if  (!(soc_feature(unit, soc_feature_flex_flow)) &&
   1969              ((key_type != TD2_L3_HASH_KEY_TYPE_V4UC) ||
   1970              ((SOC_IS_TRIDENT3X(unit)) && (mem == L3_ENTRY_SINGLEm) && (data_type != 0)))) {
   1971             /* All other keys are invalid */
   1972             return BCM_E_NOT_FOUND;
   1973         }
   1974 #ifdef BCM_TRIDENT3_SUPPORT
   1975         /* In TD3, can't distinguish regular from extended entries as
   1976          * in previous chips. Hence check for next entry BASE_VALID field
   1977          * to check for extended entries */
   1978         if (SOC_IS_TRIDENT3X(unit) && (idx != soc_mem_index_max(unit,
   1979             L3_ENTRY_SINGLEm))) {
   1980             l3_entry_ipv4_unicast_entry_t td3_l3v4_entry;
   1981             uint32 *td3_buf_entry = (uint32 *) &td3_l3v4_entry;
   1982 
   1983             if (NULL == dma_ptr) { /* Read from hardware. */
   1984                 /* Zero buffers. */
   1985                 sal_memset(td3_buf_entry, 0, BCM_L3_MEM_ENT_SIZE(unit, mem));
   1986 
   1987                 /* Read entry from hw. */
   1988                 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx + 1,
   1989                                                       td3_buf_entry));
   1990             } else { /* Read from dma. */
   1991                 td3_buf_entry = soc_mem_table_idx_to_pointer(unit, mem,
   1992                                     uint32 *, dma_ptr, idx + 1);
   1993             }
   1994 
   1995             valid = soc_mem_field32_get(unit, mem, td3_buf_entry, fld->valid);
   1996             if (valid == 7) {
   1997                 return BCM_E_NOT_FOUND;
   1998             }
   1999         }
   2000 #endif
   2001         break;
   2002     case L3_ENTRY_IPV4_MULTICASTm:
   2003 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
   2004     case L3_ENTRY_DOUBLEm:
   2005 #endif
   2006         if (key_type == TD2_L3_HASH_KEY_TYPE_V4MC) {
   2007             l3cfg->l3c_flags = BCM_L3_IPMC;
   2008         } else if (((key_type == TD2_L3_HASH_KEY_TYPE_V4UC) &&
   2009                 (mem == L3_ENTRY_DOUBLEm) && (data_type == 1)) ||
   2010                 ((key_type == TD2_L3_HASH_KEY_TYPE_V4UC_EXT) && (mem != L3_ENTRY_DOUBLEm))){
   2011             l3cfg->l3c_flags = 0;
   2012         } else if ((key_type == TD2_L3_HASH_KEY_TYPE_V4L2MC) || 
   2013             (key_type == TD2_L3_HASH_KEY_TYPE_V4L2VPMC)) {
   2014             l3cfg->l3c_flags = BCM_L3_IPMC | BCM_L3_L2ONLY;
   2015         } else if ((key_type == TD2_L3_HASH_KEY_TYPE_V6UC) &&
   2016               (((mem == L3_ENTRY_DOUBLEm) &&
   2017                 (SOC_IS_TOMAHAWK3(unit) || (data_type == 2))) ||
   2018                (mem != L3_ENTRY_DOUBLEm))){
   2019 
   2020             l3cfg->l3c_flags = BCM_L3_IP6;
   2021             if (mem == L3_ENTRY_DOUBLEm) {
   2022             uc_ipv6_lwr = IPV6UC__IP_ADDR_LWR_64f;
   2023             uc_ipv6_upr = IPV6UC__IP_ADDR_UPR_64f;
   2024         } else {
   2025                 uc_ipv6_lwr = IP_ADDR_LWR_64f;
   2026                 uc_ipv6_upr = IP_ADDR_UPR_64f;
   2027             }
   2028         } else {
   2029 #if defined(BCM_TRIDENT3_SUPPORT)
   2030             if ((SOC_IS_TRIDENT3X(unit)) && (rv == BCM_E_NONE)) {
   2031                 /* If it is a flex entry in TD3X, do not return error */
   2032             } else
   2033 #endif
   2034             {
   2035                 return BCM_E_NOT_FOUND;
   2036             }
   2037         }
   2038         break;
   2039     case L3_ENTRY_IPV6_UNICASTm:
   2040         if (key_type == TD2_L3_HASH_KEY_TYPE_V6UC) {
   2041             l3cfg->l3c_flags = BCM_L3_IP6;
   2042             uc_ipv6_lwr = IP_ADDR_LWR_64f;
   2043             uc_ipv6_upr = IP_ADDR_UPR_64f;
   2044         } else {
   2045             return BCM_E_NOT_FOUND;
   2046         }
   2047         break;
   2048     case L3_ENTRY_IPV6_MULTICASTm:
   2049 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
   2050     case L3_ENTRY_QUADm:
   2051 #endif
   2052         uc_ipv6_lwr =  IPV6UC_EXT__IP_ADDR_LWR_64f;
   2053         uc_ipv6_upr =  IPV6UC_EXT__IP_ADDR_UPR_64f;
   2054         if (key_type == TD2_L3_HASH_KEY_TYPE_V6MC) {
   2055             l3cfg->l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC;
   2056         } if ((key_type == TD2_L3_HASH_KEY_TYPE_V6UC_EXT)) {
   2057             l3cfg->l3c_flags = BCM_L3_IP6;
   2058         } else if ((key_type == TD2_L3_HASH_KEY_TYPE_V6L2MC) ||
   2059                 (key_type == TD2_L3_HASH_KEY_TYPE_V6L2VPMC)) {
   2060             l3cfg->l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC | BCM_L3_L2ONLY;
   2061         }
   2062 #ifdef BCM_TRIDENT3_SUPPORT
   2063         else if (SOC_IS_TRIDENT3X(unit) && (key_type ==
   2064                 TD3_L3_HASH_KEY_TYPE_V6UC_EXT) && (data_type ==
   2065                 TD3_L3_HASH_DATA_TYPE_V6UC_EXT)) {
   2066             l3cfg->l3c_flags = BCM_L3_IP6;
   2067         }
   2068 #endif
   2069         else {
   2070 #if defined(BCM_TRIDENT3_SUPPORT)
   2071             if ((soc_feature(unit, soc_feature_flex_flow)) && (rv == BCM_E_NONE)) {
   2072                 /* TD3X flex entry */
   2073                 if (SOC_MEM_FIELD_VALID(unit, view_id, IPV6__DIPf)) {
   2074                     l3cfg->l3c_flags = BCM_L3_IP6;
   2075                     soc_mem_ip6_addr_get(unit, view_id, buf_entry,IPV6__DIPf, l3cfg->l3c_ip6, 0);
   2076                 } else if (SOC_MEM_FIELD_VALID(unit, view_id, IPV6__SIPf)) {
   2077                     l3cfg->l3c_flags = BCM_L3_IP6;
   2078                     soc_mem_ip6_addr_get(unit, view_id, buf_entry,IPV6__SIPf, l3cfg->l3c_ip6, 0);
   2079                 }
   2080             } else
   2081 #endif
   2082             {
   2083                 return BCM_E_NOT_FOUND;
   2084             }
   2085         }
   2086         break;
   2087     default :
   2088         return BCM_E_NOT_FOUND;
   2089     }
   2090 
   2091     /* Ignore protocol mismatch & multicast entries. */
   2092     if ((ipv6  != (l3cfg->l3c_flags & BCM_L3_IP6)) ||
   2093         (l3cfg->l3c_flags & BCM_L3_IPMC)) {
   2094         return (BCM_E_NONE);
   2095     }
   2096 
   2097     if (ipv6) {
   2098 #if defined(BCM_TRIDENT3_SUPPORT)
   2099         if (!(soc_feature(unit, soc_feature_flex_flow) && (rv == BCM_E_NONE)))
   2100 #endif
   2101         {/* Extract host info from the entry. */
   2102             soc_mem_ip6_addr_get(unit, mem, buf_entry,
   2103                     uc_ipv6_lwr, l3cfg->l3c_ip6,
   2104                     SOC_MEM_IP6_LOWER_ONLY);
   2105 
   2106             soc_mem_ip6_addr_get(unit, mem, buf_entry,
   2107                     uc_ipv6_upr, l3cfg->l3c_ip6,
   2108                     SOC_MEM_IP6_UPPER_ONLY);
   2109         }
   2110     }
   2111     /* Set index to l3cfg. */
   2112     l3cfg->l3c_hw_index = idx;
   2113 
   2114     if (!ipv6) {
   2115         l3cfg->l3c_ip_addr = 
   2116             soc_mem_field32_get(unit, mem, buf_entry, fld->ip4);
   2117     }
   2118 
   2119     /* Parse entry data. */
   2120     BCM_IF_ERROR_RETURN(
   2121         _bcm_td2_l3_ent_parse(unit, mem, l3cfg, nh_idx, buf_entry, key_type));
   2122 
   2123     /* Clear the HIT bit */
   2124     if (clear_hit) {
   2125         BCM_IF_ERROR_RETURN(_bcm_td2_l3_clear_hit(unit, mem, l3cfg,
   2126                                            (void *)buf_entry, idx));
   2127     }
   2128 
   2129     return (BCM_E_NONE);
   2130 }
   2131 
   2132 /*
   2133  * Function:
   2134  *      _bcm_td2_l3_ipmc_ent_init
   2135  * Purpose:
   2136  *      Set GROUP/SOURCE/VID/IMPC flag in the entry.
   2137  * Parameters:
   2138  *      unit      - (IN)SOC unit number.
   2139  *      l3x_entry - (IN/OUT) IPMC entry to fill. 
   2140  *      l3cfg     - (IN) Api IPMC data. 
   2141  * Returns:
   2142  *    BCM_E_XXX
   2143  */
   2144 int
   2145 _bcm_td2_l3_ipmc_ent_init(int unit, uint32 *buf_p,
   2146                              _bcm_l3_cfg_t *l3cfg)
   2147 {
   2148     soc_mem_t mem;                     /* IPMC table memory.    */
   2149     int ipv6;                          /* IPv6 entry indicator. */
   2150     int idx;                           /* Iteration index.      */
   2151     soc_field_t v4typef[] = { KEY_TYPE_0f, KEY_TYPE_1f };
   2152     soc_field_t v6typef[] = { KEY_TYPE_0f, KEY_TYPE_1f, 
   2153                               KEY_TYPE_2f, KEY_TYPE_3f };
   2154     soc_field_t validf[] = { VALID_0f, VALID_1f, VALID_2f, VALID_3f };
   2155     int rv = BCM_E_NONE;
   2156     int vfi, key_type = 0;
   2157     uint32 base_valid0, base_valid1, base_valid2, base_valid3;
   2158 
   2159     /* Get entry type. */
   2160     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
   2161 
   2162     /* Get table memory. */
   2163     if (soc_mem_is_valid(unit, L3_ENTRY_DOUBLEm)) {
   2164         mem = (ipv6) ? L3_ENTRY_QUADm : L3_ENTRY_DOUBLEm;
   2165     } else {
   2166     mem =  (ipv6) ? L3_ENTRY_IPV6_MULTICASTm : L3_ENTRY_IPV4_MULTICASTm;
   2167     }
   2168 
   2169     if (ipv6) {
   2170         /* Set group address. */
   2171         soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6MC__GROUP_IP_ADDR_LWR_64f,
   2172                              l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY);
   2173         l3cfg->l3c_ip6[0] = 0x0;    /* Don't write ff entry already mcast. */
   2174         soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6MC__GROUP_IP_ADDR_UPR_56f, 
   2175                              l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY);
   2176         l3cfg->l3c_ip6[0] = 0xff;    /* Restore The entry  */
   2177 
   2178         /* Set source  address. */
   2179         if (soc_mem_field_valid(unit, mem, IPV6MC__SOURCE_IP_ADDR_BITS_63_32f)) {
   2180             soc_mem_ip6_addr_set(unit, mem, buf_p,
   2181                 IPV6MC__SOURCE_IP_ADDR_BITS_63_32f, l3cfg->l3c_sip6,
   2182                 SOC_MEM_IP6_BITS_63_32);
   2183             soc_mem_ip6_addr_set(unit, mem, buf_p,
   2184                 IPV6MC__SOURCE_IP_ADDR_BITS_31_0f, l3cfg->l3c_sip6,
   2185                 SOC_MEM_IP6_BITS_31_0);
   2186         } else {
   2187         soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6MC__SOURCE_IP_ADDR_LWR_64f, 
   2188                              l3cfg->l3c_sip6, SOC_MEM_IP6_LOWER_ONLY);
   2189         }
   2190         soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6MC__SOURCE_IP_ADDR_UPR_64f, 
   2191                              l3cfg->l3c_sip6, SOC_MEM_IP6_UPPER_ONLY);
   2192 
   2193         /* Set vlan id, VPN or L3_IIF. 
   2194          * if flag BCM_L3_L2ONLY is set or l3c_ing_intf is invalid, then program
   2195          * VLAN or VPN. 
   2196          * Else program L3_IIF. 
   2197          */
   2198         if ((l3cfg->l3c_flags & BCM_L3_L2ONLY) ||
   2199                 (l3cfg->l3c_ing_intf == BCM_IF_INVALID)) {
   2200             if (_BCM_VPN_IS_SET(l3cfg->l3c_vid)) {
   2201 
   2202                 if (soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) && 
   2203                         (l3cfg->l3c_flags & BCM_L3_L2ONLY)) {
   2204                     if (_BCM_VPN_IS_L3(l3cfg->l3c_vid)) {
   2205                         _BCM_VPN_GET(vfi, _BCM_VPN_TYPE_L3, l3cfg->l3c_vid);
   2206                     } else if (_BCM_VPN_IS_VPWS(l3cfg->l3c_vid)) {
   2207                         _BCM_VPN_GET(vfi, _BCM_VPN_TYPE_VPWS, l3cfg->l3c_vid);
   2208                     } else {
   2209                         _BCM_VPN_GET(vfi, _BCM_VPN_TYPE_VFI, l3cfg->l3c_vid);
   2210                     }
   2211                     soc_mem_field32_set(unit, mem, buf_p, IPV6MC__VFIf, vfi); 
   2212                     key_type = TD2_L3_HASH_KEY_TYPE_V6L2VPMC;
   2213                 } else {
   2214                     soc_mem_field32_set(unit, mem, buf_p, IPV6MC__L3_IIFf, l3cfg->l3c_vid);
   2215                     key_type = TD2_L3_HASH_KEY_TYPE_V6MC;
   2216                 }
   2217             } else {
   2218                 soc_mem_field32_set(unit, mem, buf_p, IPV6MC__VLAN_IDf, l3cfg->l3c_vid);
   2219                 key_type = TD2_L3_HASH_KEY_TYPE_V6L2MC;
   2220             }
   2221             if (!soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) ||
   2222                     !soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) {
   2223                 /* Override the key in case feature not supported */
   2224                 key_type = TD2_L3_HASH_KEY_TYPE_V6MC;
   2225             }
   2226         } else {
   2227             soc_mem_field32_set(unit, mem, buf_p, IPV6MC__L3_IIFf,
   2228                                 l3cfg->l3c_ing_intf);
   2229             key_type = TD2_L3_HASH_KEY_TYPE_V6MC;
   2230         }
   2231         if (soc_feature(unit, soc_feature_base_valid)) {
   2232             /* Set key type */
   2233             soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf, key_type);
   2234             if (soc_mem_field_valid(unit, mem, DATA_TYPEf)) {
   2235             soc_mem_field32_set(unit, mem, buf_p, DATA_TYPEf, key_type);
   2236             }
   2237             /* Set entry valid bit. */
   2238             if (SOC_IS_TOMAHAWK3(unit)) {
   2239                 base_valid0 = 1;
   2240                 base_valid1 = 2;
   2241                 base_valid2 = 2;
   2242                 base_valid3 = 7;
   2243             } else {
   2244                 base_valid0 = 5;
   2245                 base_valid1 = 6;
   2246                 base_valid2 = 6;
   2247                 base_valid3 = 7;
   2248             }
   2249             soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_0f, base_valid0);
   2250             soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_1f, base_valid1);
   2251             soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_2f, base_valid2);
   2252             soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_3f, base_valid3);
   2253         } else {
   2254         for (idx = 0; idx < 4; idx++) {
   2255             /* Set key type */
   2256             soc_mem_field32_set(unit, mem, buf_p, v6typef[idx], 
   2257                                 key_type);
   2258             /* Set entry valid bit. */
   2259             soc_mem_field32_set(unit, mem, buf_p, validf[idx], 1);
   2260             }
   2261         }
   2262         /* Set virtual router id. */
   2263         soc_mem_field32_set(unit, mem, buf_p, IPV6MC__VRF_IDf, l3cfg->l3c_vrf);
   2264 
   2265     } else {
   2266         /* Set group id. */
   2267         soc_mem_field32_set(unit, mem, buf_p, IPV4MC__GROUP_IP_ADDRf,
   2268                             l3cfg->l3c_ip_addr);
   2269 
   2270         /* Set source address. */
   2271         soc_mem_field32_set(unit, mem, buf_p, IPV4MC__SOURCE_IP_ADDRf,
   2272                             l3cfg->l3c_src_ip_addr);
   2273 
   2274         if ((l3cfg->l3c_flags & BCM_L3_L2ONLY) ||
   2275                 (l3cfg->l3c_ing_intf == BCM_IF_INVALID)) {
   2276             if (_BCM_VPN_IS_SET(l3cfg->l3c_vid)) {
   2277 
   2278                 if (soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) && 
   2279                    (l3cfg->l3c_flags & BCM_L3_L2ONLY)) {
   2280                     if (_BCM_VPN_IS_L3(l3cfg->l3c_vid)) {
   2281                         _BCM_VPN_GET(vfi, _BCM_VPN_TYPE_L3, l3cfg->l3c_vid);
   2282                     } else if (_BCM_VPN_IS_VPWS(l3cfg->l3c_vid)) {
   2283                         _BCM_VPN_GET(vfi, _BCM_VPN_TYPE_VPWS, l3cfg->l3c_vid);
   2284                     } else {
   2285                         _BCM_VPN_GET(vfi, _BCM_VPN_TYPE_VFI, l3cfg->l3c_vid);
   2286                     }
   2287                     soc_mem_field32_set(unit, mem, buf_p, IPV4MC__VFIf, vfi); 
   2288                     key_type = TD2_L3_HASH_KEY_TYPE_V4L2VPMC;
   2289                 } else {
   2290                     soc_mem_field32_set(unit, mem, buf_p, IPV4MC__L3_IIFf, l3cfg->l3c_vid);
   2291                     key_type = TD2_L3_HASH_KEY_TYPE_V4MC;
   2292                 }
   2293             } else {
   2294                 soc_mem_field32_set(unit, mem, buf_p, IPV4MC__VLAN_IDf, l3cfg->l3c_vid);
   2295                 key_type = TD2_L3_HASH_KEY_TYPE_V4L2MC;
   2296             }
   2297             if (!soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) ||
   2298                  !soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) {
   2299                 /* Override the key in case feature not supported */
   2300                 key_type = TD2_L3_HASH_KEY_TYPE_V4MC;
   2301             }
   2302         } else {
   2303             /* L3_IIF. */
   2304             soc_mem_field32_set(unit, mem, buf_p, IPV4MC__L3_IIFf, l3cfg->l3c_ing_intf);
   2305             key_type = TD2_L3_HASH_KEY_TYPE_V4MC;
   2306         }
   2307 
   2308         if (soc_feature(unit, soc_feature_base_valid)) {
   2309             /* Set key type */
   2310             soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf, key_type);
   2311             if (soc_mem_field_valid(unit, mem, DATA_TYPEf)) {
   2312             soc_mem_field32_set(unit, mem, buf_p, DATA_TYPEf, key_type);
   2313             }
   2314             /* Set entry valid bit. */
   2315             if (!SOC_IS_TOMAHAWK3(unit)) {
   2316                 base_valid0 = 3;
   2317                 base_valid1 = 4;
   2318             } else {
   2319                 base_valid0 = 1;
   2320                 base_valid1 = 7;
   2321             }
   2322             soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_0f, base_valid0);
   2323             soc_mem_field32_set(unit, mem, buf_p, BASE_VALID_1f, base_valid1);
   2324         } else {
   2325         for (idx = 0; idx < 2; idx++) {
   2326             /* Set key type */
   2327             soc_mem_field32_set(unit, mem, buf_p, v4typef[idx], 
   2328                                 key_type);
   2329             /* Set entry valid bit. */
   2330             soc_mem_field32_set(unit, mem, buf_p, validf[idx], 1);
   2331         }
   2332         }
   2333         /* Set virtual router id. */
   2334         soc_mem_field32_set(unit, mem, buf_p, IPV4MC__VRF_IDf, l3cfg->l3c_vrf);
   2335     }
   2336 
   2337 #ifdef BCM_TOMAHAWK_SUPPORT
   2338     if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
   2339         /* 
   2340          * This Tomahawk specific code handles migration of 
   2341          * T, MODULE_Id, PORT_NUM, TGID fields from L3_IPMC_1 table to
   2342          * L3_ENTRY_IPV4_MULTICAST table 
   2343          */
   2344         int is_trunk, mod, port_tgid, no_src_check = FALSE;
   2345         soc_field_t trunk_port, module_id,port_num, trunk_id;
   2346         
   2347         if (ipv6) {
   2348             trunk_port = IPV6MC__Tf;
   2349             module_id  = IPV6MC__MODULE_IDf;
   2350             port_num   = IPV6MC__PORT_NUMf;
   2351             trunk_id   = IPV6MC__TGIDf;
   2352         } else {
   2353             trunk_port = IPV4MC__Tf;
   2354             module_id  = IPV4MC__MODULE_IDf;
   2355             port_num   = IPV4MC__PORT_NUMf;
   2356             trunk_id   = IPV4MC__TGIDf;
   2357         }
   2358         if ((l3cfg->l3c_flags & BCM_IPMC_SOURCE_PORT_NOCHECK) ||
   2359             (l3cfg->l3c_port_tgid < 0)) {                       /* no source port */
   2360             no_src_check = TRUE;
   2361             is_trunk = 0;
   2362             mod = SOC_MODID_MAX(unit);
   2363             port_tgid = TH_IPMC_NO_SRC_CHECK_PORT;
   2364         } else if (l3cfg->l3c_tunnel) {                         /* trunk source port */
   2365             is_trunk = 1;
   2366             mod = 0;
   2367             port_tgid = l3cfg->l3c_port_tgid;
   2368         } else {                                               /* source port */
   2369             bcm_module_t    mod_in, mod_out;
   2370             bcm_port_t      port_in, port_out;
   2371     
   2372             mod_in = l3cfg->l3c_modid;
   2373             port_in = l3cfg->l3c_port_tgid;
   2374             BCM_IF_ERROR_RETURN
   2375                 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET,
   2376                                         mod_in, port_in,
   2377                                         &mod_out, &port_out));
   2378             /* Check parameters, since above is an application callback */
   2379             if (!SOC_MODID_ADDRESSABLE(unit, mod_out)) {
   2380                 return BCM_E_BADID;
   2381             }
   2382             if (!SOC_PORT_ADDRESSABLE(unit, port_out)) {
   2383                 return BCM_E_PORT;
   2384             }
   2385             is_trunk = 0;
   2386             mod = mod_out;
   2387             port_tgid = port_out;
   2388         }
   2389     
   2390         if (is_trunk) {
   2391             soc_mem_field32_set(unit, mem, buf_p, trunk_port, 1);
   2392             soc_mem_field32_set(unit, mem, buf_p, trunk_id,  port_tgid);
   2393         } else {
   2394             if (!SOC_IS_TOMAHAWK3(unit)) {
   2395             soc_mem_field32_set(unit, mem, buf_p, module_id, mod);
   2396             }
   2397             soc_mem_field32_set(unit, mem, buf_p, port_num,  port_tgid);
   2398             if (no_src_check) {
   2399                 /* For no src check program all 1's in Tf, MOD_ID and PORT_NUM */
   2400                 if (SOC_IS_TRIDENT3X(unit))
   2401                     soc_mem_field32_set(unit, mem, buf_p, trunk_port, 0);
   2402                 else
   2403                 soc_mem_field32_set(unit, mem, buf_p, trunk_port, 1);
   2404             } else {
   2405                 soc_mem_field32_set(unit, mem, buf_p, trunk_port, 0);
   2406             }
   2407         }
   2408     
   2409     }
   2410 #endif
   2411 
   2412     return rv;
   2413 }
   2414 
   2415 /*
   2416  * Function:
   2417  *      _bcm_td2_l3_ipmc_ent_parse
   2418  * Purpose:
   2419  *      Service routine used to parse hw l3 ipmc entry to api format.
   2420  * Parameters:
   2421  *      unit      - (IN)SOC unit number. 
   2422  *      l3cfg     - (IN/OUT)l3 entry parsing destination buf.
   2423  *      l3x_entry - (IN/OUT)hw buffer.
   2424  * Returns:
   2425  *      void
   2426  */
   2427 STATIC int
   2428 _bcm_td2_l3_ipmc_ent_parse(int unit, _bcm_l3_cfg_t *l3cfg,
   2429                           l3_entry_ipv6_multicast_entry_t *l3x_entry)
   2430 {
   2431     soc_mem_t mem;                     /* IPMC table memory.    */
   2432     uint32 *buf_p;                     /* HW buffer address.    */
   2433     int ipv6;                          /* IPv6 entry indicator. */
   2434     uint32 hit = 0;                    /* composite hit = hit_x|hit_y */
   2435     l3_entry_hit_only_x_entry_t hit_x;
   2436     l3_entry_hit_only_y_entry_t hit_y;
   2437     l3_entry_hit_only_entry_t hit_default;
   2438     int idx, idx_max, idx_offset, hit_idx_shift;   /* Iteration index.      */
   2439     soc_field_t hitf[] = {HIT_0f, HIT_1f, HIT_2f, HIT_3f};
   2440     soc_field_t rpe, dst_discard, vrf_id, l3mc_idx, l3mc_idx_l2, class_id, pri,
   2441                 rpa_id, expected_l3_iif, l3iif;
   2442 #ifdef BCM_MONTEREY_SUPPORT
   2443     soc_field_t vlan_id;
   2444     soc_field_t roe_decap;
   2445 #endif
   2446     soc_field_t rpf_fail_drop, rpf_fail_tocpu;
   2447     soc_field_t trunk_port, module_id, source_vp, port_num, trunk_id, svp_valid;
   2448     soc_field_t flex_ctr_base_counter_idx;
   2449     soc_field_t flex_ctr_offset_mode;
   2450     soc_field_t flex_ctr_pool_number;
   2451     uint8 l2only = 0;                   /* Entry is L2 only domain */
   2452     buf_p = (uint32 *)l3x_entry;
   2453 
   2454     /* Get entry type. */
   2455     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
   2456     l2only = (l3cfg->l3c_flags & BCM_L3_L2ONLY);
   2457 
   2458     /* Get table memory and table fields */
   2459     if (ipv6) {
   2460         if (soc_mem_is_valid(unit, L3_ENTRY_QUADm)) {
   2461             mem         = L3_ENTRY_QUADm;
   2462             if (soc_mem_field_valid(unit, L3_ENTRY_QUADm,
   2463                                     IPV6MC__DESTINATIONf)) {
   2464             l3mc_idx    = IPV6MC__DESTINATIONf;
   2465         } else {
   2466                 l3mc_idx = IPV6MC__L3MC_INDEXf;
   2467             }
   2468             l3mc_idx_l2 = IPV6MC__L3MC_INDEX_FOR_L2_DISTRIBUTIONf;
   2469         } else {
   2470         mem         = L3_ENTRY_IPV6_MULTICASTm;
   2471             l3mc_idx    = IPV6MC__L3MC_INDEXf;
   2472             l3mc_idx_l2 = INVALIDf;
   2473         }
   2474         pri         = IPV6MC__PRIf;
   2475         rpe         = IPV6MC__RPEf;
   2476         vrf_id      = IPV6MC__VRF_IDf;
   2477         l3iif       = IPV6MC__L3_IIFf;
   2478 #ifdef BCM_MONTEREY_SUPPORT
   2479         vlan_id     = IPV6MC__VLAN_IDf;
   2480         roe_decap   = IPV6MC__ROE_DECAPf;
   2481 #endif
   2482         class_id    = IPV6MC__CLASS_IDf;
   2483         dst_discard = IPV6MC__DST_DISCARDf;
   2484         rpa_id      = IPV6MC__RPA_IDf;
   2485         expected_l3_iif = IPV6MC__EXPECTED_L3_IIFf;
   2486         rpf_fail_drop   = IPV6MC__IPMC_EXPECTED_L3_IIF_MISMATCH_DROPf;
   2487         rpf_fail_tocpu  = IPV6MC__IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPUf;
   2488         idx_max     = 4;
   2489         hit_idx_shift = 0;
   2490         idx_offset = 0;
   2491         trunk_port = IPV6MC__Tf;
   2492         module_id  = IPV6MC__MODULE_IDf;
   2493         source_vp  = IPV6MC__SOURCE_VPf;
   2494         port_num   = IPV6MC__PORT_NUMf;
   2495         trunk_id   = IPV6MC__TGIDf;
   2496         svp_valid  = IPV6MC__SVP_VALIDf;
   2497         flex_ctr_base_counter_idx = IPV6MC__FLEX_CTR_BASE_COUNTER_IDXf;
   2498         flex_ctr_offset_mode      = IPV6MC__FLEX_CTR_OFFSET_MODEf;
   2499         flex_ctr_pool_number      = IPV6MC__FLEX_CTR_POOL_NUMBERf;
   2500     } else {
   2501         if (soc_mem_is_valid(unit, L3_ENTRY_DOUBLEm)) {
   2502             mem         = L3_ENTRY_DOUBLEm;
   2503             if (SOC_MEM_FIELD_VALID(unit, L3_ENTRY_DOUBLEm, 
   2504 									IPV4MC__DESTINATIONf)) {
   2505             l3mc_idx    = IPV4MC__DESTINATIONf;
   2506         } else {
   2507                 l3mc_idx = IPV4MC__L3MC_INDEXf;
   2508             }
   2509             l3mc_idx_l2 = IPV4MC__L3MC_INDEX_FOR_L2_DISTRIBUTIONf;
   2510         } else {
   2511         mem         = L3_ENTRY_IPV4_MULTICASTm;
   2512             l3mc_idx    = IPV4MC__L3MC_INDEXf;
   2513             l3mc_idx_l2 = INVALIDf;
   2514         }
   2515         pri         = IPV4MC__PRIf;
   2516         rpe         = IPV4MC__RPEf;
   2517         vrf_id      = IPV4MC__VRF_IDf;
   2518         l3iif       = IPV4MC__L3_IIFf;
   2519 #ifdef BCM_MONTEREY_SUPPORT
   2520         vlan_id     = IPV4MC__VLAN_IDf;
   2521         roe_decap   = IPV4MC__ROE_DECAPf;
   2522 #endif
   2523         class_id    = IPV4MC__CLASS_IDf;
   2524         dst_discard = IPV4MC__DST_DISCARDf;
   2525         rpa_id      = IPV4MC__RPA_IDf;
   2526         expected_l3_iif = IPV4MC__EXPECTED_L3_IIFf;
   2527         rpf_fail_drop   = IPV4MC__IPMC_EXPECTED_L3_IIF_MISMATCH_DROPf;
   2528         rpf_fail_tocpu  = IPV4MC__IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPUf;
   2529         idx_max     = 2;
   2530         hit_idx_shift = 1;
   2531         idx_offset = (l3cfg->l3c_hw_index & 0x1) << 1;
   2532         trunk_port = IPV4MC__Tf;
   2533         module_id  = IPV4MC__MODULE_IDf;
   2534         source_vp  = IPV4MC__SOURCE_VPf;
   2535         port_num   = IPV4MC__PORT_NUMf;
   2536         trunk_id   = IPV4MC__TGIDf;
   2537         svp_valid  = IPV4MC__SVP_VALIDf;
   2538         flex_ctr_base_counter_idx = IPV4MC__FLEX_CTR_BASE_COUNTER_IDXf;
   2539         flex_ctr_offset_mode      = IPV4MC__FLEX_CTR_OFFSET_MODEf;
   2540         flex_ctr_pool_number      = IPV4MC__FLEX_CTR_POOL_NUMBERf;
   2541     }
   2542 
   2543     /* Mark entry as multicast & clear rest of the flags. */
   2544     l3cfg->l3c_flags = BCM_L3_IPMC;
   2545     if (ipv6) {
   2546        l3cfg->l3c_flags |= BCM_L3_IP6;
   2547     }
   2548     if (l2only) {
   2549         l3cfg->l3c_flags |= BCM_L3_L2ONLY;
   2550     }
   2551 
   2552     if (soc_feature(unit, soc_feature_multi_pipe_mapped_ports)) {
   2553         BCM_IF_ERROR_RETURN(
   2554             BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLYm,
   2555               (l3cfg->l3c_hw_index >> hit_idx_shift), &hit_x));
   2556 
   2557         /* Read hit value. */
   2558         for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) {
   2559             hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLYm,
   2560                     &hit_x, hitf[idx]);
   2561         }
   2562 
   2563         /* Check Source Virtual Port */
   2564         if (soc_mem_field_valid(unit, mem, svp_valid) && 
   2565 		    soc_mem_field32_get(unit, mem, buf_p, svp_valid)) {
   2566             l3cfg->l3c_port_tgid = soc_mem_field32_get(unit, mem, buf_p,
   2567 															 source_vp);
   2568         } else {  /* Check Trunk Port */
   2569             if (soc_mem_field32_get(unit, mem, buf_p, trunk_port)) {
   2570                 l3cfg->l3c_tunnel = 1;
   2571                 l3cfg->l3c_port_tgid = soc_mem_field32_get(unit, mem, buf_p, trunk_id);
   2572                 if ((SOC_MEM_FIELD_VALID(unit, mem, module_id)) &&
   2573                    (((l3cfg->l3c_port_tgid & TH_IPMC_NO_SRC_CHECK_PORT)
   2574                                 == TH_IPMC_NO_SRC_CHECK_PORT)) &&
   2575                         (soc_mem_field32_get(unit, mem, buf_p, module_id) == SOC_MODID_MAX(unit))) {
   2576                     l3cfg->l3c_flags |= BCM_IPMC_SOURCE_PORT_NOCHECK;
   2577                     l3cfg->l3c_modid = SOC_MODID_MAX(unit);
   2578                 } else {
   2579                     l3cfg->l3c_flags |= BCM_L3_TGID;
   2580                 }
   2581             } else {
   2582 #ifdef BCM_TRIDENT3_SUPPORT
   2583                 if (SOC_IS_TRIDENT3X(unit) &&
   2584                     ((((l3cfg->l3c_port_tgid & TH_IPMC_NO_SRC_CHECK_PORT)
   2585                             == TH_IPMC_NO_SRC_CHECK_PORT)) &&
   2586                     (soc_mem_field32_get(unit, mem, buf_p, module_id)
   2587                             == SOC_MODID_MAX(unit)))) {
   2588                     l3cfg->l3c_flags |= BCM_IPMC_SOURCE_PORT_NOCHECK;
   2589                     l3cfg->l3c_modid = SOC_MODID_MAX(unit);
   2590                 } else
   2591 #endif /* BCM_TRIDENT3_SUPPORT */
   2592                 {
   2593                     if (soc_mem_field_valid(unit, mem, module_id)) {
   2594                     l3cfg->l3c_modid = soc_mem_field32_get(unit, mem, buf_p,
   2595                                                            module_id);
   2596                     }
   2597                     l3cfg->l3c_port_tgid = soc_mem_field32_get(unit, mem, buf_p,
   2598                                                                port_num);
   2599                 }
   2600                 l3cfg->l3c_tunnel = 0;
   2601             }
   2602         }
   2603     } else if (soc_feature(unit, soc_feature_two_ingress_pipes) &&
   2604                !SOC_IS_TRIDENT3X(unit)) {
   2605         BCM_IF_ERROR_RETURN(
   2606             BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLY_Xm,
   2607               (l3cfg->l3c_hw_index >> hit_idx_shift), &hit_x));
   2608 
   2609         BCM_IF_ERROR_RETURN(
   2610             BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLY_Ym,
   2611               (l3cfg->l3c_hw_index >> hit_idx_shift), &hit_y));
   2612 
   2613         /* Read hit value. */
   2614         for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) {
   2615             hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLY_Xm,
   2616                                        &hit_x, hitf[idx]);
   2617         }
   2618 
   2619         for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) {
   2620             hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLY_Ym,
   2621                                        &hit_y, hitf[idx]);
   2622         }
   2623     } else {
   2624         BCM_IF_ERROR_RETURN(
   2625             BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLYm,
   2626               (l3cfg->l3c_hw_index >> hit_idx_shift), &hit_default));
   2627 
   2628         /* Read hit value. */
   2629         for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) {
   2630             hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLYm,
   2631                                        &hit_default, hitf[idx]);
   2632         }
   2633     }
   2634 
   2635     if (hit) {
   2636         l3cfg->l3c_flags |= BCM_L3_HIT;
   2637     }
   2638 
   2639     /* Set ipv6 group address to multicast. */
   2640     if (ipv6) {
   2641         l3cfg->l3c_ip6[0] = 0xff;   /* Set entry ip to mcast address. */
   2642     }
   2643     if (l2only) {
   2644         /* Vlan/VFI is key, read L3iif */
   2645         l3cfg->l3c_ing_intf = soc_mem_field32_get(unit, mem, buf_p, l3iif);
   2646     } else {
   2647         /* L3IIF is key, read vid */
   2648 #ifdef BCM_MONTEREY_SUPPORT
   2649         if (SOC_IS_MONTEREY(unit)) {
   2650             l3cfg->l3c_vid = soc_mem_field32_get(unit, mem, buf_p, vlan_id);
   2651         } else
   2652 #endif
   2653         {
   2654             l3cfg->l3c_vid = soc_mem_field32_get(unit, mem, buf_p, l3iif);
   2655         }
   2656     }
   2657     /* Read priority override */
   2658     if(soc_mem_field32_get(unit, mem, buf_p, rpe)) { 
   2659         l3cfg->l3c_flags |= BCM_L3_RPE;
   2660     }
   2661 
   2662     /* Read destination discard bit. */
   2663     if(soc_mem_field32_get(unit, mem, buf_p, dst_discard)) { 
   2664         l3cfg->l3c_flags |= BCM_L3_DST_DISCARD;
   2665     }
   2666 
   2667     /* Read Virtual Router Id. */
   2668     l3cfg->l3c_vrf = soc_mem_field32_get(unit, mem, buf_p, vrf_id);
   2669 
   2670     /* Pointer to ipmc replication table. */
   2671     if (soc_feature(unit, soc_feature_generic_dest)) {
   2672         uint32 dest_type = SOC_MEM_FIF_DEST_INVALID;
   2673         l3cfg->l3c_ipmc_ptr = soc_mem_field32_dest_get(unit, mem, buf_p,
   2674                                 l3mc_idx, &dest_type);
   2675         if (dest_type != SOC_MEM_FIF_DEST_IPMC) {
   2676             return BCM_E_FAIL;
   2677         }
   2678     } else {
   2679     l3cfg->l3c_ipmc_ptr = soc_mem_field32_get(unit, mem, buf_p, l3mc_idx);
   2680     }
   2681 
   2682     if (l3mc_idx_l2 != INVALIDf && soc_mem_field_valid(unit, mem, l3mc_idx_l2)) {
   2683         l3cfg->l3c_ipmc_ptr_l2 = soc_mem_field32_get(unit, mem, buf_p, l3mc_idx_l2);
   2684     }
   2685 
   2686     /* Classification lookup class id. */
   2687     l3cfg->l3c_lookup_class = soc_mem_field32_get(unit, mem, buf_p, class_id);
   2688 
   2689     /* Read priority value. */
   2690     l3cfg->l3c_prio = soc_mem_field32_get(unit, mem, buf_p, pri);
   2691 
   2692     /* Read RPA_ID value. */
   2693     if (soc_mem_field_valid(unit, mem, rpa_id)) {
   2694     l3cfg->l3c_rp_id = soc_mem_field32_get(unit, mem, buf_p, rpa_id);
   2695     } else {
   2696         l3cfg->l3c_rp_id = 0;
   2697     }
   2698 
   2699     if (l3cfg->l3c_rp_id == 0 &&
   2700         (l3cfg->l3c_vid != 0 ||
   2701          soc_mem_field32_get(unit, mem, buf_p, expected_l3_iif) != 0)) {
   2702         /* If RPA_ID field value is 0, it could mean (1) this IPMC entry is
   2703          * not a PIM-BIDIR entry, or (2) this entry is a PIM-BIDIR entry and
   2704          * is associated with rendezvous point 0. If either the L3 IIF in the
   2705          * key or the expected L3 IIF in the data is not zero, this
   2706          * entry is not a PIM-BIDIR entry.
   2707          */ 
   2708         l3cfg->l3c_rp_id = BCM_IPMC_RP_ID_INVALID;
   2709     }
   2710 
   2711     /* Read expected iif */
   2712     l3cfg->l3c_intf = soc_mem_field32_get(unit, mem, buf_p, expected_l3_iif);
   2713     if (0 != l3cfg->l3c_intf) {
   2714         l3cfg->l3c_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK;
   2715     }
   2716     if (soc_mem_field32_get(unit, mem, buf_p, rpf_fail_drop)) {
   2717         l3cfg->l3c_flags |= BCM_IPMC_RPF_FAIL_DROP;
   2718     }
   2719     if (soc_mem_field32_get(unit, mem, buf_p, rpf_fail_tocpu)) {
   2720         l3cfg->l3c_flags |= BCM_IPMC_RPF_FAIL_TOCPU;
   2721     }
   2722 
   2723     
   2724     if (!SOC_IS_MONTEREY(unit)) {
   2725     /* Read base counter index. */
   2726     l3cfg->l3c_flex_ctr_base_id =
   2727         soc_mem_field32_get(unit, mem, buf_p, flex_ctr_base_counter_idx);
   2728     /* Read counter offset mode. */
   2729     l3cfg->l3c_flex_ctr_mode =
   2730         soc_mem_field32_get(unit, mem, buf_p, flex_ctr_offset_mode);
   2731     /* Read counter pool number. */
   2732     l3cfg->l3c_flex_ctr_pool =
   2733         soc_mem_field32_get(unit, mem, buf_p, flex_ctr_pool_number);
   2734     }
   2735 
   2736 #ifdef BCM_MONTEREY_SUPPORT
   2737     if (soc_feature(unit, soc_feature_roe) ||
   2738         soc_feature(unit, soc_feature_roe_custom)) {
   2739         if (SOC_MEM_FIELD_VALID(unit, mem, roe_decap)) {
   2740             if (soc_mem_field32_get(unit, mem, buf_p, roe_decap)) {
   2741                 l3cfg->l3c_flags2 |= BCM_L3_FLAGS2_DECAP_ROE_HEADER;
   2742             }
   2743         }
   2744     }
   2745 #endif
   2746 
   2747     return BCM_E_NONE;
   2748 }
   2749 
   2750 /*
   2751  * Function:
   2752  *      _bcm_td2_l3_host_stat_get_table_info
   2753  * Description:
   2754  *      Provides relevant flex table information(table-name,index with
   2755  *      direction)  for given L3 Host entry
   2756  *
   2757  * Parameters:
   2758  *      unit             - (IN) unit number
   2759  *      port             - (IN) GPORT ID
   2760  *      num_of_tables    - (OUT) Number of flex counter tables
   2761  *      table_info       - (OUT) Flex counter tables information
   2762  *
   2763  * Return Value:
   2764  *      BCM_E_XXX
   2765  * Notes:
   2766  */
   2767 STATIC bcm_error_t
   2768 _bcm_td2_l3_host_stat_get_table_info(
   2769                    int                        unit,
   2770                    bcm_l3_host_t              *info,
   2771                    uint32                     *num_of_tables,
   2772                    bcm_stat_flex_table_info_t *table_info)
   2773 {
   2774     int rv, embd;
   2775     soc_mem_t mem;          
   2776     _bcm_l3_cfg_t l3cfg;     
   2777 
   2778     if (NULL == info) {
   2779         return (BCM_E_PARAM);
   2780     }
   2781 
   2782     if (!(soc_feature(unit, soc_feature_l3_extended_host_entry))) {
   2783         return BCM_E_UNAVAIL;
   2784     }
   2785 
   2786     mem = INVALIDm;
   2787     /* Vrf is in device supported range check. */
   2788     if ((info->l3a_vrf > SOC_VRF_MAX(unit)) || 
   2789         (info->l3a_vrf < BCM_L3_VRF_DEFAULT)) {
   2790         return (BCM_E_PARAM);
   2791     }
   2792   
   2793     sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   2794     l3cfg.l3c_flags = info->l3a_flags;
   2795     l3cfg.l3c_vrf = info->l3a_vrf;
   2796 
   2797     if (info->l3a_flags & BCM_L3_IP6) {
   2798         sal_memcpy(l3cfg.l3c_ip6, info->l3a_ip6_addr, BCM_IP6_ADDRLEN);
   2799     } else {
   2800         l3cfg.l3c_ip_addr = info->l3a_ip_addr;
   2801     }
   2802    
   2803     rv = _bcm_td2_l3_entry_get(unit, &l3cfg, NULL, &embd);
   2804     if (BCM_SUCCESS(rv)) { /* Entry found */
   2805 #ifdef BCM_TRIDENT3_SUPPORT
   2806         if (SOC_IS_TRIDENT3X(unit)) {
   2807             mem = (l3cfg.l3c_flags & BCM_L3_IP6) ? L3_ENTRY_QUADm :
   2808                                                L3_ENTRY_DOUBLEm;
   2809         } else 
   2810 #endif
   2811         {
   2812             if (embd != TRUE) {
   2813                 return (BCM_E_PARAM);
   2814             }
   2815         mem = (l3cfg.l3c_flags & BCM_L3_IP6) ? L3_ENTRY_IPV6_MULTICASTm :
   2816                                                L3_ENTRY_IPV4_MULTICASTm;       
   2817         }
   2818 
   2819         table_info[*num_of_tables].table = mem;
   2820         table_info[*num_of_tables].index = l3cfg.l3c_hw_index;
   2821         table_info[*num_of_tables].direction = bcmStatFlexDirectionIngress;
   2822         (*num_of_tables)++;
   2823     }
   2824     
   2825     return rv;
   2826 }
   2827 
   2828 /*----- END STATIC FUNCS ----- */
   2829 
   2830 /*
   2831  * Function:
   2832  *      _bcm_td2_l3_add
   2833  * Purpose:
   2834  *      Add and entry to TD2 L3 host table.
   2835  *      The decision to add to is based on 
   2836  *      switch control(s) and table full conditions.
   2837  *      conditions.
   2838  * Parameters:
   2839  *      unit   - (IN) SOC unit number.
   2840  *      l3cfg  - (IN) L3 entry info.
   2841  *      nh_idx - (IN) Next hop index.
   2842  * Returns:
   2843  *      BCM_E_XXX
   2844  */
   2845 int
   2846 _bcm_td2_l3_add(int unit, _bcm_l3_cfg_t *l3cfg, int nh_idx)
   2847 {
   2848     int rv;
   2849 
   2850     rv = _bcm_td2_l3_entry_add(unit, l3cfg, nh_idx);
   2851     return rv;
   2852 }
   2853 
   2854 /*
   2855  * Function:
   2856  *      _bcm_td2_l3_get
   2857  * Purpose:
   2858  *      Get an entry from TD2 L3 host table.
   2859  * Parameters:
   2860  *      unit     - (IN) SOC unit number.
   2861  *      l3cfg    - (IN/OUT) L3 entry  lookup key & search result.
   2862  *      nh_index - (IN/OUT) Next hop index.
   2863  * Returns:
   2864  *      BCM_E_XXX
   2865  */
   2866 int
   2867 _bcm_td2_l3_get(int unit, _bcm_l3_cfg_t *l3cfg, int *nh_idx)
   2868 {
   2869     int rv;
   2870     int embd = _BCM_TD2_HOST_ENTRY_NOT_FOUND;
   2871 
   2872     rv = _bcm_td2_l3_entry_get(unit, l3cfg, nh_idx, &embd);
   2873     return rv;
   2874 }
   2875 
   2876 /*
   2877  * Function:
   2878  *      _bcm_td2_l3_del
   2879  * Purpose:
   2880  *      Del an entry from TD2 L3 host table.
   2881  * Parameters:
   2882  *      unit     - (IN) SOC unit number.
   2883  *      l3cfg    - (IN/OUT) L3 entry  lookup key & search result.
   2884  *      nh_index - (IN/OUT) Next hop index.
   2885  * Returns:
   2886  *      BCM_E_XXX
   2887  */
   2888 int
   2889 _bcm_td2_l3_del(int unit, _bcm_l3_cfg_t *l3cfg)
   2890 {
   2891     int rv;
   2892 
   2893     /* Attempt to delete entry */
   2894     rv = _bcm_td2_l3_entry_del(unit, l3cfg);
   2895     return rv;
   2896 }
   2897 
   2898 /*
   2899  * Function:
   2900  *      _bcm_td2_l3_traverse
   2901  * Purpose:
   2902  *      Walk over range of entries in l3 host table.
   2903  * Parameters:
   2904  *      unit - SOC unit number.
   2905  *      flags - L3 entry flags to match during traverse.  
   2906  *      start - First index to read. 
   2907  *      end - Last index to read.
   2908  *      cb  - Caller notification callback.
   2909  *      user_data - User cookie, which should be returned in cb. 
   2910  * Returns:
   2911  *      BCM_E_XXX
   2912  */
   2913 int
   2914 _bcm_td2_l3_traverse(int unit, int flags, uint32 start, uint32 end,
   2915                       bcm_l3_host_traverse_cb cb, void *user_data)
   2916 {
   2917     int rv = BCM_E_NONE;
   2918     int ipv6;                   /* Protocol IPv6/IPv4          */
   2919     int nh_idx;                 /* Next hop index.                 */
   2920     int total = 0;              /* Total number of entries walked. */
   2921     int table_size;             /* Number of entries in the table. */
   2922     int table_ent_size;         /* Table entry size. */
   2923     bcm_l3_host_t info;         /* Callback info buffer.           */
   2924     _bcm_l3_cfg_t l3cfg;        /* HW entry info.                  */
   2925     char *l3_tbl_ptr = NULL;    /* Table dma pointer.              */
   2926     int tbl, idx, idx_min, idx_max;  /* Min and Max iteration index */
   2927     int num_tables = 2;
   2928     soc_mem_t mem[2] = {INVALIDm, INVALIDm};
   2929     int show_idx_flag;
   2930 
   2931     /* If no callback provided, we are done.  */
   2932     if (NULL == cb) {
   2933         return (BCM_E_NONE);
   2934     }
   2935 
   2936     ipv6 = (flags & BCM_L3_IP6) ? TRUE : FALSE;
   2937     show_idx_flag = (flags & _BCM_L3_SHOW_INDEX) ? TRUE : FALSE;
   2938     /* If table is empty -> there is nothing to read. */
   2939     if (ipv6 && (!BCM_XGS3_L3_IP6_CNT(unit))) {
   2940         return (BCM_E_NONE);
   2941     }
   2942     if (!ipv6 && (!BCM_XGS3_L3_IP4_CNT(unit))) {
   2943         return (BCM_E_NONE);
   2944     }
   2945 
   2946     if (ipv6) {
   2947         mem[0] = BCM_XGS3_L3_MEM(unit, v6); 
   2948         if (soc_feature(unit, soc_feature_l3_extended_host_entry)) {
   2949             mem[1] = BCM_XGS3_L3_MEM(unit, v6_4); 
   2950         }
   2951     } else {
   2952         mem[0] = BCM_XGS3_L3_MEM(unit, v4); 
   2953         if (soc_feature(unit, soc_feature_l3_extended_host_entry)) {
   2954             mem[1] = BCM_XGS3_L3_MEM(unit, v4_2); 
   2955         }
   2956     }
   2957 
   2958     for(tbl = 0; tbl < num_tables; tbl++) {
   2959   
   2960         if (INVALIDm == mem[tbl]) {
   2961             continue;
   2962         }
   2963         idx_max = soc_mem_index_max(unit, mem[tbl]);
   2964         idx_min =  soc_mem_index_min(unit, mem[tbl]);
   2965         table_ent_size = BCM_L3_MEM_ENT_SIZE(unit, mem[tbl]);
   2966 
   2967         BCM_IF_ERROR_RETURN (bcm_xgs3_l3_tbl_dma(unit, mem[tbl], table_ent_size, 
   2968                                       "l3_tbl", &l3_tbl_ptr, &table_size));
   2969 
   2970         /* Input index`s sanity. */
   2971         if (start > (uint32)table_size || start > end) {
   2972             if(l3_tbl_ptr) {
   2973                 soc_cm_sfree(unit, l3_tbl_ptr);
   2974             }
   2975             return (BCM_E_NOT_FOUND);
   2976         }
   2977 
   2978         /* Iterate over all the entries - show matching ones. */
   2979         for (idx = idx_min; idx <= idx_max; idx++) {
   2980             /* Reset buffer before read. */
   2981             sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   2982             l3cfg.l3c_flags = flags;
   2983 
   2984             /* Get entry from  hw. */
   2985             rv = _bcm_td2_l3_get_host_ent_by_idx(unit, l3_tbl_ptr, mem[tbl],
   2986                                                   idx, &l3cfg, &nh_idx);
   2987 
   2988             /* Check for read errors & invalid entries. */
   2989             if (rv < 0) {
   2990                 if (rv != BCM_E_NOT_FOUND) {
   2991                     break;
   2992                 }
   2993                 continue;
   2994             }
   2995 #if defined(BCM_TRIDENT3_SUPPORT)
   2996             if (soc_feature(unit, soc_feature_flex_flow)
   2997                 && (l3cfg.l3c_flow_handle)
   2998                 && (l3cfg.l3c_flags & BCM_L3_IPMC))  {
   2999                 if (!IPMC_USED_ISSET(unit, l3cfg.l3c_ipmc_ptr)) {
   3000                    LOG_ERROR(BSL_LS_BCM_L3,
   3001                        (BSL_META_U(unit,
   3002                    "L3 host: Invalid IPMC group %d " \
   3003                    "in L3 host entry index %d\n"),
   3004                            l3cfg.l3c_ipmc_ptr, idx));
   3005                     continue;
   3006                 }
   3007 
   3008                 if (BCM_L3_CMP_EQUAL !=
   3009                     _bcm_td3_l3_flex_entry_flags_cmp(unit, flags, l3cfg.l3c_flags, &idx)) {
   3010                         continue;
   3011                 }
   3012 
   3013                 /* Valid entry found -> increment total table_sizeer */
   3014                 total++;
   3015                 if ((uint32)total < start) {
   3016                     continue;
   3017                 }
   3018 
   3019                 /* Don't read beyond last required index. */
   3020                 if ((uint32)total > end) {
   3021                     break;
   3022                 }
   3023 
   3024             } else
   3025 #endif /* BCM_TRIDENT3_SUPPORT */
   3026             {
   3027                 /* Check read entry flags & update index accordingly. */
   3028                 if (BCM_L3_CMP_EQUAL !=
   3029                     _bcm_xgs3_trvrs_flags_cmp(unit, flags, l3cfg.l3c_flags, &idx)) {
   3030                     continue;
   3031                 }
   3032 
   3033                 /* Valid entry found -> increment total table_sizeer */
   3034                 total++;
   3035                 if ((uint32)total < start) {
   3036                     continue;
   3037                 }
   3038 
   3039                 /* Don't read beyond last required index. */
   3040                 if ((uint32)total > end) {
   3041                     break;
   3042                 }
   3043 
   3044                 /* Get next hop info. */
   3045                 rv = _bcm_xgs3_l3_get_nh_info(unit, &l3cfg, nh_idx);
   3046                 if (rv < 0) {
   3047                     continue;
   3048                 }
   3049             }
   3050 
   3051             /* Fill host info. */
   3052             _bcm_xgs3_host_ent_init(unit, &l3cfg, TRUE, &info);
   3053             if (show_idx_flag && user_data) {
   3054                 *(int *)user_data = idx;
   3055             }
   3056 
   3057             if (cb) {
   3058                 rv = (*cb) (unit, total, &info, user_data);
   3059 #ifdef BCM_CB_ABORT_ON_ERR
   3060                 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   3061                     break;
   3062                 }
   3063 #endif
   3064             }
   3065         }
   3066 
   3067         if (l3_tbl_ptr) {
   3068             soc_cm_sfree(unit, l3_tbl_ptr);
   3069         }
   3070     }
   3071 
   3072     /* Reset last read status. */
   3073     if (BCM_E_NOT_FOUND == rv) {
   3074         rv = BCM_E_NONE;
   3075     }
   3076 
   3077     return (rv);
   3078 
   3079 }
   3080 
   3081 /*
   3082  * Function:
   3083  *      _bcm_td2_l3_host_stat_attach
   3084  * Description:
   3085  *      Attach counters entries to the given L3 host entry
   3086  *
   3087  * Parameters:
   3088  *      unit             - (IN) unit number
   3089  *      info             - (IN) L3 host description  
   3090  *      stat_counter_id  - (IN) Stat Counter ID.
   3091  *
   3092  * Return Value:
   3093  *      BCM_E_XXX
   3094  * Notes:
   3095  *      On BCM56640, the L3 host tables (tables L3_ENTRY_2 and L3_ENTRY_4, 
   3096  *      table EXT_L3_UCAST_DATA_WIDE) may contain a flex stat pointer when 
   3097  *      entry has a dereference next hop (no NEXT_HOP pointer, but the NH info 
   3098  *      instead).  This counter is analogous to what would be in the egress 
   3099  *      object, but is implemented in the ingress and so requires an ingress 
   3100  *      counter pool allocated.
   3101  */
   3102 bcm_error_t
   3103 _bcm_td2_l3_host_stat_attach(
   3104             int unit,
   3105             bcm_l3_host_t *info,
   3106             uint32 stat_counter_id)
   3107 {
   3108     soc_mem_t                 table[4]={0};
   3109     uint32                    flex_table_index=0;
   3110     bcm_stat_flex_direction_t direction=bcmStatFlexDirectionIngress;
   3111     uint32                    pool_number=0;
   3112     uint32                    base_index=0;
   3113     bcm_stat_flex_mode_t      offset_mode=0;
   3114     bcm_stat_object_t         object=bcmStatObjectIngPort;
   3115     bcm_stat_group_mode_t     group_mode= bcmStatGroupModeSingle;
   3116     uint32                    count=0;
   3117     uint32                     actual_num_tables=0;
   3118     uint32                     num_of_tables=0;
   3119     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   3120 
   3121     _bcm_esw_stat_get_counter_id_info(
   3122                   unit, stat_counter_id,
   3123                   &group_mode,&object,&offset_mode,&pool_number,&base_index);
   3124 
   3125     BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_object(unit,object,&direction));
   3126     BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_group(unit,group_mode));
   3127 
   3128     BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_get_table_info(
   3129                         unit,object,4,&actual_num_tables,&table[0],&direction));
   3130 
   3131     BCM_IF_ERROR_RETURN(_bcm_td2_l3_host_stat_get_table_info(
   3132                    unit, info,&num_of_tables,&table_info[0]));
   3133     /* TD3 doesn't support Flex Counter for L3_ENTRY_DOUBLE view */
   3134     if (SOC_IS_TRIDENT3(unit) &&
   3135         SOC_URPF_STATUS_GET(unit) &&
   3136         table_info[0].table == L3_ENTRY_DOUBLEm) {
   3137         return BCM_E_UNAVAIL;
   3138     }
   3139 
   3140     for (count=0; count < num_of_tables ; count++) {
   3141          for (flex_table_index=0; 
   3142               flex_table_index < actual_num_tables ; 
   3143               flex_table_index++) {
   3144               if ((table_info[count].direction == direction) &&
   3145                   (table_info[count].table == table[flex_table_index]) ) {
   3146                   if (direction == bcmStatFlexDirectionIngress) {
   3147                       return _bcm_esw_stat_flex_attach_ingress_table_counters(
   3148                              unit,
   3149                              table_info[count].table,
   3150                              table_info[count].index,
   3151                              offset_mode,
   3152                              base_index,
   3153                              pool_number);
   3154                   } else {
   3155                       return _bcm_esw_stat_flex_attach_egress_table_counters(
   3156                              unit,
   3157                              table_info[count].table,
   3158                              table_info[count].index,
   3159                              0,
   3160                              offset_mode,
   3161                              base_index,
   3162                              pool_number);
   3163                   }
   3164               }
   3165          }
   3166     }
   3167     return BCM_E_NOT_FOUND;
   3168 }
   3169 
   3170 /*
   3171  * Function:
   3172  *      _bcm_td2_l3_host_stat_detach
   3173  * Description:
   3174  *      Detach counters entries to the given L3 host entry
   3175  *
   3176  * Parameters:
   3177  *      unit             - (IN) unit number
   3178  *      info		 - (IN) L3 host description
   3179  *
   3180  * Return Value:
   3181  *      BCM_E_XXX
   3182  * Notes:
   3183  */
   3184 bcm_error_t
   3185 _bcm_td2_l3_host_stat_detach(
   3186             int unit,
   3187             bcm_l3_host_t *info)
   3188 {
   3189     uint32                     count=0;
   3190     uint32                     num_of_tables=0;
   3191     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   3192     bcm_error_t                rv = BCM_E_NONE;
   3193     bcm_error_t                err_code[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION] = {BCM_E_NONE};
   3194 
   3195     BCM_IF_ERROR_RETURN(_bcm_td2_l3_host_stat_get_table_info(
   3196                    unit, info,&num_of_tables,&table_info[0]));
   3197 
   3198     for (count=0; count < num_of_tables ; count++) {
   3199       if (table_info[count].direction == bcmStatFlexDirectionIngress) {
   3200            rv = _bcm_esw_stat_flex_detach_ingress_table_counters(
   3201                          unit,
   3202                          table_info[count].table,
   3203                          table_info[count].index);
   3204            if (BCM_E_NONE != rv && 
   3205                 BCM_E_NONE == err_code[bcmStatFlexDirectionIngress]) {
   3206                 err_code[bcmStatFlexDirectionIngress] = rv;
   3207            }
   3208       } else {
   3209            rv = _bcm_esw_stat_flex_detach_egress_table_counters(
   3210                           unit,
   3211                           0,
   3212                           table_info[count].table,
   3213                           table_info[count].index);
   3214            if (BCM_E_NONE != rv &&
   3215                 BCM_E_NONE == err_code[bcmStatFlexDirectionEgress]) {
   3216                 err_code[bcmStatFlexDirectionEgress] = rv;
   3217            }
   3218       }
   3219     }
   3220 
   3221     BCM_STAT_FLEX_DETACH_RETURN(err_code)
   3222 }
   3223 
   3224 /*
   3225  * Function:
   3226  *      _bcm_td2_l3_host_stat_counter_get
   3227  * Description:
   3228  *      Get counter statistic values for specific L3 host entry
   3229  *      if sync_mode is set, sync the sw accumulated count
   3230  *      with hw count value first, else return sw count.  
   3231  *
   3232  * Parameters:
   3233  *      unit             - (IN) unit number
   3234  *      sync_mode        - (IN) hwcount is to be synced to sw count 
   3235  *      info             - (IN) L3 host description
   3236  *      stat             - (IN) Type of the counter to retrieve
   3237  *                              I.e. ingress/egress byte/packet)
   3238  *      num_entries      - (IN) Number of counter Entries
   3239  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   3240  *      counter_values   - (OUT) Pointer to counter values
   3241  *
   3242  * Return Value:
   3243  *      BCM_E_XXX
   3244  * Notes:
   3245  */
   3246 bcm_error_t 
   3247 _bcm_td2_l3_host_stat_counter_get(
   3248             int unit,
   3249             int sync_mode,
   3250             bcm_l3_host_t *info,
   3251             bcm_l3_stat_t stat,
   3252             uint32 num_entries,
   3253             uint32 *counter_indexes,
   3254             bcm_stat_value_t *counter_values)
   3255 {
   3256     uint32                          table_count=0;
   3257     uint32                          index_count=0;
   3258     uint32                          num_of_tables=0;
   3259     bcm_stat_flex_direction_t       direction=bcmStatFlexDirectionIngress;
   3260     uint32                          byte_flag=0;
   3261     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   3262 
   3263     if ((stat == bcmL3StatInPackets) ||
   3264         (stat == bcmL3StatInBytes)) {
   3265          direction = bcmStatFlexDirectionIngress;
   3266     } else {
   3267          /* direction = bcmStatFlexDirectionEgress; */
   3268          return BCM_E_PARAM;
   3269     }
   3270     if (stat == bcmL3StatInPackets) {
   3271         byte_flag=0;
   3272     } else {
   3273         byte_flag=1; 
   3274     }
   3275 
   3276     BCM_IF_ERROR_RETURN(_bcm_td2_l3_host_stat_get_table_info(
   3277                    unit, info,&num_of_tables,&table_info[0]));
   3278 
   3279     for (table_count=0; table_count < num_of_tables ; table_count++) {
   3280       if (table_info[table_count].direction == direction) {
   3281           for (index_count=0; index_count < num_entries ; index_count++) {
   3282                /*ctr_offset_info.offset_index = counter_indexes[index_count];*/
   3283             BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_get(
   3284                          unit, sync_mode,
   3285                          table_info[table_count].index,
   3286                          table_info[table_count].table,
   3287                          0,
   3288                          byte_flag,
   3289                          counter_indexes[index_count],
   3290                          &counter_values[index_count]));
   3291           }
   3292       }
   3293     }
   3294     return BCM_E_NONE;
   3295 }
   3296 
   3297 /*
   3298  * Function:
   3299  *      _bcm_td2_l3_host_stat_counter_set
   3300  * Description:
   3301  *      Set counter statistic values for specific L3 host entry
   3302  *
   3303  * Parameters:
   3304  *      unit             - (IN) unit number
   3305  *      info             - (IN) L3 host description
   3306  *      stat             - (IN) Type of the counter to retrieve
   3307  *                              I.e. ingress/egress byte/packet)
   3308  *      num_entries      - (IN) Number of counter Entries
   3309  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   3310  *      counter_values   - (IN) Pointer to counter values
   3311  *
   3312  * Return Value:
   3313  *      BCM_E_XXX
   3314  * Notes:
   3315  */
   3316 bcm_error_t 
   3317 _bcm_td2_l3_host_stat_counter_set(
   3318             int unit,
   3319             bcm_l3_host_t *info,
   3320             bcm_l3_stat_t stat,
   3321             uint32 num_entries,
   3322             uint32 *counter_indexes,
   3323             bcm_stat_value_t *counter_values)
   3324 {
   3325     uint32                          table_count=0;
   3326     uint32                          index_count=0;
   3327     uint32                          num_of_tables=0;
   3328     bcm_stat_flex_direction_t       direction=bcmStatFlexDirectionIngress;
   3329     uint32                          byte_flag=0;
   3330     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   3331     if ((stat == bcmL3StatInPackets) ||
   3332         (stat == bcmL3StatInBytes)) {
   3333          direction = bcmStatFlexDirectionIngress;
   3334     } else {
   3335          /* direction = bcmStatFlexDirectionEgress; */
   3336          return BCM_E_PARAM;
   3337     }
   3338     if (stat == bcmL3StatInPackets) {
   3339         byte_flag=0;
   3340     } else {
   3341         byte_flag=1; 
   3342     }
   3343 
   3344     BCM_IF_ERROR_RETURN(_bcm_td2_l3_host_stat_get_table_info(
   3345                    unit, info,&num_of_tables,&table_info[0]));
   3346 
   3347     for (table_count=0; table_count < num_of_tables ; table_count++) {
   3348       if (table_info[table_count].direction == direction) {
   3349           for (index_count=0; index_count < num_entries ; index_count++) {
   3350             BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_set(
   3351                                 unit,
   3352                                 table_info[table_count].index,
   3353                                 table_info[table_count].table,
   3354                                 0,
   3355                                 byte_flag,
   3356                                 counter_indexes[index_count],
   3357                                 &counter_values[index_count]));
   3358           }
   3359       }
   3360     }
   3361     return BCM_E_NONE;
   3362 }
   3363 
   3364 /*
   3365  * Function:
   3366  *      _bcm_td2_l3_host_stat_id_get
   3367  * Description:
   3368  *      Get stat counter id associated with given L3 host entry
   3369  *
   3370  * Parameters:
   3371  *      unit             - (IN) unit number
   3372  *      info             - (IN) L3 host description
   3373  *      stat             - (IN) Type of the counter to retrieve
   3374  *                              I.e. ingress/egress byte/packet)
   3375  *      Stat_counter_id  - (OUT) Stat Counter ID
   3376  * Return Value:
   3377  *      BCM_E_XXX
   3378  * Notes:
   3379  */
   3380 bcm_error_t 
   3381 _bcm_td2_l3_host_stat_id_get(
   3382             int unit,
   3383             bcm_l3_host_t *info,
   3384             bcm_l3_stat_t stat,
   3385             uint32 *stat_counter_id)
   3386 {
   3387     bcm_stat_flex_direction_t  direction=bcmStatFlexDirectionIngress;
   3388     uint32                     num_of_tables=0;
   3389     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   3390     uint32                     index=0;
   3391     uint32                     num_stat_counter_ids=0;
   3392 
   3393     if ((stat == bcmL3StatInPackets) ||
   3394         (stat == bcmL3StatInBytes)) {
   3395          direction = bcmStatFlexDirectionIngress;
   3396     } else {
   3397          /* direction = bcmStatFlexDirectionEgress; */
   3398          return BCM_E_PARAM;
   3399     }
   3400 
   3401     BCM_IF_ERROR_RETURN(_bcm_td2_l3_host_stat_get_table_info(
   3402                         unit,info,&num_of_tables,&table_info[0]));
   3403     for (index=0; index < num_of_tables ; index++) {
   3404          if (table_info[index].direction == direction)
   3405              return _bcm_esw_stat_flex_get_counter_id(
   3406                                   unit, 1, &table_info[index],
   3407                                   &num_stat_counter_ids,stat_counter_id);
   3408     }
   3409     return BCM_E_NOT_FOUND;
   3410 }
   3411 
   3412 /*
   3413  * Function:
   3414  *      bcm_td2_l3_replace
   3415  * Purpose:
   3416  *      Replace an entry in TD2 L3 host table.
   3417  * Parameters:
   3418  *      unit -  (IN)SOC unit number.
   3419  *      l3cfg - (IN)L3 entry information.
   3420  * Returns:
   3421  *      BCM_E_XXX
   3422  */
   3423 int
   3424 bcm_td2_l3_replace(int unit, _bcm_l3_cfg_t *l3cfg)
   3425 {
   3426     
   3427     _bcm_l3_cfg_t entry;        /* Original l3 entry.             */
   3428     int nh_idx_old;             /* Original entry next hop index. */
   3429     int nh_idx_new;             /* New allocated next hop index   */
   3430     int rv = BCM_E_UNAVAIL;     /* Operation return status.       */
   3431     int embd_old = 0, embd_new = 0;
   3432     int mpath = 0;              /* Multipath */
   3433 
   3434     /*  Make sure module was initialized. */
   3435     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   3436         return (BCM_E_INIT);
   3437     }
   3438 
   3439     /* Input parameters check. */
   3440     if (NULL == l3cfg) {
   3441         return (BCM_E_PARAM); 
   3442     }
   3443 
   3444     /* Set lookup key. */
   3445     entry = *l3cfg;
   3446 
   3447     if (BCM_XGS3_L3_MCAST_ENTRY(l3cfg)) {
   3448         /* Check if identical entry exits. */
   3449         if (BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_get)) {
   3450             BCM_XGS3_L3_MODULE_LOCK(unit);
   3451             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_get) (unit, &entry);
   3452             BCM_XGS3_L3_MODULE_UNLOCK(unit);
   3453         }
   3454         if (rv < 0) {
   3455             return rv;
   3456         }
   3457 
   3458         /* Write mcast entry to hw. */
   3459         l3cfg->l3c_hw_index = entry.l3c_hw_index;       /*Replacement index & flag. */
   3460         if (BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_add)) {
   3461             BCM_XGS3_L3_MODULE_LOCK(unit);
   3462             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_add) (unit, l3cfg);
   3463             BCM_XGS3_L3_MODULE_UNLOCK(unit);
   3464         } else {
   3465             return (BCM_E_UNAVAIL);
   3466         }
   3467     } else {
   3468         if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) {
   3469             /* Trunk id validation. */
   3470             BCM_XGS3_L3_IF_INVALID_TGID_RETURN(unit, l3cfg->l3c_flags,
   3471                                                l3cfg->l3c_port_tgid);
   3472         }
   3473         mpath = l3cfg->l3c_flags & BCM_L3_MULTIPATH; 
   3474         if (!mpath &&
   3475             BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, l3cfg->l3c_intf)) {
   3476             return BCM_E_PARAM;
   3477         }
   3478 
   3479         if (mpath &&
   3480             !BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, l3cfg->l3c_intf)) {
   3481             return BCM_E_PARAM;
   3482         }
   3483 
   3484         /* Check if identical entry exits. */
   3485         rv = _bcm_td2_l3_entry_get(unit, &entry, &nh_idx_old, &embd_old);
   3486         if (((BCM_E_NOT_FOUND == rv) || (BCM_E_DISABLED == rv)) &&
   3487             !soc_property_get(unit, spn_HOST_AS_ROUTE_DISABLE, 0)) {
   3488             return  bcm_xgs3_host_as_route(unit, l3cfg, BCM_XGS3_L3_OP_ADD, rv);
   3489         } else if (BCM_FAILURE(rv)) {
   3490             return rv;
   3491         }
   3492 
   3493         if (BCM_GPORT_IS_BLACK_HOLE(l3cfg->l3c_port_tgid)) {
   3494             nh_idx_new = 0;
   3495         } else { /* If new entry is in indexed NH table */
   3496             /* Get next hop index. */
   3497             BCM_IF_ERROR_RETURN
   3498                 (_bcm_xgs3_nh_init_add(unit, l3cfg, NULL, &nh_idx_new));
   3499         }
   3500 
   3501 #ifdef BCM_TOMAHAWK_SUPPORT
   3502         if (soc_feature(unit, soc_feature_extended_view_no_trunk_support) &&
   3503             BCM_TD2_L3_USE_EMBEDDED_NEXT_HOP(unit, l3cfg->l3c_intf, nh_idx_new) &&
   3504             (l3cfg->l3c_flags & BCM_L3_TGID)) {
   3505             return BCM_E_UNAVAIL;
   3506         }
   3507 #endif /* BCM_TOMAHAWK_SUPPORT */
   3508 
   3509 #ifdef BCM_TRIDENT2_SUPPORT
   3510         if ((SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT3X(unit)) &&
   3511             soc_feature(unit, soc_feature_ecmp_resilient_hash) &&
   3512             mpath && (entry.l3c_flags & BCM_L3_MULTIPATH)) {
   3513             /* If an old ECMP group is replaced by a new one, and if
   3514              * they have members in common, the resilient hash flow set
   3515              * entries containing the shared members are copied from the old
   3516              * ECMP group to the new ECMP group, in order to minimize
   3517              * flow-to-member reassignments.
   3518              */
   3519             BCM_IF_ERROR_RETURN(bcm_td2_l3_egress_ecmp_rh_shared_copy(unit,
   3520                                 nh_idx_old, nh_idx_new));
   3521         }
   3522 #ifdef BCM_TOMAHAWK_SUPPORT
   3523         if (SOC_IS_TOMAHAWKX(unit) &&
   3524             soc_feature(unit, soc_feature_ecmp_resilient_hash_optimized) &&
   3525             mpath && (entry.l3c_flags & BCM_L3_MULTIPATH)) {
   3526                 BCM_IF_ERROR_RETURN(bcm_opt_l3_egress_ecmp_rh_shared_copy(unit,
   3527                                     nh_idx_old, nh_idx_new));
   3528         }
   3529 #endif /* BCM_TOMAHAWK_SUPPORT */
   3530 #endif /* BCM_TRIDENT2_SUPPORT */
   3531 
   3532         embd_new = BCM_TD2_L3_USE_EMBEDDED_NEXT_HOP(unit, l3cfg->l3c_intf, 
   3533                                                     nh_idx_new);
   3534         /* Write entry to hw. */
   3535         if (embd_old != embd_new) {
   3536             rv = bcm_xgs3_l3_del(unit, &entry);
   3537             l3cfg->l3c_hw_index = BCM_XGS3_L3_INVALID_INDEX;
   3538         } else {
   3539             /*Replacement index & flag. */
   3540             l3cfg->l3c_hw_index = entry.l3c_hw_index; 
   3541         }
   3542         if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_add)) {
   3543             BCM_XGS3_L3_MODULE_LOCK(unit);
   3544             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_add)(unit, l3cfg, nh_idx_new);
   3545             BCM_XGS3_L3_MODULE_UNLOCK(unit);
   3546         } else {
   3547             rv = BCM_E_UNAVAIL;
   3548         }
   3549 
   3550         /* Do best effort clean_up if needed. */
   3551         if (BCM_FAILURE(rv)) {
   3552             bcm_xgs3_nh_del(unit, 0, nh_idx_new);
   3553         }
   3554 
   3555         if (embd_old == embd_new) {
   3556             /* Free original next hop index. */
   3557             if (entry.l3c_flags & BCM_L3_MULTIPATH) {
   3558                 /* Destroy ecmp group only if previous route is multipath */
   3559                 BCM_IF_ERROR_RETURN(
   3560                     bcm_xgs3_ecmp_group_del(unit, nh_idx_old, 0));
   3561             } else {
   3562                 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_del(unit, 0, nh_idx_old));
   3563             }
   3564         }
   3565     }
   3566     return rv;
   3567 }
   3568 
   3569 /*
   3570  * Function:
   3571  *      bcm_td2_l3_del_intf
   3572  * Purpose:
   3573  *      Delete all the entries in TD2 L3 host table with
   3574  *      NH matching a certain interface.
   3575  * Parameters:
   3576  *      unit   - (IN)SOC unit number.
   3577  *      l3cfg  - (IN)Pointer to memory for l3 table related information.
   3578  *      negate - (IN)0 means interface match; 1 means not match
   3579  * Returns:
   3580  *      BCM_E_XXX
   3581  */
   3582 int
   3583 bcm_td2_l3_del_intf(int unit, _bcm_l3_cfg_t *l3cfg, int negate)
   3584 {
   3585     int rv;                             /* Operation return status.      */
   3586     int tmp_rv;                         /* First error occured.          */
   3587     bcm_if_t intf;                      /* Deleted interface id.         */
   3588     int nh_index;                       /* Next hop index.               */
   3589     bcm_l3_egress_t egr;                /* Egress object.                */
   3590     _bcm_if_del_pattern_t pattern;      /* Interface & negate combination 
   3591                                            to be used for every l3 entry
   3592                                            comparision.                  */
   3593 
   3594     /*  Make sure module was initialized. */
   3595     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   3596         return (BCM_E_INIT);
   3597     }
   3598 
   3599     /* Input parameters check */
   3600     if (NULL == l3cfg) {
   3601         return (BCM_E_PARAM);
   3602     }
   3603 
   3604     intf = l3cfg->l3c_intf;
   3605 
   3606     /* Check l3 switching mode. */ 
   3607     if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
   3608         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf) || 
   3609             BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) {
   3610             if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) {
   3611                 nh_index = intf - BCM_XGS3_EGRESS_IDX_MIN(unit); 
   3612             } else {
   3613                 nh_index = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   3614             }
   3615             /* Get egress object information. */
   3616             BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, nh_index, &egr));
   3617             /* Use egress object interface for iteration */
   3618             intf = egr.intf;
   3619         }
   3620     }
   3621 
   3622     pattern.l3_intf = intf;
   3623     pattern.negate = negate;
   3624 
   3625     /* Delete all ipv4 entries matching the interface. */
   3626     tmp_rv = _bcm_td2_l3_del_match(unit, 0, (void *)&pattern,
   3627                                     _bcm_xgs3_l3_intf_cmp, NULL, NULL);
   3628 
   3629     /* Delete all ipv6 entries matching the interface. */
   3630     rv = _bcm_td2_l3_del_match(unit, BCM_L3_IP6, (void *)&pattern,
   3631                                 _bcm_xgs3_l3_intf_cmp, NULL, NULL);
   3632 
   3633     return (tmp_rv < 0) ? tmp_rv : rv;
   3634 }
   3635 
   3636 /*
   3637  * Function:
   3638  *      _bcm_td2_l3_get_by_idx
   3639  * Purpose:
   3640  *      Get an entry from L3 table by index.
   3641  * Parameters:
   3642  *      unit     - (IN)SOC unit number.
   3643  *      dma_ptr  - (IN)Table pointer in dma. 
   3644  *      idx      - (IN)Index to read.
   3645  *      l3cfg    - (OUT)l3 entry search result.
   3646  *      nh_index - (OUT)Next hop index.
   3647  * Returns:
   3648  *      BCM_E_XXX
   3649  */
   3650 int
   3651 _bcm_td2_l3_get_by_idx(int unit, void *dma_ptr, int idx,
   3652                         _bcm_l3_cfg_t *l3cfg, int *nh_idx)
   3653 {
   3654     int v6;
   3655     int embeded_nh;
   3656     soc_mem_t mem;
   3657     int rv = BCM_E_UNAVAIL;     /* Operation return code. */
   3658 
   3659     /*  Make sure module was initialized. */
   3660     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   3661         return (BCM_E_INIT);
   3662     }
   3663 
   3664     if (l3cfg->l3c_flags & BCM_L3_IPMC) {
   3665         /* Get multicast entry. */
   3666         rv = _bcm_td2_l3_ipmc_get_by_idx(unit, dma_ptr, idx, l3cfg);
   3667     } else {
   3668         /* Get unicast entry. */
   3669         v6 = (l3cfg->l3c_flags & BCM_L3_IP6); 
   3670         embeded_nh = (l3cfg->l3c_flags & BCM_L3_DEREFERENCED_NEXTHOP); 
   3671         mem = (v6) ? 
   3672               ((embeded_nh) ? 
   3673               BCM_XGS3_L3_MEM(unit, v6_4) : BCM_XGS3_L3_MEM(unit, v6)) :
   3674               ((embeded_nh) ?  
   3675               BCM_XGS3_L3_MEM(unit, v4_2) : BCM_XGS3_L3_MEM(unit, v4)); 
   3676         rv = _bcm_td2_l3_get_host_ent_by_idx(unit, dma_ptr, mem,
   3677                                              idx, l3cfg, nh_idx);
   3678     }
   3679     return rv;
   3680 }
   3681 
   3682 
   3683 /*
   3684  * Function:
   3685  *      _bcm_td2_l3_del_match
   3686  * Purpose:
   3687  *      Delete an entry in L3 table matches a certain rule.
   3688  * Parameters:
   3689  *      unit      - (IN)SOC unit number.
   3690  *      flags.    - (IN)Generic l3 flags. 
   3691  *      pattern   - (IN)Comparison match argurment.
   3692  *      cmp_func  - (IN)Comparison function.
   3693  *      notify_cb - (IN)Delete notification callback. 
   3694  *      user_data - (IN)User provided cookie for callback.
   3695  * Returns:
   3696  *      BCM_E_XXX
   3697  */
   3698 int
   3699 _bcm_td2_l3_del_match(int unit, int flags, void *pattern,
   3700                        bcm_xgs3_ent_op_cb cmp_func,
   3701                        bcm_l3_host_traverse_cb notify_cb, void *user_data)
   3702 {
   3703     int rv = BCM_E_NONE;
   3704     int ipv6;             /* IPv6/IPv4 lookup flag. */
   3705     int nh_idx;           /* Next hop index.        */
   3706     int tbl, idx;         /* Iteration indices.     */
   3707     int cmp_result;       /* Compare against pattern result. */
   3708     bcm_l3_host_t info;   /* Host cb buffer.        */
   3709     _bcm_l3_cfg_t l3cfg;  /* Hw entry info.         */
   3710     int idx_max;
   3711     int num_tables = 2;  
   3712     soc_mem_t mem[2] = {INVALIDm, INVALIDm};
   3713     int table_ent_size;         /* Table entry size. */
   3714     int table_size;             /* Number of entries in the table. */
   3715     char *l3_tbl_ptr = NULL;    /* Table dma pointer.              */
   3716 
   3717     /* Check Protocol. */
   3718     ipv6 = (flags & BCM_L3_IP6) ? TRUE : FALSE;
   3719 
   3720     if (ipv6) {
   3721         mem[0] = BCM_XGS3_L3_MEM(unit, v6); 
   3722         if (soc_feature(unit, soc_feature_l3_extended_host_entry)) {
   3723             mem[1] = BCM_XGS3_L3_MEM(unit, v6_4); 
   3724         }
   3725     } else {
   3726         mem[0] = BCM_XGS3_L3_MEM(unit, v4); 
   3727         if (soc_feature(unit, soc_feature_l3_extended_host_entry)) {
   3728             mem[1] = BCM_XGS3_L3_MEM(unit, v4_2); 
   3729         }
   3730     }
   3731 
   3732     for (tbl = 0; tbl < num_tables; tbl++) {
   3733         if (INVALIDm == mem[tbl]) {
   3734             continue;
   3735         }
   3736         idx_max = soc_mem_index_max(unit, mem[tbl]);
   3737         table_ent_size = BCM_L3_MEM_ENT_SIZE(unit, mem[tbl]);
   3738         BCM_IF_ERROR_RETURN(
   3739             bcm_xgs3_l3_tbl_dma(unit, mem[tbl], table_ent_size,
   3740                                 "l3_tbl", &l3_tbl_ptr, &table_size));
   3741 
   3742         for (idx = 0; idx <= idx_max; idx++) {
   3743 
   3744             /* Set protocol. */
   3745             sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   3746             l3cfg.l3c_flags = flags;
   3747             rv = _bcm_td2_l3_get_host_ent_by_idx(unit, l3_tbl_ptr, mem[tbl], idx,
   3748                                                  &l3cfg, &nh_idx);
   3749             /* Check for read errors & invalid entries. */
   3750             if (rv < 0) {
   3751                 if (rv != BCM_E_NOT_FOUND) {
   3752                     break;
   3753                 }
   3754                 /* If not found, reset the return value */
   3755                 rv = BCM_E_NONE;
   3756                 continue;
   3757             }
   3758 
   3759  #if defined(BCM_TRIDENT3_SUPPORT)
   3760             if (soc_feature(unit, soc_feature_flex_flow)
   3761                 && (l3cfg.l3c_flow_handle)
   3762                 && (l3cfg.l3c_flags & BCM_L3_IPMC))  {
   3763                    LOG_VERBOSE(BSL_LS_BCM_L3,
   3764                        (BSL_META_U(unit,
   3765                    "L3 host: IPMC do not compare the l3 entry flags.")));
   3766                     nh_idx = BCM_XGS3_L3_INVALID_INDEX;
   3767                     if (BCM_L3_CMP_EQUAL !=
   3768                     _bcm_td3_l3_flex_entry_flags_cmp(unit, flags, l3cfg.l3c_flags, &idx)) {
   3769                         continue;
   3770                     }
   3771             } else
   3772 #endif /* BCM_TRIDENT3_SUPPORT */
   3773             {
   3774 
   3775                 /* Check read entry flags & update index accordingly. */
   3776                 if (BCM_L3_CMP_EQUAL !=
   3777                     _bcm_xgs3_trvrs_flags_cmp(unit, flags, l3cfg.l3c_flags, &idx)) {
   3778                     continue;
   3779                 }
   3780             }
   3781 
   3782             /* If compare function provided match the entry against pattern */
   3783             if (cmp_func) {
   3784                 rv = (*cmp_func) (unit, pattern, (void *)&l3cfg,
   3785                                   (void *)&nh_idx, &cmp_result);
   3786                 if (BCM_FAILURE(rv)) {
   3787                     break;
   3788                 }
   3789                 /* If entry doesn't match the pattern don't delete it. */
   3790                 if (BCM_L3_CMP_EQUAL != cmp_result) {
   3791                     continue;
   3792                 }
   3793             }
   3794 
   3795             /* Entry matches the rule -> delete it. */
   3796             rv = _bcm_td2_l3_entry_del(unit, &l3cfg);
   3797             if (BCM_FAILURE(rv)) {
   3798                 break;
   3799             }
   3800     
   3801             if (l3cfg.l3c_flags & BCM_L3_MULTIPATH) {
   3802                 /* Update ECMP reference count */
   3803                 if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
   3804                     rv = bcm_xgs3_ecmp_group_del(unit, nh_idx, 0);
   3805                 }
   3806             } else {
   3807                 /* Release next hop index. */
   3808                 rv = bcm_xgs3_nh_del(unit, 0, nh_idx);
   3809             }
   3810             if (BCM_FAILURE(rv)) {
   3811                 break;
   3812             }
   3813    
   3814             /* Check if notification required. */
   3815             if (notify_cb) {
   3816                 /* Fill host info. */
   3817                 _bcm_xgs3_host_ent_init(unit, &l3cfg, FALSE, &info);
   3818                 /* Call notification callback. */
   3819                 (*notify_cb) (unit, idx, &info, user_data);
   3820             }
   3821         }
   3822 
   3823         if (l3_tbl_ptr) {
   3824             soc_cm_sfree(unit, l3_tbl_ptr);
   3825             l3_tbl_ptr = NULL;
   3826         }
   3827         if (BCM_FAILURE(rv)) {
   3828             return rv;
   3829         }
   3830     }
   3831     /* Reset last read status. */
   3832     return BCM_E_NONE;
   3833 }
   3834 
   3835 /*
   3836  * Function:
   3837  *      _bcm_td2_l3_ipmc_get
   3838  * Purpose:
   3839  *      Get TD2 L3 multicast entry.
   3840  * Parameters:
   3841  *      unit  - (IN)SOC unit number.
   3842  *      l3cfg - (IN/OUT)Group/Source key & Get result buffer.
   3843  * Returns:
   3844  *    BCM_E_XXX
   3845  */
   3846 int
   3847 _bcm_td2_l3_ipmc_get(int unit, _bcm_l3_cfg_t *l3cfg)
   3848 {
   3849     uint32 l3x_key[SOC_MAX_MEM_FIELD_WORDS];    /* Lookup key buffer.    */
   3850     uint32 l3x_entry[SOC_MAX_MEM_FIELD_WORDS];  /* Search result buffer. */
   3851     int clear_hit;                              /* Clear hit flag.       */
   3852     soc_mem_t mem;                              /* IPMC table memory.    */
   3853     int ipv6;                                   /* IPv6 entry indicator. */
   3854     int rv;                                     /* Return value.         */
   3855     int l3_entry_idx;                           /* Entry index           */
   3856 
   3857 #ifdef BCM_TRIDENT3_SUPPORT
   3858     if (soc_feature(unit, soc_feature_flex_flow) &&
   3859         (l3cfg->l3c_flow_handle != 0)) {
   3860         int nh_idx = 0;
   3861         int embd = 0;
   3862 
   3863         return _bcm_td3_l3_flex_entry_get(unit, l3cfg, &nh_idx, &embd);
   3864     }
   3865 #endif
   3866 
   3867     /* Get entry type. */
   3868     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
   3869 
   3870     /* Get table memory. */
   3871     if (soc_mem_is_valid(unit, L3_ENTRY_DOUBLEm)) {
   3872         mem = (ipv6) ? L3_ENTRY_QUADm : L3_ENTRY_DOUBLEm;
   3873     } else {
   3874     mem =  (ipv6) ? L3_ENTRY_IPV6_MULTICASTm : L3_ENTRY_IPV4_MULTICASTm;
   3875     }
   3876 
   3877     /*  Zero buffers. */
   3878     sal_memcpy(l3x_key, soc_mem_entry_null(unit, mem),
   3879                    soc_mem_entry_words(unit,mem) * 4);
   3880     sal_memcpy(l3x_entry, soc_mem_entry_null(unit, mem),
   3881                    soc_mem_entry_words(unit,mem) * 4);
   3882 
   3883     /* Check if clear hit bit is required. */
   3884     clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR;
   3885 
   3886     /* Lookup Key preparation. */
   3887     rv = _bcm_td2_l3_ipmc_ent_init(unit, (uint32 *)l3x_key, l3cfg);
   3888     if (BCM_FAILURE(rv)) {
   3889         return rv;
   3890     }
   3891 
   3892     /* Perform hw lookup. */
   3893     MEM_LOCK(unit, mem);
   3894     rv = soc_mem_generic_lookup(unit, mem, MEM_BLOCK_ANY,
   3895                                 _BCM_TD2_L3_MEM_BANKS_ALL,
   3896                                 l3x_key, l3x_entry, &l3_entry_idx);
   3897     l3cfg->l3c_hw_index = l3_entry_idx;
   3898 
   3899     MEM_UNLOCK(unit, mem);
   3900     BCM_XGS3_LKUP_IF_ERROR_RETURN(rv, BCM_E_NOT_FOUND);
   3901 
   3902     /* Extract buffer information. */
   3903     BCM_IF_ERROR_RETURN(_bcm_td2_l3_ipmc_ent_parse(unit, l3cfg, (void *)l3x_entry));
   3904 
   3905     /* Clear the HIT bit */
   3906     if (clear_hit) {
   3907         BCM_IF_ERROR_RETURN(_bcm_td2_l3_clear_hit(unit, mem, l3cfg, l3x_entry,
   3908                                                   l3_entry_idx));
   3909     }
   3910     return rv;
   3911 }
   3912 
   3913 /*
   3914  * Function:
   3915  *      _bcm_td2_l3_ipmc_get_by_idx
   3916  * Purpose:
   3917  *      Get l3 multicast entry by entry index.
   3918  * Parameters:
   3919  *      unit      - (IN)SOC unit number.
   3920  *      dma_ptr  - (IN)Table pointer in dma. 
   3921  *      idx       - (IN)Index to read. 
   3922  *      l3cfg     - (IN/OUT)Entry data.
   3923  * Returns:
   3924  *    BCM_E_XXX
   3925  */
   3926 int
   3927 _bcm_td2_l3_ipmc_get_by_idx(int unit, void *dma_ptr,
   3928                            int idx, _bcm_l3_cfg_t *l3cfg)
   3929 {
   3930     uint32 l3_entry_v6[SOC_MAX_MEM_FIELD_WORDS];    /* Read buffer.            */
   3931     uint32 l3_entry_v4[SOC_MAX_MEM_FIELD_WORDS];    /* Read buffer.            */
   3932     void *buf_p;                      /* Hardware buffer ptr     */
   3933     soc_mem_t mem;                     /* IPMC table memory.      */
   3934     uint32 ipv6;                       /* IPv6 entry indicator.   */
   3935     int clear_hit;                     /* Clear hit bit indicator.*/
   3936     int key_type;
   3937     soc_field_t l3iif;
   3938     uint32 base_valid0, base_valid1, base_valid2, base_valid3;
   3939 
   3940     /* Get entry type. */
   3941     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
   3942 
   3943     /* Get table memory. */
   3944     if (ipv6) {
   3945         mem   = L3_ENTRY_IPV6_MULTICASTm;
   3946         buf_p = (l3_entry_ipv6_multicast_entry_t *)l3_entry_v6;
   3947         l3iif = IPV6MC__L3_IIFf;
   3948     } else {
   3949         mem   = L3_ENTRY_IPV4_MULTICASTm;
   3950         buf_p = (l3_entry_ipv4_multicast_entry_t *)l3_entry_v4;
   3951         l3iif = IPV4MC__L3_IIFf;
   3952     }
   3953     if (soc_mem_is_valid(unit, L3_ENTRY_DOUBLEm)) {
   3954         mem =  (ipv6) ? L3_ENTRY_QUADm : L3_ENTRY_DOUBLEm;
   3955         if (ipv6) {
   3956             buf_p = (l3_entry_quad_entry_t *)l3_entry_v6;
   3957         } else {
   3958             buf_p = (l3_entry_double_entry_t *)l3_entry_v4;
   3959         }
   3960     }
   3961 
   3962     /* Check if clear hit is required. */
   3963     clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR;
   3964 
   3965     if (NULL == dma_ptr) {             /* Read from hardware. */
   3966         /* Zero buffers. */
   3967         sal_memcpy(buf_p, soc_mem_entry_null(unit, mem), 
   3968                      soc_mem_entry_words(unit,mem) * 4);
   3969 
   3970         /* Read entry from hw. */
   3971         BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, buf_p));
   3972     } else {                    /* Read from dma. */
   3973         if (ipv6) {
   3974             if (soc_mem_is_valid(unit, L3_ENTRY_QUADm)) {
   3975                 buf_p = soc_mem_table_idx_to_pointer(unit, mem,
   3976                             l3_entry_quad_entry_t *, dma_ptr, idx);
   3977             } else {
   3978             buf_p = soc_mem_table_idx_to_pointer(unit, mem,
   3979                      l3_entry_ipv6_multicast_entry_t *, dma_ptr, idx);
   3980             }
   3981         } else {
   3982             if (soc_mem_is_valid(unit, L3_ENTRY_DOUBLEm)) {
   3983                 buf_p = soc_mem_table_idx_to_pointer(unit, mem,
   3984                             l3_entry_double_entry_t *, dma_ptr, idx);
   3985         } else {
   3986             buf_p = soc_mem_table_idx_to_pointer(unit, mem,
   3987                      l3_entry_ipv4_multicast_entry_t *, dma_ptr, idx);
   3988         }
   3989     }
   3990     }
   3991 
   3992     /* Ignore invalid entries. */
   3993     if (soc_feature(unit, soc_feature_base_valid)) {
   3994         if (ipv6) {
   3995            if (SOC_IS_TOMAHAWK3(unit))
   3996            {
   3997                 base_valid0 = 1;
   3998                 base_valid1 = 2;
   3999                 base_valid2 = 2;
   4000                 base_valid3 = 7;
   4001             }
   4002             else
   4003             {
   4004                 base_valid0 = 5;
   4005                 base_valid1 = 6;
   4006                 base_valid2 = 6;
   4007                 base_valid3 = 7;
   4008             }
   4009 
   4010             if (soc_mem_field32_get(unit, mem, buf_p, BASE_VALID_0f) != base_valid0 ||
   4011                 soc_mem_field32_get(unit, mem, buf_p, BASE_VALID_1f) != base_valid1 ||
   4012                 soc_mem_field32_get(unit, mem, buf_p, BASE_VALID_2f) != base_valid2 ||
   4013                 soc_mem_field32_get(unit, mem, buf_p, BASE_VALID_3f) != base_valid3) {
   4014                 return (BCM_E_NOT_FOUND);
   4015             }
   4016         } else {
   4017             if (SOC_IS_TOMAHAWK3(unit))
   4018             {
   4019                 base_valid0 = 1;
   4020                 base_valid1 = 7;
   4021             }
   4022             else
   4023             {
   4024                 base_valid0 = 3;
   4025                 base_valid1 = 4;
   4026             }
   4027             if (soc_mem_field32_get(unit, mem, buf_p, BASE_VALID_0f) != base_valid0 ||
   4028                 soc_mem_field32_get(unit, mem, buf_p, BASE_VALID_1f) != base_valid1) {
   4029                 return (BCM_E_NOT_FOUND);
   4030             }
   4031         }
   4032         key_type = soc_mem_field32_get(unit, mem, buf_p, KEY_TYPEf);
   4033     } else {
   4034     if (!soc_mem_field32_get(unit, mem, buf_p, VALID_0f)) {
   4035         return (BCM_E_NOT_FOUND);
   4036     }
   4037 
   4038     key_type = soc_mem_field32_get(unit, mem, buf_p, KEY_TYPE_0f);
   4039     }
   4040 
   4041     switch (key_type) {
   4042       case TD2_L3_HASH_KEY_TYPE_V4L2MC:
   4043       case TD2_L3_HASH_KEY_TYPE_V4L2VPMC:
   4044           l3cfg->l3c_flags = BCM_L3_IPMC | BCM_L3_L2ONLY;
   4045           break;
   4046       case TD2_L3_HASH_KEY_TYPE_V4MC:
   4047           l3cfg->l3c_flags = BCM_L3_IPMC;
   4048           break;
   4049       case TD2_L3_HASH_KEY_TYPE_V6L2MC:
   4050       case TD2_L3_HASH_KEY_TYPE_V6L2VPMC:
   4051           l3cfg->l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC | BCM_L3_L2ONLY;
   4052           break;
   4053       case TD2_L3_HASH_KEY_TYPE_V6MC:
   4054           l3cfg->l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC;
   4055           break;
   4056       default:
   4057           /* Catch all other key types, set flags to zero so that the 
   4058            * following flag check is effective for all key types */
   4059           l3cfg->l3c_flags = 0;  
   4060           break;
   4061     }
   4062 
   4063     /* Ignore protocol mismatch & multicast entries. */
   4064     if ((ipv6  != (l3cfg->l3c_flags & BCM_L3_IP6)) ||
   4065         (!(l3cfg->l3c_flags & BCM_L3_IPMC))) {
   4066         return (BCM_E_NOT_FOUND); 
   4067     }
   4068 
   4069     /* Set index to l3cfg. */
   4070     l3cfg->l3c_hw_index = idx;
   4071 
   4072     if (ipv6) {
   4073         /* Get group address. */
   4074         soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6MC__GROUP_IP_ADDR_LWR_64f,
   4075                              l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY);
   4076 
   4077         soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6MC__GROUP_IP_ADDR_UPR_56f,
   4078                              l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY);
   4079 
   4080         /* Get source  address. */
   4081         if (soc_mem_field_valid(unit, mem, IPV6MC__SOURCE_IP_ADDR_BITS_63_32f)) {
   4082             soc_mem_ip6_addr_get(unit, mem, buf_p,
   4083                 IPV6MC__SOURCE_IP_ADDR_BITS_63_32f, l3cfg->l3c_sip6,
   4084                 SOC_MEM_IP6_BITS_63_32);
   4085             soc_mem_ip6_addr_get(unit, mem, buf_p,
   4086                 IPV6MC__SOURCE_IP_ADDR_BITS_31_0f, l3cfg->l3c_sip6,
   4087                 SOC_MEM_IP6_BITS_31_0);
   4088         } else {
   4089         soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6MC__SOURCE_IP_ADDR_LWR_64f, 
   4090                              l3cfg->l3c_sip6, SOC_MEM_IP6_LOWER_ONLY);
   4091         }
   4092         soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6MC__SOURCE_IP_ADDR_UPR_64f, 
   4093                              l3cfg->l3c_sip6, SOC_MEM_IP6_UPPER_ONLY);
   4094 
   4095         l3cfg->l3c_ip6[0] = 0xff;    /* Set entry to multicast*/
   4096     } else {
   4097         /* Get group id. */
   4098         l3cfg->l3c_ip_addr =
   4099             soc_mem_field32_get(unit, mem, buf_p, IPV4MC__GROUP_IP_ADDRf);
   4100 
   4101         /* Get source address. */
   4102         l3cfg->l3c_src_ip_addr =
   4103             soc_mem_field32_get(unit, mem,  buf_p, IPV4MC__SOURCE_IP_ADDRf);
   4104     }
   4105 
   4106     /* Get L3_IIF or vlan id. */
   4107     l3cfg->l3c_vid = soc_mem_field32_get(unit, mem, buf_p, l3iif);
   4108 
   4109     /* Parse entry data. */
   4110     BCM_IF_ERROR_RETURN(_bcm_td2_l3_ipmc_ent_parse(unit, l3cfg, buf_p));
   4111 
   4112     /* Clear the HIT bit */
   4113     if (clear_hit) {
   4114         BCM_IF_ERROR_RETURN(_bcm_td2_l3_clear_hit(unit, mem, l3cfg, buf_p,
   4115                                                      l3cfg->l3c_hw_index));
   4116     }
   4117     return (BCM_E_NONE);
   4118 }
   4119 
   4120 /*
   4121  * Function:
   4122  *      _bcm_td2_l3_ipmc_add
   4123  * Purpose:
   4124  *      Add TD2 L3 multicast entry.
   4125  * Parameters:
   4126  *      unit  - (IN)SOC unit number.
   4127  *      l3cfg - (IN/OUT)Group/Source key.
   4128  * Returns:
   4129  *    BCM_E_XXX
   4130  */
   4131 int
   4132  _bcm_td2_l3_ipmc_add(int unit, _bcm_l3_cfg_t *l3cfg)
   4133 {
   4134     uint32 l3x_entry[SOC_MAX_MEM_FIELD_WORDS];  /* Write entry buffer.   */
   4135     soc_mem_t mem;                              /* IPMC table memory.    */
   4136     uint32 *buf_p;                              /* HW buffer address.    */
   4137     int ipv6;                                   /* IPv6 entry indicator. */
   4138     int idx;                                    /* Iteration index.      */
   4139     int idx_max;                                /* Iteration index max.  */
   4140     int rv;                                     /* Return value.         */
   4141     soc_field_t hitf[] = { HIT_0f, HIT_1f, HIT_2f, HIT_3f};
   4142     soc_field_t rpe, dst_discard, vrf_id, l3mc_idx, l3mc_idx_l2, class_id, pri, rpa_id;
   4143     soc_field_t exp_iif, exp_iif_drop, exp_iif_copytocpu;
   4144     soc_field_t flex_ctr_base_counter_idx;
   4145     soc_field_t flex_ctr_offset_mode;
   4146     soc_field_t flex_ctr_pool_number;
   4147 #ifdef BCM_MONTEREY_SUPPORT
   4148     soc_field_t roe_decap;
   4149 #endif
   4150 
   4151 #ifdef BCM_TRIDENT3_SUPPORT
   4152     if (soc_feature(unit, soc_feature_flex_flow) &&
   4153         (l3cfg->l3c_flow_handle != 0)) {
   4154         return _bcm_td3_l3_flex_entry_add(unit, l3cfg, 0);
   4155     }
   4156 #endif
   4157 
   4158     /* Get entry type. */
   4159     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
   4160 
   4161     /* Get table memory and table fields */
   4162     if (ipv6) {
   4163         if (soc_mem_is_valid(unit, L3_ENTRY_QUADm)) {
   4164             mem     = L3_ENTRY_QUADm;
   4165             l3mc_idx    = IPV6MC__DESTINATIONf;
   4166             if (soc_feature(unit, soc_feature_generic_dest)) {
   4167 	            l3mc_idx = IPV6MC__DESTINATIONf;
   4168             } else {
   4169                 l3mc_idx = IPV6MC__L3MC_INDEXf;
   4170             }
   4171             l3mc_idx_l2 = IPV6MC__L3MC_INDEX_FOR_L2_DISTRIBUTIONf;
   4172         } else {
   4173         mem         = L3_ENTRY_IPV6_MULTICASTm;
   4174             l3mc_idx    = IPV6MC__L3MC_INDEXf;
   4175             l3mc_idx_l2 = INVALIDf;
   4176         }
   4177         pri         = IPV6MC__PRIf;
   4178         rpe         = IPV6MC__RPEf;
   4179         vrf_id      = IPV6MC__VRF_IDf;
   4180         class_id    = IPV6MC__CLASS_IDf;
   4181         dst_discard = IPV6MC__DST_DISCARDf;
   4182         rpa_id      = IPV6MC__RPA_IDf;
   4183         exp_iif     = IPV6MC__EXPECTED_L3_IIFf;
   4184         exp_iif_drop      = IPV6MC__IPMC_EXPECTED_L3_IIF_MISMATCH_DROPf;
   4185         exp_iif_copytocpu = IPV6MC__IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPUf;       
   4186         flex_ctr_base_counter_idx = IPV6MC__FLEX_CTR_BASE_COUNTER_IDXf;
   4187         flex_ctr_offset_mode      = IPV6MC__FLEX_CTR_OFFSET_MODEf;
   4188         flex_ctr_pool_number      = IPV6MC__FLEX_CTR_POOL_NUMBERf;
   4189 #ifdef BCM_MONTEREY_SUPPORT
   4190         roe_decap = IPV6MC__ROE_DECAPf;
   4191 #endif
   4192     } else {
   4193         if (soc_mem_is_valid(unit, L3_ENTRY_DOUBLEm)) {
   4194             mem     = L3_ENTRY_DOUBLEm;
   4195             if (soc_feature(unit, soc_feature_generic_dest)) {
   4196             l3mc_idx    = IPV4MC__DESTINATIONf;
   4197         } else {
   4198 	            l3mc_idx    = IPV4MC__L3MC_INDEXf;
   4199             }
   4200             l3mc_idx_l2 = IPV4MC__L3MC_INDEX_FOR_L2_DISTRIBUTIONf;
   4201         } else {
   4202         mem         = L3_ENTRY_IPV4_MULTICASTm;
   4203             l3mc_idx    = IPV4MC__L3MC_INDEXf;
   4204             l3mc_idx_l2 = INVALIDf;
   4205         }
   4206 
   4207         pri         = IPV4MC__PRIf;
   4208         rpe         = IPV4MC__RPEf;
   4209         vrf_id      = IPV4MC__VRF_IDf;
   4210         class_id    = IPV4MC__CLASS_IDf;
   4211         dst_discard = IPV4MC__DST_DISCARDf;
   4212         rpa_id      = IPV4MC__RPA_IDf;
   4213         exp_iif     = IPV4MC__EXPECTED_L3_IIFf;
   4214         exp_iif_drop      = IPV4MC__IPMC_EXPECTED_L3_IIF_MISMATCH_DROPf;
   4215         exp_iif_copytocpu = IPV4MC__IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPUf;
   4216         flex_ctr_base_counter_idx = IPV4MC__FLEX_CTR_BASE_COUNTER_IDXf;
   4217         flex_ctr_offset_mode      = IPV4MC__FLEX_CTR_OFFSET_MODEf;
   4218         flex_ctr_pool_number      = IPV4MC__FLEX_CTR_POOL_NUMBERf;
   4219 #ifdef BCM_MONTEREY_SUPPORT
   4220         roe_decap = IPV4MC__ROE_DECAPf;
   4221 #endif
   4222     }
   4223 
   4224     /*  Zero buffers. */
   4225     buf_p = l3x_entry;
   4226     sal_memcpy(buf_p, soc_mem_entry_null(unit, mem), 
   4227                    soc_mem_entry_words(unit,mem) * 4);
   4228 
   4229    /* Prepare entry to write. */
   4230    rv = _bcm_td2_l3_ipmc_ent_init(unit, l3x_entry, l3cfg);
   4231    if (BCM_FAILURE(rv)) {
   4232        return rv;
   4233    }
   4234 
   4235     /* Set priority override bit. */
   4236     if (l3cfg->l3c_flags & BCM_L3_RPE) {
   4237         soc_mem_field32_set(unit, mem, buf_p, rpe, 1);
   4238     }
   4239 
   4240     /* Set destination discard. */
   4241     if (l3cfg->l3c_flags & BCM_L3_DST_DISCARD) {
   4242         soc_mem_field32_set(unit, mem, buf_p, dst_discard, 1);
   4243     }
   4244     
   4245     /* Virtual router id. */
   4246     soc_mem_field32_set(unit, mem, buf_p, vrf_id, l3cfg->l3c_vrf);
   4247 
   4248     /* Set priority. */
   4249     soc_mem_field32_set(unit, mem, buf_p, pri, l3cfg->l3c_prio);
   4250 
   4251     /* Pointer to ipmc table. */
   4252     if (soc_feature(unit, soc_feature_generic_dest)) {
   4253         soc_mem_field32_dest_set(unit, mem, buf_p, l3mc_idx,
   4254             SOC_MEM_FIF_DEST_IPMC, l3cfg->l3c_ipmc_ptr);
   4255     } else {
   4256     soc_mem_field32_set(unit, mem, buf_p, l3mc_idx, l3cfg->l3c_ipmc_ptr);
   4257     }
   4258 
   4259     /* Set L3MC_INDEX_FOR_L2_DISTRIBUTION */
   4260     if (l3mc_idx_l2 != INVALIDf && soc_mem_field_valid(unit, mem, l3mc_idx_l2)) {
   4261         soc_mem_field32_set(unit, mem, buf_p, l3mc_idx_l2, l3cfg->l3c_ipmc_ptr_l2);
   4262     }
   4263 
   4264     /* Classification lookup class id. */
   4265     soc_mem_field32_set(unit, mem, buf_p, class_id, l3cfg->l3c_lookup_class);
   4266    
   4267     /* Rendezvous point ID. */
   4268     if (SOC_MEM_FIELD_VALID(unit, mem, rpa_id)) {
   4269     if (l3cfg->l3c_rp_id != BCM_IPMC_RP_ID_INVALID) {
   4270         soc_mem_field32_set(unit, mem, buf_p, rpa_id, l3cfg->l3c_rp_id);
   4271     }
   4272     }
   4273 
   4274     /* RPF */
   4275     if ((BCM_IPMC_POST_LOOKUP_RPF_CHECK & l3cfg->l3c_flags) &&
   4276         (0 != l3cfg->l3c_intf)) {
   4277         /* Set Expected_IIF to L3_IIF*/
   4278         soc_mem_field32_set(unit, mem, buf_p, exp_iif, l3cfg->l3c_intf);
   4279         if (BCM_IPMC_RPF_FAIL_DROP & l3cfg->l3c_flags) {
   4280             soc_mem_field32_set(unit, mem, buf_p, exp_iif_drop, 1);
   4281         }
   4282         if (BCM_IPMC_RPF_FAIL_TOCPU & l3cfg->l3c_flags) {
   4283             soc_mem_field32_set(unit, mem, buf_p, exp_iif_copytocpu, 1);
   4284         }
   4285     }
   4286 
   4287     idx_max = (ipv6) ? 4 : 2;
   4288     for (idx = 0; idx < idx_max; idx++) {
   4289         /* Set hit bit. */
   4290         if (l3cfg->l3c_flags & BCM_L3_HIT) {
   4291             soc_mem_field32_set(unit, mem, buf_p, hitf[idx], 1);
   4292         }
   4293     }
   4294 
   4295     
   4296     if (!SOC_IS_MONTEREY(unit)) {
   4297     /* Base counter index. */
   4298     soc_mem_field32_set(unit, mem, buf_p, flex_ctr_base_counter_idx,
   4299                         l3cfg->l3c_flex_ctr_base_id);
   4300     /* Counter offset mode. */
   4301     soc_mem_field32_set(unit, mem, buf_p, flex_ctr_offset_mode,
   4302                         l3cfg->l3c_flex_ctr_mode);
   4303     /* Counter pool number. */
   4304     soc_mem_field32_set(unit, mem, buf_p, flex_ctr_pool_number,
   4305                         l3cfg->l3c_flex_ctr_pool);
   4306     }
   4307 
   4308 #ifdef BCM_MONTEREY_SUPPORT
   4309     if (soc_feature(unit, soc_feature_roe) ||
   4310         soc_feature(unit, soc_feature_roe_custom)) {
   4311         if (SOC_MEM_FIELD_VALID(unit, mem, roe_decap)) {
   4312             if (l3cfg->l3c_flags2 & BCM_L3_FLAGS2_DECAP_ROE_HEADER) {
   4313                 soc_mem_field32_set(unit, mem, buf_p, roe_decap, 1);
   4314             }
   4315         }
   4316     }
   4317 #endif
   4318 
   4319     /* Write entry to the hw. */
   4320     MEM_LOCK(unit, mem);
   4321     /* Handle replacement. */
   4322     if (BCM_XGS3_L3_INVALID_INDEX != l3cfg->l3c_hw_index) {
   4323         rv = BCM_XGS3_MEM_WRITE(unit, mem, l3cfg->l3c_hw_index, buf_p);
   4324     } else {
   4325         rv = soc_mem_insert(unit, mem, MEM_BLOCK_ANY, (void *)buf_p);
   4326     }
   4327 
   4328     /* Increment number of ipmc routes. */
   4329     if (BCM_SUCCESS(rv) && (BCM_XGS3_L3_INVALID_INDEX == l3cfg->l3c_hw_index)) {
   4330         (ipv6) ? BCM_XGS3_L3_IP6_IPMC_CNT(unit)++ : \
   4331                  BCM_XGS3_L3_IP4_IPMC_CNT(unit)++;
   4332     }
   4333     /*    coverity[overrun-local : FALSE]    */
   4334     MEM_UNLOCK(unit, mem);
   4335     return rv;
   4336 }
   4337 
   4338 /*
   4339  * Function:
   4340  *      _bcm_td2_l3_ipmc_del
   4341  * Purpose:
   4342  *      Delete TD2 L3 multicast entry.
   4343  * Parameters:
   4344  *      unit  - (IN)SOC unit number.
   4345  *      l3cfg - (IN)Group/Source deletion key.
   4346  * Returns:
   4347  *    BCM_E_XXX
   4348  */
   4349 int
   4350 _bcm_td2_l3_ipmc_del(int unit, _bcm_l3_cfg_t *l3cfg)
   4351 {
   4352     uint32 l3x_entry[SOC_MAX_MEM_FIELD_WORDS];  /* Delete buffer.          */
   4353     soc_mem_t mem;                              /* IPMC table memory.      */
   4354     int ipv6;                                   /* IPv6 entry indicator.   */
   4355     int rv;                                     /* Operation return value. */
   4356 
   4357 #ifdef BCM_TRIDENT3_SUPPORT
   4358     if (soc_feature(unit, soc_feature_flex_flow) &&
   4359         (l3cfg->l3c_flow_handle != 0)) {
   4360         return _bcm_td3_l3_flex_entry_del(unit, l3cfg);
   4361     }
   4362 #endif
   4363 
   4364     /* Get entry type. */
   4365     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
   4366 
   4367     /* Get table memory. */
   4368     if (soc_mem_is_valid(unit, L3_ENTRY_DOUBLEm)) {
   4369         mem = (ipv6) ? L3_ENTRY_QUADm : L3_ENTRY_DOUBLEm;
   4370     } else {
   4371     mem =  (ipv6) ? L3_ENTRY_IPV6_MULTICASTm : L3_ENTRY_IPV4_MULTICASTm;
   4372     }
   4373 
   4374     /*  Zero entry buffer. */
   4375     sal_memcpy(l3x_entry, soc_mem_entry_null(unit, mem),
   4376                soc_mem_entry_words(unit,mem) * 4);
   4377 
   4378 
   4379     /* Key preparation. */
   4380     rv = _bcm_td2_l3_ipmc_ent_init(unit, l3x_entry, l3cfg);
   4381     if (BCM_FAILURE(rv)) {
   4382         return rv;
   4383     }
   4384 
   4385     /* Delete the entry from hw. */
   4386     MEM_LOCK(unit, mem);
   4387 
   4388     rv = soc_mem_delete(unit, mem, MEM_BLOCK_ANY, (void *)l3x_entry);
   4389 
   4390     /* Decrement number of ipmc routes. */
   4391     if (BCM_SUCCESS(rv)) {
   4392         (ipv6) ? BCM_XGS3_L3_IP6_IPMC_CNT(unit)-- : \
   4393             BCM_XGS3_L3_IP4_IPMC_CNT(unit)--;
   4394     }
   4395     MEM_UNLOCK(unit, mem);
   4396     return rv;
   4397 }
   4398 
   4399 /*
   4400  * FLEX STAT FUNCTIONS for L3 ROUTE and L3 NAT
   4401  *
   4402  * This following functions implements flex stat routines to attach, detach and get/set
   4403  * flex counter functions.
   4404  * 
   4405  * FLEX ATTACH 
   4406  *   The function allocates flex counter from the counter pool and configures
   4407  *   attributes to set the base counter index and base offset. Flex counter pool,
   4408  *   base index and offset is associated to the table index request for the
   4409  *   module identifiers like, vpn, port, vp Additionally the reference counter
   4410  *   for the flex counter is incremented for multple references of the counter.
   4411  *
   4412  * FLEX DETACH 
   4413  *   The function disassociates flex counter details assigned during flex attach
   4414  *   and decrements the reference counter.
   4415  *
   4416  * FLEX COUNTER GET/SET 
   4417  *   The function read/set the associate counter values. Set is required for the
   4418  *   purpose of clearing the counter.
   4419  *
   4420  *
   4421  * FLEX COUNTER MULTI GET/SET
   4422  *   The function reads/sets multiple flex stats and returns the counter arrays. 
   4423  *
   4424  * FLEX STAT ID
   4425  *   The funciton retrieves the stat id for the given module identifiers. The
   4426  *   flex counter stat id has the following format.
   4427  *
   4428  *          (8 modes)  (32 groups) (16 pools)  (32 objIds)  (64K index)
   4429  *         +---------+------------+----------+-----------+-----------------+ 
   4430  *         |         |            |          |           |                 | 
   4431  *         | ModeId  |  GroupMode |   PoolId | Account   |  Base Index     |
   4432  *         |         |            |          | objectId  |                 |
   4433  *         +---------+------------+----------+-----------+-----------------+
   4434  *        (31)    (29)(28)     (24)(23)   (20)(19)    (15)(14)            (0)
   4435  *
   4436  *
   4437  *   PoolId      : Counter pool no. 
   4438  *                 ( TD2: Ingress(8 pool x 4k counters)
   4439  *                        Egress (4 pool x 4k counters)
   4440  *   GroupMode   : Attribute group mode determines base offset and no. of counters
   4441  *   ModeId      : Ingress/Egress Modes
   4442  *   Base Idx    : Index into counter block of 256 counters
   4443  *   Account Obj : Flexible accounting objects
   4444  */
   4445 
   4446 /*
   4447  * Function:
   4448  *      _bcm_td2_l3_route_stat_get_table_info
   4449  * Description:
   4450  *      Provides relevant flex table information(table-name,index with
   4451  *      direction)  for given ingress interface.
   4452  *
   4453  * Parameters:
   4454  *      unit             - (IN) unit number
   4455  *      info			 - (IN) L3 Route Info
   4456  *      num_of_tables    - (OUT) Number of flex counter tables
   4457  *      table_info       - (OUT) Flex counter tables information
   4458  *
   4459  * Return Value:
   4460  *      BCM_E_XXX
   4461  * Notes:
   4462  */
   4463 #ifdef BCM_TOMAHAWK_SUPPORT
   4464 #ifdef ALPM_ENABLE
   4465 #define ALPM_BKT_NODE_PTR_CNT   32768
   4466 /* No need per unit setting */
   4467 uint32 *alpm_bkt_node_ptr[ALPM_BKT_NODE_PTR_CNT];
   4468 
   4469 uint32 *alpm_bkt_node_ptr_arr_get(uint32 idx)
   4470 {
   4471     if (idx >= 0 && idx < ALPM_BKT_NODE_PTR_CNT) {
   4472         return alpm_bkt_node_ptr[idx];
   4473     }
   4474 
   4475     return NULL;
   4476 }
   4477 
   4478 int alpm_bkt_node_ptr_arr_idx_get(uint32 *bkt_node_ptr, uint32 *idx)
   4479 {
   4480     int i;
   4481 
   4482     for (i = 0; i < ALPM_BKT_NODE_PTR_CNT; i++) {
   4483         if (alpm_bkt_node_ptr[i] == bkt_node_ptr) {
   4484             *idx = i;
   4485             return BCM_E_NONE;
   4486         }
   4487     }
   4488 
   4489     return BCM_E_NOT_FOUND;
   4490 }
   4491 
   4492 int alpm_bkt_node_ptr_arr_add(uint32 *bkt_node_ptr, uint32 *idx)
   4493 {
   4494     int i, first_null_idx = -1;
   4495 
   4496     for (i = 0; i < ALPM_BKT_NODE_PTR_CNT; i++) {
   4497         if (alpm_bkt_node_ptr[i] == bkt_node_ptr) {
   4498             *idx = i;
   4499             return BCM_E_EXISTS;
   4500         }
   4501 
   4502         if (first_null_idx == -1 && alpm_bkt_node_ptr[i] == NULL) {
   4503             first_null_idx = i;
   4504         }
   4505     }
   4506 
   4507     if (first_null_idx == -1) {
   4508         return BCM_E_FULL;
   4509     } else {
   4510         alpm_bkt_node_ptr[first_null_idx] = bkt_node_ptr;
   4511         *idx = first_null_idx;
   4512         return BCM_E_NONE;
   4513     }
   4514 }
   4515 
   4516 int alpm_bkt_node_ptr_arr_del(uint32 *bkt_node_ptr)
   4517 {
   4518     int i;
   4519 
   4520     for (i = 0; i < ALPM_BKT_NODE_PTR_CNT; i++) {
   4521         if (alpm_bkt_node_ptr[i] == bkt_node_ptr) {
   4522             alpm_bkt_node_ptr[i] = NULL;
   4523             return BCM_E_NONE;
   4524         }
   4525     }
   4526 
   4527     return BCM_E_NOT_FOUND;
   4528 }
   4529 
   4530 #endif /* ALPM_ENABLE */
   4531 #endif
   4532 static
   4533 bcm_error_t  _bcm_td2_l3_route_stat_get_table_info(
   4534             int                        unit,
   4535             bcm_l3_route_t	           *info,
   4536             uint32                     *num_of_tables,
   4537             bcm_stat_flex_table_info_t *table_info,
   4538             _bcm_defip_cfg_t           *defip_copy)
   4539 {
   4540     int rv;
   4541     int index, scale;
   4542     soc_mem_t mem;
   4543     int max_prefix_length;
   4544     _bcm_defip_cfg_t defip;
   4545     soc_mem_t defip_mem = L3_DEFIPm;
   4546     soc_mem_t defip_pair_mem = L3_DEFIP_PAIR_128m;
   4547 
   4548     if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) {
   4549 	    defip_mem = L3_DEFIP_LEVEL1m;
   4550         defip_pair_mem = L3_DEFIP_PAIR_LEVEL1m;
   4551     }
   4552 
   4553     if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
   4554         return BCM_E_UNAVAIL;
   4555     }
   4556 
   4557     /*  Make sure module was initialized. */
   4558     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   4559         return (BCM_E_INIT);
   4560     }
   4561 
   4562     /* Vrf is in device supported range check. */
   4563     if ((info->l3a_vrf > SOC_VRF_MAX(unit)) || 
   4564         (info->l3a_vrf < BCM_L3_VRF_GLOBAL)) {
   4565         return BCM_E_PARAM;
   4566     }
   4567 
   4568     /*  Check that device supports ipv6. */
   4569     if (BCM_L3_NO_IP6_SUPPORT(unit, info->l3a_flags)) {
   4570         return BCM_E_UNAVAIL;
   4571     }
   4572 
   4573     mem = defip_mem;
   4574     scale = 1;
   4575 
   4576     sal_memset(&defip, 0, sizeof(_bcm_defip_cfg_t));
   4577     defip.defip_flags = info->l3a_flags;
   4578     defip.defip_vrf = info->l3a_vrf;
   4579 
   4580     L3_LOCK(unit);
   4581     if (info->l3a_flags & BCM_L3_IP6) {
   4582 #if defined(BCM_TRIDENT3_SUPPORT)
   4583         if (SOC_IS_TRIDENT3X(unit) && soc_feature(unit, soc_feature_flex_flow)
   4584             && (info->flow_handle != 0)) {
   4585             soc_mem_t view_id;
   4586             soc_flow_db_mem_view_info_t vinfo;
   4587 
   4588             BCM_IF_ERROR_RETURN(
   4589                     soc_flow_db_ffo_to_mem_view_id_get(unit,
   4590                         info->flow_handle,
   4591                         info->flow_option_handle,
   4592                         SOC_FLOW_DB_FUNC_L3_ROUTE_ID,
   4593                         (uint32 *)&view_id));
   4594             BCM_IF_ERROR_RETURN(soc_flow_db_mem_view_info_get(unit, view_id, &vinfo));
   4595             mem = vinfo.mem;
   4596         } else
   4597 #endif /* BCM_TRIDENT3_SUPPORT */
   4598         {
   4599             max_prefix_length =
   4600                 soc_feature(unit, soc_feature_lpm_prefix_length_max_128) ? 128 : 64;
   4601             sal_memcpy(defip.defip_ip6_addr, info->l3a_ip6_net, BCM_IP6_ADDRLEN);
   4602             defip.defip_sub_len = bcm_ip6_mask_length(info->l3a_ip6_mask);
   4603             if (defip.defip_sub_len > max_prefix_length) {
   4604                 L3_UNLOCK(unit);
   4605                 return BCM_E_PARAM;
   4606             }
   4607             if (defip.defip_sub_len > 64) {
   4608                 if (SOC_PERSIST(unit)->memState[defip_pair_mem].index_max >= 0) {
   4609                     mem = defip_pair_mem;
   4610                 }
   4611             } else {
   4612                 scale = 2;
   4613             }
   4614         }
   4615         rv = mbcm_driver[unit]->mbcm_ip6_defip_cfg_get(unit, &defip);
   4616     } else {
   4617         defip.defip_ip_addr = info->l3a_subnet & info->l3a_ip_mask;
   4618         defip.defip_sub_len = bcm_ip_mask_length(info->l3a_ip_mask);
   4619         rv = mbcm_driver[unit]->mbcm_ip4_defip_cfg_get(unit, &defip);
   4620     }
   4621 
   4622     L3_UNLOCK(unit);
   4623     if (rv < 0) {
   4624         return rv;
   4625     }
   4626 
   4627     index = defip.defip_index * scale;
   4628 
   4629 #ifdef ALPM_ENABLE
   4630     if (soc_feature(unit, soc_feature_alpm) &&
   4631         soc_property_get(unit, spn_L3_ALPM_ENABLE, 0)) {
   4632 
   4633         if (defip.defip_alpm_cookie & SOC_ALPM_LOOKUP_HIT) {
   4634             /* override table and index to ALPM format */
   4635             if (soc_feature(unit, soc_feature_alpm2)) {
   4636                 if (SOC_MEM_IS_VALID(unit, L3_DEFIP_ALPM_RAWm)) {
   4637                 mem = L3_DEFIP_ALPM_RAWm;
   4638             } else {
   4639                     if (soc_property_get(unit, "l3_alpm2_level", 3) == 2) {
   4640                         mem = L3_DEFIP_ALPM_LEVEL2m;
   4641                     } else {
   4642                         mem = L3_DEFIP_ALPM_LEVEL3m;
   4643                     }
   4644                }
   4645             } else {
   4646                 if (info->l3a_flags & BCM_L3_IP6) {
   4647                     if (soc_mem_index_count(unit, defip_pair_mem)) {
   4648                         mem = L3_DEFIP_ALPM_IPV6_128m;
   4649                     } else {
   4650                         mem = L3_DEFIP_ALPM_IPV6_64_1m;
   4651                     }
   4652                 } else {
   4653                     mem = L3_DEFIP_ALPM_IPV4_1m;
   4654                 }
   4655                 if (mem == L3_DEFIP_ALPM_IPV6_64_1m || mem == L3_DEFIP_ALPM_IPV4_1m) {
   4656                     if (!(defip.defip_alpm_cookie & SOC_ALPM_COOKIE_FLEX)) {
   4657                         return BCM_E_PARAM;
   4658                     }
   4659                 }
   4660             }
   4661             index = ALPM_ENT_INDEX(defip.defip_index);
   4662             if (defip_copy) {
   4663                 sal_memcpy(defip_copy, &defip, sizeof(defip));
   4664             }
   4665         } else { /* Entries in TCAM, like Global High, IPMC */
   4666             index = defip.defip_index;
   4667             if (info->l3a_flags & BCM_L3_IP6) {
   4668                 if (soc_mem_index_count(unit, defip_pair_mem)) {
   4669                     mem = defip_pair_mem;
   4670                 } else {
   4671                     mem = defip_mem;
   4672                     index *= 2;
   4673                 }
   4674             } else {
   4675                 mem = defip_mem;
   4676             }
   4677             if (defip_copy) {
   4678                 sal_memcpy(defip_copy, &defip, sizeof(defip));
   4679             }
   4680         }
   4681     }
   4682 #endif
   4683 
   4684     table_info[*num_of_tables].table = mem;
   4685     table_info[*num_of_tables].index = index;
   4686     table_info[*num_of_tables].direction = bcmStatFlexDirectionIngress;
   4687     (*num_of_tables)++;
   4688 
   4689     LOG_INFO(BSL_LS_BCM_L3,
   4690              (BSL_META_U(unit,
   4691                          "L3 Route Stat: table = %s, index = %d\n"),
   4692               SOC_MEM_NAME(unit, mem), index));
   4693     
   4694     return BCM_E_NONE;
   4695 }
   4696 
   4697 
   4698 /*
   4699  * Function:
   4700  *      _bcm_td2_l3_route_stat_attach
   4701  * Description:
   4702  *      Attach counters entries to the given  l3 route defip index . Allocate
   4703  *      flex counter and assign counter index and offset for the index pointed
   4704  *      by l3 defip index
   4705  *
   4706  * Parameters:
   4707  *      unit             - (IN) unit number
   4708  *      info			 - (IN) L3 Route Info
   4709  *      stat_counter_id  - (IN) Stat Counter ID.
   4710  *
   4711  * Return Value:
   4712  *      BCM_E_XXX
   4713  * Notes:
   4714  */
   4715     
   4716 bcm_error_t  _bcm_td2_l3_route_stat_attach (
   4717                             int                 unit,
   4718                             bcm_l3_route_t	    *info,
   4719                             uint32              stat_counter_id)
   4720 {
   4721     int                        rv = BCM_E_NONE;
   4722     int                        counter_flag = 0;
   4723     soc_mem_t                  table[5] = {INVALIDm};
   4724     bcm_stat_flex_direction_t  direction = bcmStatFlexDirectionIngress;
   4725     uint32                     pool_number = 0;
   4726     uint32                     base_index = 0;
   4727     bcm_stat_flex_mode_t       offset_mode = 0;
   4728     bcm_stat_object_t          object = bcmStatObjectIngPort;
   4729     bcm_stat_group_mode_t      group_mode = bcmStatGroupModeSingle;
   4730     uint32                     count = 0;
   4731     uint32                     actual_num_tables = 0;
   4732     uint32                     flex_table_index = 0;
   4733     uint32                     num_of_tables = 0;
   4734     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   4735     _bcm_defip_cfg_t           defip;
   4736 
   4737 
   4738     /* Get pool, base index group mode and offset modes from stat counter id */
   4739     _bcm_esw_stat_get_counter_id_info(
   4740                   unit, stat_counter_id,
   4741                   &group_mode, &object, &offset_mode, &pool_number, &base_index);
   4742 
   4743     /* Validate object and group mode */
   4744     BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_object(unit, object, &direction));
   4745     BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_group(unit, group_mode));
   4746 
   4747     /* Get Table index to attach flexible counter */
   4748     BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_get_table_info(
   4749                         unit, object, 5, &actual_num_tables, &table[0], &direction));
   4750     BCM_IF_ERROR_RETURN(_bcm_td2_l3_route_stat_get_table_info(
   4751                         unit, info, &num_of_tables, &table_info[0], &defip));
   4752 
   4753 #ifdef ALPM_ENABLE
   4754 #ifdef BCM_TOMAHAWK_SUPPORT
   4755     if (soc_feature(unit, soc_feature_alpm2) &&
   4756        (table_info[0].table == L3_DEFIP_ALPM_RAWm ||
   4757         table_info[0].table == L3_DEFIP_ALPM_LEVEL2m ||
   4758         table_info[0].table == L3_DEFIP_ALPM_LEVEL3m)) {
   4759         /* flex counter only available in Full route data mode,
   4760            ALPM_ROUTE_FULL_MD is same as SOC_ALPM_COOKIE_FLEX */
   4761         if ((defip.defip_alpm_cookie & ALPM_ROUTE_FULL_MD) == 0) {
   4762             return BCM_E_UNAVAIL;
   4763         }
   4764 
   4765         rv = alpm_bkt_node_ptr_arr_add(defip.bkt_node, &table_info[0].index);
   4766         if (rv == BCM_E_FULL) {
   4767             return rv;
   4768         }
   4769     }
   4770 #endif
   4771 #endif
   4772 
   4773     for (count = 0; count < num_of_tables; count++) {
   4774         for (flex_table_index=0; 
   4775              flex_table_index < actual_num_tables ; 
   4776              flex_table_index++) {
   4777             if ((table_info[count].direction == direction) &&
   4778                 (table_info[count].table == table[flex_table_index]) ) {
   4779                 if (direction == bcmStatFlexDirectionIngress) {
   4780                     counter_flag = 1;
   4781                     rv = _bcm_esw_stat_flex_attach_ingress_table_counters(
   4782                          unit,
   4783                          table_info[count].table,
   4784                          table_info[count].index,
   4785                          offset_mode,
   4786                          base_index,
   4787                          pool_number);
   4788                     if (BCM_FAILURE(rv)) {
   4789                         break;
   4790                     }
   4791                 } else {
   4792                     counter_flag = 1;
   4793                     rv = _bcm_esw_stat_flex_attach_egress_table_counters(
   4794                          unit,
   4795                          table_info[count].table,
   4796                          table_info[count].index,
   4797                          0,
   4798                          offset_mode,
   4799                          base_index,
   4800                          pool_number);
   4801 
   4802                     if(BCM_FAILURE(rv)) {
   4803                         break;
   4804                     }
   4805                 } 
   4806             }
   4807         }
   4808     }
   4809 
   4810     if (counter_flag == 0) {
   4811         rv = BCM_E_NOT_FOUND;
   4812     }
   4813 
   4814     if (BCM_FAILURE(rv)) {
   4815         return rv;
   4816     }
   4817 
   4818 #ifdef ALPM_ENABLE
   4819     if (soc_feature(unit, soc_feature_alpm) &&
   4820         soc_property_get(unit, spn_L3_ALPM_ENABLE, 0)) {
   4821 
   4822         if (defip.defip_alpm_cookie & SOC_ALPM_LOOKUP_HIT) {
   4823             /* for ALPM, need call add to trigger propation */
   4824             L3_LOCK(unit);
   4825             defip.defip_flags |= BCM_L3_REPLACE;
   4826             if (info->l3a_flags & BCM_L3_IP6) {
   4827                 rv = mbcm_driver[unit]->mbcm_ip6_defip_add(unit, &defip);
   4828             } else {
   4829                 rv = mbcm_driver[unit]->mbcm_ip4_defip_add(unit, &defip);
   4830             }
   4831             L3_UNLOCK(unit);
   4832         }
   4833     }
   4834 #endif
   4835 
   4836     return rv;
   4837 }
   4838 
   4839 
   4840 /*
   4841  * Function:
   4842  *      _bcm_td2_l3_route_stat_detach
   4843  * Description:
   4844  *      Detach counter entries to the given  l3 route index. 
   4845  *
   4846  * Parameters:
   4847  *      unit             - (IN) unit number
   4848  *      info		     - (IN) L3 Route Info
   4849  *
   4850  * Return Value:
   4851  *      BCM_E_XXX
   4852  * Notes:
   4853  */
   4854 bcm_error_t  _bcm_td2_l3_route_stat_detach (
   4855                             int                 unit,
   4856                             bcm_l3_route_t	    *info)
   4857 {
   4858     uint32                     count = 0;
   4859     uint32                     num_of_tables = 0;
   4860     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   4861     bcm_error_t                rv = BCM_E_NONE;
   4862     bcm_error_t                err_code[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION] = {BCM_E_NONE};
   4863     _bcm_defip_cfg_t           defip;
   4864 
   4865     /* Get the table index to be detached */
   4866     BCM_IF_ERROR_RETURN(_bcm_td2_l3_route_stat_get_table_info(
   4867                         unit, info, &num_of_tables, &table_info[0], &defip));
   4868 
   4869 #ifdef ALPM_ENABLE
   4870 #ifdef BCM_TOMAHAWK_SUPPORT
   4871     if (soc_feature(unit, soc_feature_alpm2) &&
   4872         (table_info[0].table == L3_DEFIP_ALPM_RAWm ||
   4873          table_info[0].table == L3_DEFIP_ALPM_LEVEL2m ||
   4874          table_info[0].table == L3_DEFIP_ALPM_LEVEL3m)) {
   4875         /* flex counter only available in Full route data mode,
   4876            ALPM_ROUTE_FULL_MD is same as SOC_ALPM_COOKIE_FLEX */
   4877         if ((defip.defip_alpm_cookie & ALPM_ROUTE_FULL_MD) == 0) {
   4878             return BCM_E_UNAVAIL;
   4879         }
   4880 
   4881         BCM_IF_ERROR_RETURN(
   4882             alpm_bkt_node_ptr_arr_idx_get(defip.bkt_node, &table_info[0].index));
   4883     }
   4884 #endif
   4885 #endif
   4886 
   4887     for (count = 0; count < num_of_tables; count++) {
   4888          if (table_info[count].direction == bcmStatFlexDirectionIngress) {
   4889              rv = _bcm_esw_stat_flex_detach_ingress_table_counters(
   4890                         unit, table_info[count].table, table_info[count].index);
   4891              if (BCM_E_NONE != rv &&
   4892                 BCM_E_NONE == err_code[bcmStatFlexDirectionIngress]) {
   4893                 err_code[bcmStatFlexDirectionIngress] = rv;
   4894              }
   4895          } else {
   4896              rv = _bcm_esw_stat_flex_detach_egress_table_counters(
   4897                         unit, 0, table_info[count].table, table_info[count].index);
   4898              if (BCM_E_NONE != rv &&
   4899                 BCM_E_NONE == err_code[bcmStatFlexDirectionEgress]) {
   4900                 err_code[bcmStatFlexDirectionEgress] = rv;
   4901              }
   4902          }
   4903     }
   4904 
   4905 #ifdef ALPM_ENABLE
   4906 #ifdef BCM_TOMAHAWK_SUPPORT
   4907     if (soc_feature(unit, soc_feature_alpm2) &&
   4908         table_info[0].table == L3_DEFIP_ALPM_RAWm) {
   4909         (void)alpm_bkt_node_ptr_arr_del(defip.bkt_node);
   4910     }
   4911 #endif
   4912 #endif
   4913 
   4914     BCM_STAT_FLEX_DETACH_RV_SET(rv, err_code)
   4915 
   4916     if (BCM_FAILURE(rv)) {
   4917         return rv;
   4918     }
   4919 
   4920 #ifdef ALPM_ENABLE
   4921     if (soc_feature(unit, soc_feature_alpm) &&
   4922         soc_property_get(unit, spn_L3_ALPM_ENABLE, 0)) {
   4923 
   4924         if (defip.defip_alpm_cookie & SOC_ALPM_LOOKUP_HIT) {
   4925             /* for ALPM, need call add to trigger propation */
   4926             L3_LOCK(unit);
   4927             defip.defip_flags |= BCM_L3_REPLACE;
   4928             if (info->l3a_flags & BCM_L3_IP6) {
   4929                 rv = mbcm_driver[unit]->mbcm_ip6_defip_add(unit, &defip);
   4930             } else {
   4931                 rv = mbcm_driver[unit]->mbcm_ip4_defip_add(unit, &defip);
   4932             }
   4933             L3_UNLOCK(unit);
   4934         }
   4935     }
   4936 #endif
   4937 
   4938     return rv;
   4939 }
   4940 
   4941 /*
   4942  * Function:
   4943  *      _bcm_td2_l3_route_stat_counter_get
   4944  *
   4945  * Description:
   4946  *  Get l3 route counter value for specified l3 route index
   4947  *  if sync_mode is set, sync the sw accumulated count
   4948  *  with hw count value first, else return sw count.  
   4949  *
   4950  * Parameters:
   4951  *      unit             - (IN) unit number
   4952  *      sync_mode        - (IN) hwcount is to be synced to sw count 
   4953  *      info			 - (IN)  L3 Route Info
   4954  *      stat             - (IN) l3 route counter stat types
   4955  *      num_entries      - (IN) Number of counter Entries
   4956  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   4957  *      counter_values   - (OUT) Pointer to counter values
   4958  *
   4959  * Return Value:
   4960  *      BCM_E_XXX
   4961  * Notes:
   4962  */
   4963  bcm_error_t  _bcm_td2_l3_route_stat_counter_get(
   4964                             int                 unit, 
   4965                             int                 sync_mode, 
   4966                             bcm_l3_route_t	    *info,
   4967                             bcm_l3_route_stat_t stat, 
   4968                             uint32              num_entries, 
   4969                             uint32              *counter_indexes, 
   4970                             bcm_stat_value_t    *counter_values)
   4971 {
   4972     uint32                     table_count = 0;
   4973     uint32                     index_count = 0;
   4974     uint32                     num_of_tables = 0;
   4975     bcm_stat_flex_direction_t  direction = bcmStatFlexDirectionIngress;
   4976     uint32                     byte_flag = 0;
   4977     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   4978     _bcm_defip_cfg_t           defip;
   4979 
   4980     /* Get the flex counter direction - ingress/egress */
   4981     if ((stat == bcmL3RouteInPackets) ||
   4982         (stat == bcmL3RouteInBytes)) {
   4983          direction = bcmStatFlexDirectionIngress;
   4984     } else {
   4985         /* direction = bcmStatFlexDirectionEgress;*/
   4986         return BCM_E_UNAVAIL;
   4987     }
   4988     if (stat == bcmL3RouteInPackets) {
   4989         byte_flag=0;
   4990     } else {
   4991         byte_flag=1;
   4992     }
   4993    
   4994     /*  Get Table index to read the flex counter */
   4995     BCM_IF_ERROR_RETURN(_bcm_td2_l3_route_stat_get_table_info(
   4996                         unit, info, &num_of_tables, &table_info[0], &defip));
   4997 
   4998 #ifdef ALPM_ENABLE
   4999 #ifdef BCM_TOMAHAWK_SUPPORT
   5000     if (soc_feature(unit, soc_feature_alpm2) &&
   5001         (table_info[0].table == L3_DEFIP_ALPM_RAWm ||
   5002          table_info[0].table == L3_DEFIP_ALPM_LEVEL2m ||
   5003          table_info[0].table == L3_DEFIP_ALPM_LEVEL3m)) {
   5004         BCM_IF_ERROR_RETURN(
   5005             alpm_bkt_node_ptr_arr_idx_get(defip.bkt_node, &table_info[0].index));
   5006     }
   5007 #endif
   5008 #endif
   5009 
   5010     /* Get the flex counter for the attached table index */
   5011     for (table_count = 0; table_count < num_of_tables ; table_count++) {
   5012          if (table_info[table_count].direction == direction) {
   5013              for (index_count = 0; index_count < num_entries ; index_count++) {
   5014                   BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_get(
   5015                                       unit, sync_mode,
   5016                                       table_info[table_count].index,
   5017                                       table_info[table_count].table,
   5018                                       0,
   5019                                       byte_flag,
   5020                                       counter_indexes[index_count],
   5021                                       &counter_values[index_count]));
   5022              }
   5023          }
   5024     }
   5025 
   5026     return BCM_E_NONE;
   5027 }
   5028 
   5029 /*
   5030  * Function:
   5031  *      _bcm_td2_l3_route_stat_counter_set
   5032  *
   5033  * Description:
   5034  *  Set l3 route counter value for specified l3 route index
   5035  *
   5036  * Parameters:
   5037  *      unit             - (IN) unit number
   5038  *      info			 - (IN) L3 Route Info
   5039  *      stat             - (IN) l3 route counter stat types
   5040  *      num_entries      - (IN) Number of counter Entries
   5041  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   5042  *      counter_values   - (OUT) Pointer to counter values
   5043  *
   5044  * Return Value:
   5045  *      BCM_E_XXX
   5046  * Notes:
   5047  */
   5048  bcm_error_t  _bcm_td2_l3_route_stat_counter_set(
   5049                             int                 unit, 
   5050                             bcm_l3_route_t	    *info,
   5051                             bcm_l3_route_stat_t stat, 
   5052                             uint32              num_entries, 
   5053                             uint32              *counter_indexes, 
   5054                             bcm_stat_value_t    *counter_values)
   5055 {
   5056     uint32                     table_count=0;
   5057     uint32                     index_count=0;
   5058     uint32                     num_of_tables=0;
   5059     bcm_stat_flex_direction_t  direction=bcmStatFlexDirectionIngress;
   5060     uint32                     byte_flag=0;
   5061     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   5062     _bcm_defip_cfg_t           defip;
   5063 
   5064     /* Get the flex counter direction - ingress/egress */
   5065     if ((stat == bcmL3RouteInPackets) ||
   5066         (stat == bcmL3RouteInBytes)) {
   5067          direction = bcmStatFlexDirectionIngress;
   5068     } else {
   5069         /* direction = bcmStatFlexDirectionEgress;*/
   5070         return BCM_E_UNAVAIL;
   5071     }
   5072     if (stat == bcmL3RouteInPackets) {
   5073         byte_flag=0;
   5074     } else {
   5075         byte_flag=1;
   5076     }
   5077    
   5078     /*  Get Table index to read the flex counter */
   5079     BCM_IF_ERROR_RETURN(_bcm_td2_l3_route_stat_get_table_info(
   5080                         unit, info, &num_of_tables, &table_info[0], &defip));
   5081 
   5082 #ifdef ALPM_ENABLE
   5083 #ifdef BCM_TOMAHAWK_SUPPORT
   5084     if (soc_feature(unit, soc_feature_alpm2) &&
   5085         (table_info[0].table == L3_DEFIP_ALPM_RAWm ||
   5086          table_info[0].table == L3_DEFIP_ALPM_LEVEL2m ||
   5087          table_info[0].table == L3_DEFIP_ALPM_LEVEL3m)) {
   5088         BCM_IF_ERROR_RETURN(
   5089             alpm_bkt_node_ptr_arr_idx_get(defip.bkt_node, &table_info[0].index));
   5090     }
   5091 #endif
   5092 #endif
   5093 
   5094     /* Get the flex counter for the attached table index */
   5095     for (table_count = 0; table_count < num_of_tables ; table_count++) {
   5096          if (table_info[table_count].direction == direction) {
   5097              for (index_count = 0; index_count < num_entries; index_count++) {
   5098                   BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_set(
   5099                                       unit,
   5100                                       table_info[table_count].index,
   5101                                       table_info[table_count].table,
   5102                                       0,
   5103                                       byte_flag,
   5104                                       counter_indexes[index_count],
   5105                                       &counter_values[index_count]));
   5106              }
   5107          }
   5108     }
   5109     return BCM_E_NONE;
   5110 }
   5111 
   5112 /*
   5113  * Function:
   5114  *      _bcm_td2_l3_route_stat_multi_get
   5115  *
   5116  * Description:
   5117  *  Get Multiple l3 route counter value for specified l3 route index for multiple stat
   5118  *  types
   5119  *
   5120  * Parameters:
   5121  *      unit             - (IN) unit number
   5122  *      info			 - (IN) L3 Route Info
   5123  *      nstat            - (IN) Number of elements in stat array
   5124  *      stat_arr         - (IN) Collected statistics descriptors array
   5125  *      value_arr        - (OUT) Collected counters values
   5126  *
   5127  * Return Value:
   5128  *      BCM_E_XXX
   5129  * Notes:
   5130  */
   5131 
   5132     
   5133  bcm_error_t  _bcm_td2_l3_route_stat_multi_get(
   5134                             int                 unit, 
   5135                             bcm_l3_route_t	    *info,
   5136                             int                 nstat, 
   5137                             bcm_l3_route_stat_t *stat_arr,
   5138                             uint64              *value_arr)
   5139 {
   5140     int              rv = BCM_E_NONE;
   5141     int              idx;
   5142     uint32           counter_indexes = 0;
   5143     bcm_stat_value_t counter_values = {0};
   5144     int              sync_mode = 0; 
   5145 
   5146     /* Iterate of all stats array to retrieve flex counter values */
   5147     for (idx = 0; idx < nstat ;idx++) {
   5148          BCM_IF_ERROR_RETURN(_bcm_td2_l3_route_stat_counter_get( 
   5149                              unit, sync_mode, info, stat_arr[idx], 
   5150                              1, &counter_indexes, &counter_values));
   5151          if ((stat_arr[idx] == bcmL3RouteInPackets)) {
   5152              COMPILER_64_SET(value_arr[idx],
   5153                              COMPILER_64_HI(counter_values.packets64),
   5154                              COMPILER_64_LO(counter_values.packets64));
   5155          } else {
   5156              COMPILER_64_SET(value_arr[idx],
   5157                              COMPILER_64_HI(counter_values.bytes),
   5158                              COMPILER_64_LO(counter_values.bytes));
   5159          }
   5160     }
   5161     return rv;
   5162 }
   5163 
   5164 /*
   5165  * Function:
   5166  *      _bcm_td2_l3_route_stat_multi_get32
   5167  *
   5168  * Description:
   5169  *  Get 32bit l3 route counter value for specified l3 route index for multiple stat
   5170  *  types
   5171  *
   5172  * Parameters:
   5173  *      unit             - (IN) unit number
   5174  *      info		 	 - (IN) L3 Route Info
   5175  *      nstat            - (IN) Number of elements in stat array
   5176  *      stat_arr         - (IN) Collected statistics descriptors array
   5177  *      value_arr        - (OUT) Collected counters values
   5178  *
   5179  * Return Value:
   5180  *      BCM_E_XXX
   5181  * Notes:
   5182  */
   5183  bcm_error_t  _bcm_td2_l3_route_stat_multi_get32(
   5184                             int                 unit, 
   5185                             bcm_l3_route_t	    *info,
   5186                             int                 nstat, 
   5187                             bcm_l3_route_stat_t *stat_arr,
   5188                             uint32              *value_arr)
   5189 {
   5190     int              rv = BCM_E_NONE;
   5191     int              idx;
   5192     uint32           counter_indexes = 0;
   5193     bcm_stat_value_t counter_values = {0};
   5194     int              sync_mode = 0;
   5195 
   5196     /* Iterate of all stats array to retrieve flex counter values */
   5197     for (idx = 0; idx < nstat ;idx++) {
   5198          BCM_IF_ERROR_RETURN(_bcm_td2_l3_route_stat_counter_get( 
   5199                              unit, sync_mode, info, stat_arr[idx], 
   5200                              1, &counter_indexes, &counter_values));
   5201          if ((stat_arr[idx] == bcmL3RouteInPackets)) {
   5202                 value_arr[idx] = counter_values.packets;
   5203          } else {
   5204              value_arr[idx] = COMPILER_64_LO(counter_values.bytes);
   5205          }
   5206     }
   5207     return rv;
   5208 }
   5209 
   5210 /*
   5211  * Function:
   5212  *     _bcm_td2_l3_route_stat_multi_set
   5213  *
   5214  * Description:
   5215  *  Set l3 route counter value for specified l3 route index for multiple stat
   5216  *  types
   5217  *
   5218  * Parameters:
   5219  *      unit             - (IN) unit number
   5220  *      info			 - (IN) L3 Route Info
   5221  *      stat             - (IN) l3 route counter stat types
   5222  *      num_entries      - (IN) Number of counter Entries
   5223  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   5224  *      counter_values   - (OUT) Pointer to counter values
   5225  *
   5226  * Return Value:
   5227  *      BCM_E_XXX
   5228  * Notes:
   5229  */
   5230 bcm_error_t  _bcm_td2_l3_route_stat_multi_set(
   5231                             int                 unit, 
   5232                             bcm_l3_route_t	    *info,
   5233                             int                 nstat, 
   5234                             bcm_l3_route_stat_t *stat_arr,
   5235                             uint64              *value_arr)
   5236 {
   5237     int              rv = BCM_E_NONE;
   5238     int              idx;
   5239     uint32           counter_indexes = 0;
   5240     bcm_stat_value_t counter_values = {0};
   5241 
   5242     /* Iterate f all stats array to retrieve flex counter values */
   5243     for (idx = 0; idx < nstat ;idx++) {
   5244          if ((stat_arr[idx] == bcmL3RouteInPackets)) {
   5245               counter_values.packets = COMPILER_64_LO(value_arr[idx]);
   5246          } else {
   5247               COMPILER_64_SET(counter_values.bytes,
   5248                               COMPILER_64_HI(value_arr[idx]),
   5249                               COMPILER_64_LO(value_arr[idx]));
   5250          }
   5251           BCM_IF_ERROR_RETURN(_bcm_td2_l3_route_stat_counter_set( 
   5252                              unit, info, stat_arr[idx], 
   5253                              1, &counter_indexes, &counter_values));
   5254     }
   5255     return rv;
   5256 
   5257 }
   5258 
   5259 /*
   5260  * Function:
   5261  *      _bcm_td2_l3_route_stat_multi_set32
   5262  *
   5263  * Description:
   5264  *  Set 32bit l3 route counter value for specified l3 route index for multiple stat
   5265  *  types
   5266  *
   5267  * Parameters:
   5268  *      unit             - (IN) unit number
   5269  *      info			 - (IN) L3 Route Info
   5270  *      stat             - (IN) l3 route counter stat types
   5271  *      num_entries      - (IN) Number of counter Entries
   5272  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   5273  *      counter_values   - (OUT) Pointer to counter values
   5274  *
   5275  * Return Value:
   5276  *      BCM_E_XXX
   5277  * Notes:
   5278  */
   5279 
   5280  bcm_error_t  _bcm_td2_l3_route_stat_multi_set32(
   5281                             int                 unit, 
   5282                             bcm_l3_route_t	    *info,
   5283                             int                 nstat, 
   5284                             bcm_l3_route_stat_t *stat_arr,
   5285                             uint32              *value_arr)
   5286 {
   5287     int              rv = BCM_E_NONE;
   5288     int              idx;
   5289     uint32           counter_indexes = 0;
   5290     bcm_stat_value_t counter_values = {0};
   5291 
   5292     /* Iterate of all stats array to retrieve flex counter values */
   5293     for (idx = 0; idx < nstat ;idx++) {
   5294          if ((stat_arr[idx] == bcmL3RouteInPackets)) {
   5295              counter_values.packets = value_arr[idx];
   5296          } else {
   5297              COMPILER_64_SET(counter_values.bytes,0,value_arr[idx]);
   5298          }
   5299 
   5300          BCM_IF_ERROR_RETURN(_bcm_td2_l3_route_stat_counter_set( 
   5301                              unit, info, stat_arr[idx], 
   5302                              1, &counter_indexes, &counter_values));
   5303     }
   5304     return rv;
   5305 }
   5306 
   5307 /*
   5308  * Function: 
   5309  *      _bcm_td2_l3_route_stat_id_get
   5310  *
   5311  * Description: 
   5312  *      Get Stat Counter if associated with given l3 route index
   5313  *
   5314  * Parameters: 
   5315  *      unit             - (IN) bcm device
   5316  *      info			 - (IN) L3 Route Info
   5317  *      stat             - (IN) l3 route counter stat types
   5318  *      stat_counter_id  - (IN) Stat Counter ID.
   5319  *
   5320  * Returns:
   5321  *      BCM_E_NONE - Success
   5322  *      BCM_E_XXX
   5323  * Notes:
   5324  */
   5325 
   5326  bcm_error_t  _bcm_td2_l3_route_stat_id_get(
   5327                             int                 unit,
   5328                             bcm_l3_route_t	    *info,
   5329                             bcm_l3_route_stat_t stat, 
   5330                             uint32              *stat_counter_id) 
   5331 {
   5332     bcm_stat_flex_direction_t  direction = bcmStatFlexDirectionIngress;
   5333     uint32                     num_of_tables = 0;
   5334     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   5335     uint32                     index = 0;
   5336     uint32                     num_stat_counter_ids = 0;
   5337     _bcm_defip_cfg_t           defip;
   5338 
   5339     if ((stat == bcmL3RouteInPackets) ||
   5340         (stat == bcmL3RouteInBytes)) {
   5341          direction = bcmStatFlexDirectionIngress;
   5342     } else {
   5343         /* direction = bcmStatFlexDirectionEgress;*/
   5344         return BCM_E_UNAVAIL;
   5345     }
   5346 
   5347     /*  Get Tables, for which flex counter are attached  */
   5348     BCM_IF_ERROR_RETURN(_bcm_td2_l3_route_stat_get_table_info(
   5349                         unit, info, &num_of_tables, &table_info[0], &defip));
   5350 
   5351 #ifdef ALPM_ENABLE
   5352 #ifdef BCM_TOMAHAWK_SUPPORT
   5353     if (soc_feature(unit, soc_feature_alpm2) &&
   5354         (table_info[0].table == L3_DEFIP_ALPM_RAWm ||
   5355          table_info[0].table == L3_DEFIP_ALPM_LEVEL2m ||
   5356          table_info[0].table == L3_DEFIP_ALPM_LEVEL3m)) {
   5357         BCM_IF_ERROR_RETURN(
   5358             alpm_bkt_node_ptr_arr_idx_get(defip.bkt_node, &table_info[0].index));
   5359     }
   5360 #endif
   5361 #endif
   5362 
   5363     /* Retrieve stat counter id */
   5364     for (index = 0; index < num_of_tables ; index++) {
   5365          if (table_info[index].direction == direction)
   5366              return _bcm_esw_stat_flex_get_counter_id(
   5367                                   unit, 1, &table_info[index],
   5368                                   &num_stat_counter_ids, stat_counter_id);
   5369     }
   5370     return BCM_E_NOT_FOUND;
   5371 }
   5372 /***************************************************************
   5373  *                        IP4 Options
   5374  */
   5375 
   5376 /* Free IP4 options resources */
   5377 int _bcm_td2_l3_ip4_options_free_resources(int unit)
   5378 {
   5379     _bcm_l3_bookkeeping_t *l3_bk_info = L3_INFO(unit);
   5380 
   5381     /* free ip4 options profile usage bitmap */
   5382     if (NULL != l3_bk_info->ip4_options_bitmap) {
   5383         sal_free(l3_bk_info->ip4_options_bitmap);
   5384         l3_bk_info->ip4_options_bitmap = NULL;
   5385     }
   5386 
   5387     /* free ip4 options hw index usage bitmap */
   5388     if (NULL != l3_bk_info->ip4_profiles_hw_idx) {
   5389         sal_free(l3_bk_info->ip4_profiles_hw_idx);
   5390         l3_bk_info->ip4_profiles_hw_idx = NULL;
   5391     }
   5392     if (NULL != ip4_profiles_hw_idx_lock[unit]) {
   5393         sal_mutex_destroy(ip4_profiles_hw_idx_lock[unit]);
   5394         ip4_profiles_hw_idx_lock[unit] = NULL;
   5395     }
   5396     return BCM_E_NONE;
   5397 }
   5398 
   5399 /* Initialize the IP4 options book keeping */
   5400 int 
   5401 _bcm_td2_l3_ip4_options_profile_init(int unit)
   5402 {
   5403     _bcm_l3_bookkeeping_t *l3_bk_info = L3_INFO(unit);
   5404     int ip4_options_profiles;
   5405     int default_index = BCM_L3_IP4_OPTIONS_DEF_PROFILE_INDEX;
   5406     int rv = BCM_E_NONE;
   5407 
   5408     ip4_options_profiles = _BCM_IP4_OPTIONS_LEN;
   5409 
   5410     /* Allocate ip4 options profile usage bitmap */
   5411     if (NULL == l3_bk_info->ip4_options_bitmap) {
   5412         l3_bk_info->ip4_options_bitmap =
   5413             sal_alloc(SHR_BITALLOCSIZE(ip4_options_profiles), "ip4_options_bitmap");
   5414         if (l3_bk_info->ip4_options_bitmap == NULL) {
   5415             _bcm_td2_l3_ip4_options_free_resources(unit);
   5416             return BCM_E_MEMORY;
   5417         }
   5418     }
   5419     sal_memset(l3_bk_info->ip4_options_bitmap, 0, SHR_BITALLOCSIZE(ip4_options_profiles));
   5420     if (NULL == l3_bk_info->ip4_profiles_hw_idx) {
   5421         l3_bk_info->ip4_profiles_hw_idx = 
   5422             sal_alloc(sizeof(uint32) * ip4_options_profiles, "ip4_profiles_hw_idx");
   5423         if (l3_bk_info->ip4_profiles_hw_idx == NULL) {
   5424             _bcm_td2_l3_ip4_options_free_resources(unit);
   5425             return BCM_E_MEMORY;
   5426         }    
   5427     }
   5428     sal_memset(l3_bk_info->ip4_profiles_hw_idx, 0, (sizeof(uint32) * ip4_options_profiles));
   5429 
   5430     if (NULL == ip4_profiles_hw_idx_lock[unit]) {
   5431         ip4_profiles_hw_idx_lock[unit] = sal_mutex_create("Ip4 profiles hw idx mutex");
   5432         
   5433         if (NULL == ip4_profiles_hw_idx_lock[unit]) {
   5434             _bcm_td2_l3_ip4_options_free_resources(unit);
   5435             return BCM_E_MEMORY;
   5436         }
   5437     }
   5438     rv = _bcm_td2_l3_ip4_options_profile_create (unit, BCM_L3_IP4_OPTIONS_WITH_ID, 
   5439                                             bcmIntfIPOptionActionDrop, &default_index);
   5440     return rv;
   5441 }
   5442 
   5443 
   5444 
   5445 STATIC int
   5446 _bcm_td2_l3_ip4_profile_id_alloc(int unit)
   5447 {
   5448     int i, option_profile_size = -1;
   5449     SHR_BITDCL *bitmap;
   5450 
   5451     bitmap = L3_INFO(unit)->ip4_options_bitmap;
   5452     option_profile_size = _BCM_IP4_OPTIONS_LEN;
   5453     for (i = 0; i < option_profile_size; i++) {
   5454         if (!SHR_BITGET(bitmap, i)) {
   5455             return i;
   5456         }
   5457     }
   5458     return -1;
   5459 }
   5460 
   5461 int
   5462 _bcm_td2_l3_ip4_options_profile_create(int unit, uint32 flags, 
   5463                                    bcm_l3_ip4_options_action_t default_action, 
   5464                                    int *ip4_options_profile_id)
   5465 {
   5466     ip_option_control_profile_table_entry_t ip_option_profile[_BCM_IP_OPTION_PROFILE_CHUNK];
   5467     int id, index = -1, rv = BCM_E_NONE;
   5468     int i, copy_cpu, drop;
   5469     void *entries[1], *entry;
   5470 
   5471     /* Check for pre-specified ID */
   5472     if (flags & BCM_L3_IP4_OPTIONS_WITH_ID) {
   5473         id = *ip4_options_profile_id;
   5474         if (id >= _BCM_IP4_OPTIONS_LEN ) {
   5475             return BCM_E_PARAM;
   5476         }  
   5477         if (_BCM_IP4_OPTIONS_USED_GET(unit, id)) {
   5478             if (!(flags & BCM_L3_IP4_OPTIONS_REPLACE)) {
   5479                 return BCM_E_EXISTS;
   5480             } else {
   5481                 if (id == BCM_L3_IP4_OPTIONS_DEF_PROFILE_INDEX) {
   5482                     return BCM_E_BADID;
   5483                 }
   5484             }
   5485         } 
   5486     }
   5487     /* Reserve a chunk in the IP4_OPTION Profile table */
   5488     sal_memset(ip_option_profile, 0, sizeof(ip_option_profile));
   5489     entries[0] = &ip_option_profile;
   5490 
   5491     /* Set the default action for the profile */
   5492     switch (default_action) {
   5493     case bcmIntfIPOptionActionCopyToCPU:
   5494         copy_cpu = 1;
   5495         drop = 0;
   5496         break;
   5497     case bcmIntfIPOptionActionDrop:
   5498         copy_cpu = 0;
   5499         drop = 1;
   5500         break;
   5501     case bcmIntfIPOptionActionCopyCPUAndDrop:
   5502         copy_cpu = 1;
   5503         drop = 1;
   5504         break;
   5505     case bcmIntfIPOptionActionNone:
   5506     default :
   5507         copy_cpu = 0;
   5508         drop = 0;
   5509         break;
   5510     }
   5511     for (i = 0; i < _BCM_IP_OPTION_PROFILE_CHUNK; i++) {
   5512         entry = &ip_option_profile[i];
   5513         soc_mem_field32_set(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry,
   5514                             COPYTO_CPUf, copy_cpu);
   5515         soc_mem_field32_set(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry,
   5516                             DROPf, drop);
   5517     }
   5518 
   5519     BCM_IF_ERROR_RETURN(_bcm_l3_ip4_options_profile_entry_add(unit, entries, 
   5520                                         _BCM_IP_OPTION_PROFILE_CHUNK,
   5521                                          (uint32 *)&index));
   5522        /* To avoid deadlock, There should be not any semaphore 
   5523         * between HW_IDX_LOCK and HW_IDX_UNLOCK 
   5524         */
   5525     HW_IDX_LOCK(unit);
   5526 
   5527     if (flags & BCM_L3_IP4_OPTIONS_WITH_ID) {
   5528         id = *ip4_options_profile_id;
   5529         if (0 == (_BCM_IP4_OPTIONS_USED_GET(unit, id))) {
   5530             _BCM_IP4_OPTIONS_USED_SET(unit, id);
   5531         }
   5532     } else {
   5533         id = _bcm_td2_l3_ip4_profile_id_alloc(unit);
   5534         if (id == -1) {
   5535             HW_IDX_UNLOCK(unit);
   5536             _bcm_l3_ip4_options_profile_entry_delete(unit, index);
   5537             return BCM_E_RESOURCE;
   5538         }
   5539         _BCM_IP4_OPTIONS_USED_SET(unit, id);
   5540         *ip4_options_profile_id = id;
   5541     }
   5542 
   5543     L3_INFO(unit)->ip4_profiles_hw_idx[id] = (index / 
   5544                                           _BCM_IP_OPTION_PROFILE_CHUNK);
   5545     HW_IDX_UNLOCK(unit);
   5546 
   5547     return rv;
   5548 }
   5549 
   5550 
   5551 
   5552 int 
   5553 _bcm_td2_l3_ip4_options_profile_destroy(int unit, int ip4_options_profile_id)
   5554 {
   5555     int id, rv = BCM_E_UNAVAIL;
   5556     int index;
   5557     
   5558     if (ip4_options_profile_id == BCM_L3_IP4_OPTIONS_DEF_PROFILE_INDEX) {
   5559         return BCM_E_BADID;
   5560     }
   5561     L3_LOCK(unit);
   5562     id = ip4_options_profile_id;
   5563     if (!_BCM_IP4_OPTIONS_USED_GET(unit, id)) {
   5564         L3_UNLOCK(unit);
   5565         return BCM_E_NOT_FOUND;
   5566     } else {
   5567     
   5568         HW_IDX_LOCK(unit);
   5569         index = L3_INFO(unit)->ip4_profiles_hw_idx[id];
   5570         L3_INFO(unit)->ip4_profiles_hw_idx[id] = 0;
   5571         HW_IDX_UNLOCK(unit);
   5572         
   5573         rv = _bcm_l3_ip4_options_profile_entry_delete
   5574                  (unit, index * _BCM_IP_OPTION_PROFILE_CHUNK);
   5575         
   5576         _BCM_IP4_OPTIONS_USED_CLR(unit, id);
   5577     }
   5578 #ifdef BCM_WARM_BOOT_SUPPORT
   5579     SOC_CONTROL_LOCK(unit);
   5580     SOC_CONTROL(unit)->scache_dirty = 1;
   5581     SOC_CONTROL_UNLOCK(unit);
   5582 #endif
   5583     L3_UNLOCK(unit);
   5584     return rv;
   5585 }
   5586 
   5587 /* Add an entry to a  ip_option_profile */
   5588 /* Read the existing profile chunk, modify what's needed and add the 
   5589  * new profile. This can result in the HW profile index changing for a 
   5590  * given ID */
   5591 int 
   5592 _bcm_td2_l3_ip4_options_profile_action_set(int unit,
   5593                          int ip4_options_profile_id, 
   5594                          int ip4_option, 
   5595                          bcm_l3_ip4_options_action_t action)
   5596 {
   5597     ip_option_control_profile_table_entry_t ip_option_profile[_BCM_IP_OPTION_PROFILE_CHUNK];
   5598     int id, index = -1, rv = BCM_E_NONE;
   5599     void *entries[1], *entry;
   5600     int offset;
   5601 
   5602     /*  Make sure module was initialized. */
   5603     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   5604         return (BCM_E_INIT);
   5605     }
   5606 
   5607     id = ip4_options_profile_id;
   5608     if (id == BCM_L3_IP4_OPTIONS_DEF_PROFILE_INDEX) {
   5609         return BCM_E_BADID;
   5610     }
   5611     L3_LOCK(unit);
   5612 
   5613     if (!_BCM_IP4_OPTIONS_USED_GET(unit, id)) {
   5614         L3_UNLOCK(unit);
   5615         return BCM_E_PARAM;
   5616     } else {
   5617         entries[0] = ip_option_profile;
   5618 
   5619         /* Base index of table in hardware */
   5620         GET_HW_IDX(unit, index, id);
   5621         index = index * _BCM_IP_OPTION_PROFILE_CHUNK;
   5622 
   5623         rv = _bcm_l3_ip4_options_profile_entry_get(unit, index, 
   5624                                             _BCM_IP_OPTION_PROFILE_CHUNK, 
   5625                                             entries);
   5626         if (BCM_FAILURE(rv)) {
   5627             L3_UNLOCK(unit);
   5628             return (rv);
   5629         }
   5630 
   5631         /* Offset within table */
   5632         offset = ip4_option;
   5633 
   5634         /* Modify what's needed */
   5635         entry = &ip_option_profile[offset];
   5636         switch (action) {
   5637         case bcmIntfIPOptionActionCopyToCPU:
   5638             soc_mem_field32_set(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry,
   5639                                 COPYTO_CPUf, 1);
   5640             soc_mem_field32_set(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry,
   5641                                 DROPf, 0);
   5642             break;
   5643 
   5644         case bcmIntfIPOptionActionDrop:
   5645             soc_mem_field32_set(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry,
   5646                                 COPYTO_CPUf, 0);
   5647             soc_mem_field32_set(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry,
   5648                                 DROPf, 1);
   5649             break;
   5650 
   5651         case bcmIntfIPOptionActionCopyCPUAndDrop:
   5652             soc_mem_field32_set(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry,
   5653                                 COPYTO_CPUf, 1);
   5654             soc_mem_field32_set(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry,
   5655                                 DROPf, 1);
   5656             break;
   5657 
   5658         case bcmIntfIPOptionActionNone:
   5659         default :
   5660             soc_mem_field32_set(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry,
   5661                                 COPYTO_CPUf, 0);
   5662             soc_mem_field32_set(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry,
   5663                                 DROPf, 0);
   5664 
   5665         }
   5666         /* Delete the old profile chunk */
   5667         rv = _bcm_l3_ip4_options_profile_entry_delete(unit, index);
   5668         if (BCM_FAILURE(rv)) {
   5669             L3_UNLOCK(unit);
   5670             return (rv);
   5671         }
   5672 
   5673         /* Add new chunk and store new HW index */
   5674         rv = _bcm_l3_ip4_options_profile_entry_add(unit, entries,
   5675                                             _BCM_IP_OPTION_PROFILE_CHUNK, 
   5676                                             (uint32 *)&index);
   5677         
   5678         SET_HW_IDX(unit, id, index / _BCM_IP_OPTION_PROFILE_CHUNK);
   5679 
   5680     }
   5681 #ifdef BCM_WARM_BOOT_SUPPORT
   5682     SOC_CONTROL_LOCK(unit);
   5683     SOC_CONTROL(unit)->scache_dirty = 1;
   5684     SOC_CONTROL_UNLOCK(unit);
   5685 #endif
   5686     L3_UNLOCK(unit);
   5687     return rv;
   5688 }
   5689 
   5690 
   5691 int 
   5692 _bcm_td2_l3_ip4_options_profile_action_get(int unit,
   5693                          int ip4_options_profile_id, 
   5694                          int ip4_option, 
   5695                          bcm_l3_ip4_options_action_t *action)
   5696 {
   5697     ip_option_control_profile_table_entry_t ip_option_profile[_BCM_IP_OPTION_PROFILE_CHUNK];
   5698     int id, index = -1, rv = BCM_E_NONE;
   5699     void *entries[1], *entry;
   5700     int offset;
   5701     int copy_to_cpu, drop;
   5702 
   5703     /*  Make sure module was initialized. */
   5704     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   5705         return (BCM_E_INIT);
   5706     }
   5707 
   5708     id = ip4_options_profile_id;
   5709     L3_LOCK(unit);
   5710 
   5711     if (!_BCM_IP4_OPTIONS_USED_GET(unit, id)) {
   5712         L3_UNLOCK(unit);
   5713         return BCM_E_PARAM;
   5714     } else {
   5715         entries[0] = ip_option_profile;
   5716 
   5717         /* Base index of table in hardware */
   5718         GET_HW_IDX(unit, index, id);
   5719 
   5720         index = index * _BCM_IP_OPTION_PROFILE_CHUNK;
   5721 
   5722         rv = _bcm_l3_ip4_options_profile_entry_get(unit, index, 
   5723                                             _BCM_IP_OPTION_PROFILE_CHUNK, 
   5724                                             entries);
   5725         if (BCM_FAILURE(rv)) {
   5726             L3_UNLOCK(unit);
   5727             return (rv);
   5728         }
   5729 
   5730         /* Offset within table */
   5731         offset = ip4_option;
   5732 
   5733         /* Modify what's needed */
   5734         entry = &ip_option_profile[offset];
   5735 
   5736         copy_to_cpu = soc_mem_field32_get(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry,
   5737                                 COPYTO_CPUf);
   5738         drop = soc_mem_field32_get(unit, IP_OPTION_CONTROL_PROFILE_TABLEm, entry,
   5739                                 DROPf);
   5740 
   5741         *action = bcmIntfIPOptionActionNone;
   5742         if ((copy_to_cpu == 0) && (drop == 0)) {
   5743             *action = bcmIntfIPOptionActionNone;
   5744         }
   5745         if ((copy_to_cpu == 1) && (drop == 0)) {
   5746             *action = bcmIntfIPOptionActionCopyToCPU;
   5747         }
   5748         if ((copy_to_cpu == 0) && (drop == 1)) {
   5749             *action = bcmIntfIPOptionActionDrop;
   5750         }
   5751         if ((copy_to_cpu == 1) && (drop == 1)) {
   5752             *action = bcmIntfIPOptionActionCopyCPUAndDrop;
   5753         }
   5754     }
   5755     L3_UNLOCK(unit);
   5756     return rv;
   5757 }
   5758 
   5759 /* Get the list of all created IP options profile IDs */
   5760 int
   5761 _bcm_td2_l3_ip4_options_profile_multi_get(int unit, int array_size, 
   5762                                       int *ip_options_ids_array, 
   5763                                       int *array_count)
   5764 {
   5765     int rv = BCM_E_NONE;
   5766     int idx, count;
   5767 
   5768     L3_LOCK(unit);
   5769     if (array_size == 0) {
   5770         /* querying the number of map-ids for storage allocation */
   5771         if (array_count == NULL) {
   5772             rv = BCM_E_PARAM;
   5773         }
   5774         if (BCM_SUCCESS(rv)) {
   5775             count = 0;
   5776             *array_count = 0;
   5777             SHR_BITCOUNT_RANGE(L3_INFO(unit)->ip4_options_bitmap, count, 
   5778                                0, _BCM_IP4_OPTIONS_LEN);
   5779             *array_count += count;
   5780         }
   5781     } else {
   5782         if ((ip_options_ids_array == NULL) || (array_count == NULL)) {
   5783             rv = BCM_E_PARAM;
   5784         }
   5785         if (BCM_SUCCESS(rv)) {
   5786             count = 0;
   5787             for (idx = 0; ((idx < _BCM_IP4_OPTIONS_LEN) && 
   5788                          (count < array_size)); idx++) {
   5789                 if (_BCM_IP4_OPTIONS_USED_GET(unit, idx)) {
   5790                     *(ip_options_ids_array + count) = idx;
   5791                     count++;
   5792                 }
   5793             }
   5794             *array_count = count;
   5795         }
   5796     }
   5797     L3_UNLOCK(unit);
   5798     return rv;
   5799 }
   5800 
   5801 /* Get the IP options actions for a given profile ID */
   5802 int
   5803 _bcm_td2_l3_ip4_options_profile_action_multi_get(int unit, uint32 flags,
   5804                           int ip_option_profile_id, int array_size, 
   5805                           bcm_l3_ip4_options_action_t *array, int *array_count)
   5806 {
   5807     int             rv = BCM_E_NONE;
   5808     int             num_entries, idx, id, hw_id, alloc_size, entry_size, count;
   5809     uint8           *dma_buf;
   5810     void            *entry;
   5811     soc_mem_t       mem;
   5812     bcm_l3_ip4_options_action_t   *action;
   5813     int copy_to_cpu, drop;
   5814 
   5815     /* ignore with_id & replace flags */
   5816     id = ip_option_profile_id;
   5817     hw_id = 0;
   5818     num_entries = 0;
   5819     entry_size = 0;
   5820     L3_LOCK(unit);
   5821 
   5822     if (!_BCM_IP4_OPTIONS_USED_GET(unit, id)) {
   5823         rv = BCM_E_PARAM;
   5824     }
   5825     num_entries = _BCM_IP_OPTION_PROFILE_CHUNK;
   5826     entry_size = sizeof(ip_option_control_profile_table_entry_t);
   5827     
   5828     GET_HW_IDX(unit, hw_id, id);
   5829     hw_id = hw_id * _BCM_IP_OPTION_PROFILE_CHUNK;
   5830     mem = IP_OPTION_CONTROL_PROFILE_TABLEm;
   5831 
   5832 
   5833     L3_UNLOCK(unit);
   5834     BCM_IF_ERROR_RETURN(rv);
   5835 
   5836     if (array_size == 0) { /* querying the size of profile-chunk */
   5837         *array_count = num_entries;
   5838         return BCM_E_NONE;
   5839     }
   5840     if (!array || !array_count) {
   5841         return BCM_E_PARAM;
   5842     }
   5843 
   5844     /* Allocate memory for DMA & regular */
   5845     alloc_size = num_entries * entry_size;
   5846     dma_buf = soc_cm_salloc(unit, alloc_size, "IP option multi get DMA buf");
   5847     if (!dma_buf) {
   5848         return BCM_E_MEMORY;
   5849     }
   5850     sal_memset(dma_buf, 0, alloc_size);
   5851 
   5852     /* Read the profile chunk */
   5853     rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, hw_id, 
   5854                             (hw_id + num_entries - 1), dma_buf);
   5855     if (BCM_FAILURE(rv)) {
   5856         soc_cm_sfree(unit, dma_buf);
   5857         return rv;
   5858     }
   5859 
   5860     count = 0;
   5861     L3_LOCK(unit);
   5862     for (idx=0; ((idx<num_entries) && (count < array_size)); idx++) {
   5863         action = &array[idx];
   5864         entry = soc_mem_table_idx_to_pointer(unit, mem, void *, 
   5865                                              dma_buf, idx);
   5866         copy_to_cpu = soc_mem_field32_get(unit, mem, entry, COPY_TO_CPUf);
   5867         drop = soc_mem_field32_get(unit, mem, entry, DROPf);
   5868 
   5869         *action = bcmIntfIPOptionActionNone;
   5870         if ((copy_to_cpu == 0) && (drop == 0)) {
   5871             *action = bcmIntfIPOptionActionNone;
   5872         }
   5873         if ((copy_to_cpu == 1) && (drop == 0)) {
   5874             *action = bcmIntfIPOptionActionCopyToCPU;
   5875         }
   5876         if ((copy_to_cpu == 0) && (drop == 1)) {
   5877             *action = bcmIntfIPOptionActionDrop;
   5878         }
   5879         if ((copy_to_cpu == 1) && (drop == 1)) {
   5880             *action = bcmIntfIPOptionActionCopyCPUAndDrop;
   5881         }
   5882         count++;
   5883     }
   5884     L3_UNLOCK(unit);
   5885     soc_cm_sfree(unit, dma_buf);
   5886 
   5887     BCM_IF_ERROR_RETURN(rv);
   5888 
   5889     *array_count = count;
   5890     return BCM_E_NONE;
   5891 }
   5892 
   5893 
   5894 /* Function:
   5895 *	   _bcm_td2_l3_ip4_options_profile_id2idx
   5896 * Purpose:
   5897 *	   Translate profile ID into hardware table index.
   5898 * Parameters:
   5899 * Returns:
   5900 *	   BCM_E_XXX
   5901 */	   
   5902 int
   5903 _bcm_td2_l3_ip4_options_profile_id2idx(int unit, int profile_id, int *hw_idx)
   5904 {
   5905     if (hw_idx == NULL) {
   5906         return BCM_E_PARAM;
   5907     }
   5908     /*  Make sure module was initialized. */
   5909     if (L3_INFO(unit)->ip4_options_bitmap == NULL) {
   5910         return (BCM_E_INIT);
   5911     }
   5912 
   5913     if (!_BCM_IP4_OPTIONS_USED_GET(unit, profile_id)) {
   5914         return BCM_E_NOT_FOUND;
   5915     } else {
   5916         GET_HW_IDX(unit, *hw_idx, profile_id);
   5917         *hw_idx = *hw_idx * _BCM_IP_OPTION_PROFILE_CHUNK;
   5918     }
   5919     return BCM_E_NONE;
   5920 }
   5921 
   5922 /* Function:
   5923 *	   _bcm_td2_l3_ip4_options_profile_idx2id
   5924 * Purpose:
   5925 *	   Translate hardware table index into Profile ID used by API
   5926 * Parameters:
   5927 * Returns:
   5928 *	   BCM_E_XXX
   5929 */	   
   5930 int
   5931 _bcm_td2_l3_ip4_options_profile_idx2id(int unit, int hw_idx, int *profile_id)
   5932 {
   5933     int id;
   5934     int profiles_hw_idx;
   5935     
   5936     if (profile_id == NULL) {
   5937         return BCM_E_PARAM;
   5938     }
   5939        /* To avoid deadlock, There should be not any semaphore 
   5940         * between HW_IDX_LOCK and HW_IDX_UNLOCK 
   5941         */
   5942     HW_IDX_LOCK(unit); 
   5943 
   5944     for (id = 0; id < _BCM_IP4_OPTIONS_LEN; id++) {
   5945         if (_BCM_IP4_OPTIONS_USED_GET(unit, id)) {
   5946             profiles_hw_idx = L3_INFO(unit)->ip4_profiles_hw_idx[id];
   5947             if (profiles_hw_idx * _BCM_IP_OPTION_PROFILE_CHUNK == hw_idx) {
   5948                 *profile_id = id;
   5949                 HW_IDX_UNLOCK(unit); 
   5950                 return BCM_E_NONE;
   5951             }
   5952         }
   5953     }
   5954     HW_IDX_UNLOCK(unit); 
   5955     return BCM_E_NOT_FOUND;
   5956 }
   5957 
   5958 /*
   5959  * Function:
   5960  *      _bcm_td2_nh_nat_id_update
   5961  * Purpose:
   5962  *      Routine updates the dst realm nat id of 
   5963  *      next hop interfaces associating with the key.
   5964  * Parameters:
   5965  *      unit     - (IN) SOC unit number.
   5966  *      key_type - (IN) Type of the key which the nh entries associate with.
   5967  *      val      - (IN) Value of the key. 
   5968  *      nat_id   - (IN) Nat realm id.
   5969  * Returns:
   5970  *    BCM_E_XXX
   5971  */
   5972 STATIC int
   5973 _bcm_td2_nh_nat_id_update(int unit, int key_type, void *val, int nat_id)
   5974 {
   5975     uint32 *ing_entry_ptr;        /* Ingress next hop entry pointer.*/
   5976     uint32 *initial_ing_entry_ptr;/* Initial Ingress next hop entry pointer.*/
   5977     char *ing_tbl_ptr = NULL;     /* Dma table pointer.             */
   5978     char *initial_ing_tbl_ptr = NULL; /* Dma initial ing nh table pointer. */
   5979     int ifindex;                  /* Interface index.               */
   5980     soc_mem_t mem;                /* Next hop memory.               */
   5981     soc_mem_t initial_mem;        /* Inital Ingress Next hop memory. */
   5982     int idx;                      /* Iteration index.               */
   5983     char *egr_tbl_ptr = NULL;     /* Dma egress nh table pointer.   */
   5984     uint32 *egr_entry_ptr = NULL; /* Egress next hop entry pointer. */
   5985     int rv = BCM_E_NONE;          /* Operation return status.       */
   5986     uint32 *egr_intf_entry_ptr;        /* EGR_L3_INTF entry pointer. */
   5987     char   *egr_intf_tbl_ptr = NULL;   /* EGR_L3_INTF dma table pointer.  */
   5988     uint32 *vlan_mpls_entry_ptr;        /* VLAN_MPLS entry pointer. */
   5989     char   *vlan_mpls_tbl_ptr = NULL;   /* VLAN_MPLS dma table pointer.  */
   5990     bcm_vlan_t     vlan;
   5991     bcm_if_t       l3_iif;
   5992     _bcm_l3_intf_fields_t *fld;    /* Interface table common fields. */
   5993     soc_field_t intf_field = INTF_NUMf;
   5994     soc_mem_t vlan_mem = VLAN_MPLSm;
   5995     int table_ent_size;
   5996 
   5997 #ifdef BCM_TRIDENT3_SUPPORT
   5998     if (SOC_IS_TRIDENT3X(unit)) {
   5999         vlan_mem = VLAN_TABm;
   6000     }
   6001 #endif
   6002     
   6003     /* Get next table memory. */
   6004     mem         = BCM_XGS3_L3_MEM(unit, nh);
   6005     initial_mem = INITIAL_ING_L3_NEXT_HOPm;
   6006     fld = (_bcm_l3_intf_fields_t *)BCM_XGS3_L3_MEM_FIELDS(unit, intf);
   6007 
   6008     /* Table DMA the nhtable to software copy */
   6009     rv = bcm_xgs3_l3_tbl_dma(unit, mem, BCM_XGS3_L3_ENT_SZ(unit, nh), "nh_tbl",
   6010                              &ing_tbl_ptr, NULL);
   6011     BCM_IF_ERROR_RETURN(rv);
   6012 
   6013     /* Get initial next table memory. */
   6014     rv = bcm_xgs3_l3_tbl_dma(unit, initial_mem,
   6015                              sizeof(initial_ing_l3_next_hop_entry_t),
   6016                              "initial_nh_tbl", &initial_ing_tbl_ptr, NULL);
   6017     if (rv < 0) {
   6018         goto cleanup;
   6019     }
   6020 
   6021 
   6022     /*  Read egress next hop entry. */
   6023     rv = bcm_xgs3_l3_tbl_dma(unit, EGR_L3_NEXT_HOPm,
   6024                              sizeof(egr_l3_next_hop_entry_t), "egr_nh_tbl",
   6025                              &egr_tbl_ptr, NULL);
   6026     if (rv < 0) {
   6027         goto cleanup;
   6028     }
   6029 
   6030     if ((key_type == _BCM_NH_UPDATE_KEY_VLAN) ||
   6031          (key_type == _BCM_NH_UPDATE_KEY_L3_IIF)) {
   6032         /*  Read EGR_L3_INTF table. */
   6033         rv = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, intf),
   6034                                  sizeof(egr_l3_intf_entry_t), "egr_l3_intf_tbl",
   6035                                  &egr_intf_tbl_ptr, NULL);
   6036         if (rv < 0) {
   6037             goto cleanup;
   6038         }
   6039     }
   6040 
   6041     if ((BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit)) &&
   6042         (key_type == _BCM_NH_UPDATE_KEY_L3_IIF)) {
   6043         /*  Read VLAN_MPLS table. */
   6044         table_ent_size = BCM_L3_MEM_ENT_SIZE(unit, vlan_mem);
   6045         rv = bcm_xgs3_l3_tbl_dma(unit, vlan_mem,
   6046                                  table_ent_size, "vlan_mpls_tbl",
   6047                                  &vlan_mpls_tbl_ptr, NULL);
   6048         if (rv < 0) {
   6049             goto cleanup;
   6050         }
   6051     }
   6052     
   6053 
   6054     for (idx = 0; idx < BCM_XGS3_L3_NH_TBL_SIZE(unit); idx++) {
   6055         /* Skip unused entries. */
   6056         if (!BCM_XGS3_L3_ENT_REF_CNT
   6057                 (BCM_XGS3_L3_TBL_PTR(unit, next_hop), idx)) {
   6058             continue;
   6059         }
   6060 
   6061         /* Skip trap to CPU entry internally installed entry. */
   6062         if (BCM_XGS3_L3_L2CPU_NH_IDX(unit) == idx) {
   6063             continue;
   6064         }
   6065 
   6066         /*  Read egress next hop entry. */
   6067         egr_entry_ptr =
   6068             soc_mem_table_idx_to_pointer(unit, EGR_L3_NEXT_HOPm,
   6069                                          uint32 *, egr_tbl_ptr, idx);
   6070 
   6071         /* Get interface index. */
   6072         if (SOC_IS_TRIDENT3X(unit)) {
   6073             intf_field = L3__INTF_NUMf;
   6074         }
   6075         ifindex =  soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
   6076                                        egr_entry_ptr, intf_field);
   6077         if (key_type == _BCM_NH_UPDATE_KEY_L3_INTF) {
   6078             if (ifindex != *(bcm_if_t *)val) {
   6079                 continue;
   6080             }
   6081         } else if ((key_type == _BCM_NH_UPDATE_KEY_VLAN) ||
   6082                    (key_type == _BCM_NH_UPDATE_KEY_L3_IIF)) {
   6083             egr_intf_entry_ptr =
   6084                 soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, intf),
   6085                                              uint32 *, egr_intf_tbl_ptr,
   6086                                              ifindex);
   6087             /* coverity[forward_null : FALSE] */
   6088             vlan = soc_mem_field32_get(unit, BCM_XGS3_L3_MEM(unit, intf),
   6089                                        egr_intf_entry_ptr, fld->vlan_id);
   6090             
   6091             if (key_type == _BCM_NH_UPDATE_KEY_VLAN) {
   6092                 if (vlan != *(bcm_vlan_t *)val) {
   6093                     continue;
   6094                 }
   6095             } else if (key_type == _BCM_NH_UPDATE_KEY_L3_IIF) {
   6096                 if (BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit)) {
   6097                     vlan_mpls_entry_ptr =
   6098                         soc_mem_table_idx_to_pointer(unit, vlan_mem,
   6099                                                      uint32 *,
   6100                                                      vlan_mpls_tbl_ptr,
   6101                                                      vlan);
   6102                     /* coverity[forward_null : FALSE] */
   6103                     l3_iif = soc_mem_field32_get(unit, vlan_mem,
   6104                                                  vlan_mpls_entry_ptr,
   6105                                                  L3_IIFf);
   6106                 } else {
   6107                     l3_iif = vlan;
   6108                 }
   6109 
   6110                 if (l3_iif != *(bcm_if_t *)val) {
   6111                     continue;
   6112                 }
   6113             }
   6114         } else {
   6115             rv = BCM_E_INTERNAL;
   6116             goto cleanup;
   6117         }
   6118 
   6119         /* Calculate entry ofset. */
   6120         ing_entry_ptr =
   6121             soc_mem_table_idx_to_pointer(unit, mem, uint32 *, ing_tbl_ptr, idx);
   6122         soc_mem_field32_set(unit, mem, ing_entry_ptr, DST_REALM_IDf, nat_id);
   6123 
   6124         /* Initial ingress nh table */
   6125         initial_ing_entry_ptr = soc_mem_table_idx_to_pointer(
   6126                                     unit, initial_mem, uint32 *,
   6127                                     initial_ing_tbl_ptr, idx);
   6128         soc_mem_field32_set(unit, initial_mem, initial_ing_entry_ptr,
   6129                             DST_REALM_IDf, nat_id);
   6130     }
   6131 
   6132     /* Write the buffer back. */
   6133     rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ALL,
   6134                              soc_mem_index_min(unit, mem),
   6135                              soc_mem_index_max(unit, mem), ing_tbl_ptr);
   6136     if (SOC_FAILURE(rv)) {
   6137         goto cleanup;
   6138     }
   6139     
   6140     rv = soc_mem_write_range(unit, initial_mem, MEM_BLOCK_ALL,
   6141                              soc_mem_index_min(unit, initial_mem),
   6142                              soc_mem_index_max(unit, initial_mem),
   6143                              initial_ing_tbl_ptr);
   6144 
   6145 cleanup:
   6146     if (ing_tbl_ptr) {
   6147         soc_cm_sfree(unit, ing_tbl_ptr);
   6148     }
   6149     
   6150     if (initial_ing_tbl_ptr) {
   6151         soc_cm_sfree(unit, initial_ing_tbl_ptr);
   6152     }
   6153     
   6154     if (egr_tbl_ptr) {
   6155         soc_cm_sfree(unit, egr_tbl_ptr);
   6156     }
   6157     
   6158     if (egr_intf_tbl_ptr) {
   6159         soc_cm_sfree(unit, egr_intf_tbl_ptr);
   6160     }
   6161     
   6162     if (vlan_mpls_tbl_ptr) {
   6163         soc_cm_sfree(unit, vlan_mpls_tbl_ptr);
   6164     }    
   6165 
   6166     return rv;
   6167 }
   6168 
   6169 /*
   6170  * Function:
   6171  *      _bcm_td2_nh_nat_id_update_by_l3_intf
   6172  * Purpose:
   6173  *      Routine updates the dst realm nat id of 
   6174  *      next hop interfaces associating with the l3 egress intf.
   6175  * Parameters:
   6176  *      unit    - (IN) SOC unit number.
   6177  *      intf    - (IN) Interface index.
   6178  *      nat_id  - (IN) Nat realm id.
   6179  * Returns:
   6180  *    BCM_E_XXX
   6181  */
   6182 int
   6183 _bcm_td2_nh_nat_id_update_by_l3_intf(int unit, bcm_if_t intf, int nat_id)
   6184 {
   6185     return _bcm_td2_nh_nat_id_update(unit, _BCM_NH_UPDATE_KEY_L3_INTF,
   6186                                      (void *)&intf, nat_id);
   6187 }
   6188 
   6189 /*
   6190  * Function:
   6191  *      _bcm_td2_nh_nat_id_update_by_l3_iif
   6192  * Purpose:
   6193  *      Routine updates the dst realm nat id of 
   6194  *      next hop interfaces associating with the l3 ingress intf.
   6195  * Parameters:
   6196  *      unit    - (IN) SOC unit number.
   6197  *      l3_iif  - (IN) L3 ingress interface.
   6198  *      nat_id  - (IN) Nat realm id.
   6199  * Returns:
   6200  *    BCM_E_XXX
   6201  */
   6202 int
   6203 _bcm_td2_nh_nat_id_update_by_l3_iif(int unit, bcm_if_t l3_iif, int nat_id)
   6204 {
   6205     return _bcm_td2_nh_nat_id_update(unit, _BCM_NH_UPDATE_KEY_L3_IIF,
   6206                                      (void *)&l3_iif, nat_id);
   6207 }
   6208 
   6209 /*
   6210  * Function:
   6211  *      _bcm_td2_nh_nat_id_update_by_vlan
   6212  * Purpose:
   6213  *      Routine updates the dst realm nat id of 
   6214  *      next hop interfaces associating with the vlan.
   6215  * Parameters:
   6216  *      unit    - (IN) SOC unit number.
   6217  *      vlan    - (IN) Vlan id.
   6218  *      nat_id  - (IN) Nat realm id.
   6219  * Returns:
   6220  *    BCM_E_XXX
   6221  */
   6222 int
   6223 _bcm_td2_nh_nat_id_update_by_vlan(int unit, bcm_vlan_t vlan, int nat_id)
   6224 {
   6225     return _bcm_td2_nh_nat_id_update(unit, _BCM_NH_UPDATE_KEY_VLAN,
   6226                                      (void *)&vlan, nat_id);
   6227 }
   6228 
   6229 /* 
   6230  * Function:
   6231  *      _bcm_td2_vp_urpf_mode_set
   6232  * Purpose:
   6233  *      Set VP routing urpf mode
   6234  * Parameters:
   6235  *      unit        : (IN) Device Unit Number
   6236  * Returns:
   6237  *      BCM_E_XXX
   6238  */
   6239 int
   6240 _bcm_td2_vp_urpf_mode_set(int unit, bcm_port_t port, int arg) {
   6241 
   6242     int vp;
   6243     source_vp_entry_t svp;
   6244 
   6245     if (BCM_GPORT_IS_NIV_PORT(port)) {
   6246         vp = BCM_GPORT_NIV_PORT_ID_GET(port);
   6247         if(!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   6248             return BCM_E_NOT_FOUND;
   6249         }
   6250     } else if (BCM_GPORT_IS_EXTENDER_PORT(port)) {
   6251         vp = BCM_GPORT_EXTENDER_PORT_ID_GET(port);
   6252         if(!_bcm_vp_used_get(unit, vp, _bcmVpTypeExtender)) {
   6253             return BCM_E_NOT_FOUND;
   6254         }
   6255     } else if (BCM_GPORT_IS_VLAN_PORT(port)) {
   6256         vp = BCM_GPORT_VLAN_PORT_ID_GET(port);
   6257         if(!_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) {
   6258             return BCM_E_NOT_FOUND;
   6259         }
   6260     } else {
   6261         return BCM_E_PARAM;
   6262     }
   6263 
   6264     BCM_IF_ERROR_RETURN(READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp));
   6265     soc_SOURCE_VPm_field32_set(unit, &svp, URPF_MODEf, (arg ? 1 : 0));
   6266     BCM_IF_ERROR_RETURN(WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp));
   6267     return BCM_E_NONE;
   6268 }
   6269 
   6270 /* 
   6271  * Function:
   6272  *      _bcm_td2_vp_urpf_mode_get
   6273  * Purpose:
   6274  *      Get VP routing urpf mode
   6275  * Parameters:
   6276  *      unit        : (IN) Device Unit Number
   6277  * Returns:
   6278  *      BCM_E_XXX
   6279  */
   6280 int
   6281 _bcm_td2_vp_urpf_mode_get(int unit, bcm_port_t port, int *arg) {
   6282 
   6283     int vp;
   6284     source_vp_entry_t svp;
   6285 
   6286     if (BCM_GPORT_IS_NIV_PORT(port)) {
   6287         vp = BCM_GPORT_NIV_PORT_ID_GET(port);
   6288         if(!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   6289             return BCM_E_NOT_FOUND;
   6290         }
   6291     } else if (BCM_GPORT_IS_EXTENDER_PORT(port)) {
   6292         vp = BCM_GPORT_EXTENDER_PORT_ID_GET(port);
   6293         if(!_bcm_vp_used_get(unit, vp, _bcmVpTypeExtender)) {
   6294             return BCM_E_NOT_FOUND;
   6295         }
   6296     } else if (BCM_GPORT_IS_VLAN_PORT(port)) {
   6297         vp = BCM_GPORT_VLAN_PORT_ID_GET(port);
   6298         if(!_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) {
   6299             return BCM_E_NOT_FOUND;
   6300         }
   6301     } else {
   6302         return BCM_E_PARAM;
   6303     }
   6304 
   6305     BCM_IF_ERROR_RETURN(READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp));
   6306     *arg = soc_SOURCE_VPm_field32_get(unit, &svp, URPF_MODEf);
   6307     return BCM_E_NONE;
   6308 }
   6309 
   6310 /* 
   6311  * Function:
   6312  *      _bcm_td2_l3_iif_profile_get
   6313  * Purpose:
   6314  *      Read TD2 iif profile entry and convert to corresponding
   6315  *      legacy vlan profile flags.
   6316  * Parameters:
   6317  *      unit        : (IN) Device Unit Number
   6318  * Returns:
   6319  *      NONE
   6320  */
   6321 int
   6322 _bcm_td2_l3_intf_iif_profile_get(int unit, bcm_vlan_t vid,
   6323                                  bcm_vlan_control_vlan_t *control) {
   6324 
   6325     _bcm_l3_ingress_intf_t iif; /* Ingress interface config.*/
   6326 
   6327     if (NULL == control) {
   6328         return BCM_E_INTERNAL;
   6329     }
   6330 
   6331     /* Input parameters sanity check. */
   6332     if ((vid > soc_mem_index_max(unit, L3_IIFm)) || 
   6333         (vid < soc_mem_index_min(unit, L3_IIFm))) {
   6334         return (BCM_E_PARAM);
   6335     }
   6336 
   6337     iif.intf_id = vid;
   6338     BCM_IF_ERROR_RETURN(_bcm_tr_l3_ingress_interface_get(unit, NULL, &iif));
   6339 
   6340     control->flags |= (iif.flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP4_UCAST) ?
   6341                  BCM_VLAN_IP4_DISABLE: 0;
   6342     control->flags |= (iif.flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP6_UCAST ) ?
   6343                  BCM_VLAN_IP6_DISABLE: 0;
   6344     control->flags |= (iif.flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP4_MCAST ) ?
   6345                  BCM_VLAN_IP4_MCAST_DISABLE: 0;
   6346     control->flags |= (iif.flags & BCM_L3_INGRESS_ROUTE_DISABLE_IP6_MCAST ) ?
   6347                  BCM_VLAN_IP6_MCAST_DISABLE: 0;
   6348     control->flags |= (iif.flags & BCM_L3_INGRESS_UNKNOWN_IP4_MCAST_TOCPU ) ?
   6349                 BCM_VLAN_UNKNOWN_IP4_MCAST_TOCPU : 0;
   6350     control->flags |= (iif.flags & BCM_L3_INGRESS_UNKNOWN_IP6_MCAST_TOCPU ) ?
   6351                 BCM_VLAN_UNKNOWN_IP6_MCAST_TOCPU : 0;
   6352     control->flags |= (iif.flags & BCM_L3_INGRESS_ICMP_REDIRECT_TOCPU ) ?
   6353                  BCM_VLAN_ICMP_REDIRECT_TOCPU : 0;
   6354     control->flags |= (iif.flags & BCM_L3_INGRESS_IPMC_DO_VLAN_DISABLE) ?
   6355                       BCM_VLAN_IPMC_DO_VLAN_DISABLE : 0;
   6356     if (iif.flags & BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK) {
   6357         control->flags &= ~BCM_VLAN_L3_URPF_DEFAULT_ROUTE_CHECK_DISABLE;
   6358     }
   6359     if (iif.flags & BCM_L3_INGRESS_GLOBAL_ROUTE) {
   6360         control->flags &= ~BCM_VLAN_L3_VRF_GLOBAL_DISABLE;
   6361     }
   6362 
   6363     return (BCM_E_NONE);
   6364 }
   6365 
   6366 /* 
   6367  * Function:
   6368  *      _bcm_td2_l3_iif_profile_update
   6369  * Purpose:
   6370  *      Update TD2 iif profile based on vlan intf flags
   6371  * Parameters:
   6372  *      unit        : (IN) Device Unit Number
   6373  * Returns:
   6374  *      NONE
   6375  */
   6376 int
   6377 _bcm_td2_l3_intf_iif_profile_update(int unit, bcm_vlan_t vid, 
   6378                                     bcm_vlan_control_vlan_t *control) {
   6379 
   6380     _bcm_l3_ingress_intf_t iif; /* Ingress interface config.*/
   6381     int ret_val;                /* Operation return value.  */
   6382 
   6383     /* Input parameters sanity check. */
   6384     if ((vid > soc_mem_index_max(unit, L3_IIFm)) || 
   6385         (vid < soc_mem_index_min(unit, L3_IIFm))) {
   6386         return (BCM_E_PARAM);
   6387     }
   6388 
   6389     iif.intf_id = vid;
   6390     soc_mem_lock(unit, L3_IIFm);
   6391 
   6392     ret_val = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif);
   6393     if (BCM_FAILURE(ret_val)) {
   6394         soc_mem_unlock(unit, L3_IIFm);
   6395         return (ret_val);
   6396     }
   6397 
   6398     /* Set default values */
   6399     iif.flags |= BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK;
   6400     iif.flags |= BCM_L3_INGRESS_GLOBAL_ROUTE;
   6401     iif.flags &= ~BCM_L3_INGRESS_ROUTE_DISABLE_IP4_UCAST;
   6402     iif.flags &= ~BCM_L3_INGRESS_ROUTE_DISABLE_IP6_UCAST;
   6403     iif.flags &= ~BCM_L3_INGRESS_ROUTE_DISABLE_IP4_MCAST;
   6404     iif.flags &= ~BCM_L3_INGRESS_ROUTE_DISABLE_IP6_MCAST;
   6405     iif.flags &= ~BCM_L3_INGRESS_UNKNOWN_IP4_MCAST_TOCPU;
   6406     iif.flags &= ~BCM_L3_INGRESS_UNKNOWN_IP6_MCAST_TOCPU;
   6407     iif.flags &= ~BCM_L3_INGRESS_UNKNOWN_IPMC_AS_L2MC;
   6408     iif.flags &= ~BCM_L3_INGRESS_ICMP_REDIRECT_TOCPU;
   6409     iif.flags &= ~BCM_L3_INGRESS_IPMC_DO_VLAN_DISABLE;
   6410 
   6411     iif.flags |= (control->flags & BCM_VLAN_IP4_DISABLE) ?
   6412                  BCM_L3_INGRESS_ROUTE_DISABLE_IP4_UCAST : 0;
   6413     iif.flags |= (control->flags & BCM_VLAN_IP6_DISABLE) ?
   6414                  BCM_L3_INGRESS_ROUTE_DISABLE_IP6_UCAST : 0;
   6415     iif.flags |= (control->flags & BCM_VLAN_IP4_MCAST_DISABLE) ?
   6416                  BCM_L3_INGRESS_ROUTE_DISABLE_IP4_MCAST : 0;
   6417     iif.flags |= (control->flags & BCM_VLAN_IP6_MCAST_DISABLE) ?
   6418                  BCM_L3_INGRESS_ROUTE_DISABLE_IP6_MCAST : 0;
   6419     iif.flags |= (control->flags & BCM_VLAN_UNKNOWN_IP4_MCAST_TOCPU) ?
   6420                  BCM_L3_INGRESS_UNKNOWN_IP4_MCAST_TOCPU : 0;
   6421     iif.flags |= (control->flags & BCM_VLAN_UNKNOWN_IP6_MCAST_TOCPU) ?
   6422                  BCM_L3_INGRESS_UNKNOWN_IP6_MCAST_TOCPU : 0;
   6423     iif.flags |= (control->flags & BCM_VLAN_ICMP_REDIRECT_TOCPU) ?
   6424                  BCM_L3_INGRESS_ICMP_REDIRECT_TOCPU : 0;
   6425     iif.flags |= (control->flags & BCM_VLAN_IPMC_DO_VLAN_DISABLE) ?
   6426                  BCM_L3_INGRESS_IPMC_DO_VLAN_DISABLE : 0;
   6427 
   6428     if (control->flags & BCM_VLAN_L3_URPF_DEFAULT_ROUTE_CHECK_DISABLE) {
   6429         iif.flags &= ~BCM_L3_INGRESS_URPF_DEFAULT_ROUTE_CHECK;
   6430     }
   6431     if (control->flags & BCM_VLAN_L3_VRF_GLOBAL_DISABLE) {
   6432         iif.flags &= ~BCM_L3_INGRESS_GLOBAL_ROUTE;
   6433     }
   6434 
   6435     ret_val = _bcm_tr_l3_ingress_interface_set(unit, &iif, NULL, NULL);
   6436 
   6437     soc_mem_unlock(unit, L3_IIFm);
   6438 
   6439     return (ret_val);
   6440 }
   6441 
   6442 /*
   6443  * Function:
   6444  *      _bcm_td2_l3_iif_ip4_options_profile_index_set
   6445  * Purpose:
   6446  *      Set the IP_OPTION_PROFILE_INDEX of the table L3_IIF.
   6447  * Parameters:
   6448  *      unit       - (IN) unit number
   6449  *      intf_info  - (IN/OUT) information of the l3 ingress interface
   6450  * Returns:
   6451  *      BCM_E_XXX
   6452  */
   6453 int
   6454 _bcm_td2_l3_iif_ip4_options_profile_index_set(int unit,
   6455                                               _bcm_l3_intf_cfg_t *intf_info)
   6456 {
   6457     _bcm_l3_ingress_intf_t iif; /* Ingress interface config. */
   6458     int                    rv = BCM_E_NONE;
   6459     uint32                 buf[SOC_MAX_MEM_FIELD_WORDS];
   6460     bcm_vlan_t             vid;
   6461     soc_mem_t              vlan_attrs_mem = VLAN_MPLSm;
   6462 
   6463 #ifdef BCM_TRIDENT3_SUPPORT
   6464     if (SOC_IS_TRIDENT3X(unit)) {
   6465         vlan_attrs_mem = VLAN_TABm;
   6466     }
   6467 #endif
   6468 
   6469     if (!soc_feature(unit, soc_feature_l3_ip4_options_profile)) {
   6470         return BCM_E_UNAVAIL;
   6471     }
   6472 
   6473     sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t));
   6474     iif.intf_id = intf_info->l3i_vid;
   6475 
   6476     if (BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit)) {
   6477         if (SOC_MEM_FIELD_VALID(unit, vlan_attrs_mem, L3_IIFf)) {
   6478             sal_memset (buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
   6479             vid = intf_info->l3i_vid;
   6480             SOC_IF_ERROR_RETURN(
   6481                 soc_mem_read(unit, VLAN_TABm, MEM_BLOCK_ANY, vid, buf));
   6482 
   6483             if (!soc_mem_field32_get(unit, VLAN_TABm, buf, VALIDf)) {
   6484                 return BCM_E_NONE;
   6485             }
   6486 
   6487             sal_memset (buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
   6488             BCM_IF_ERROR_RETURN(
   6489                 soc_mem_read(unit, vlan_attrs_mem, MEM_BLOCK_ANY, vid, buf));
   6490             iif.intf_id = soc_mem_field32_get(unit, vlan_attrs_mem,
   6491                                               buf, L3_IIFf);
   6492         }
   6493     }
   6494 
   6495     soc_mem_lock(unit, L3_IIFm);
   6496 
   6497     rv = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif);
   6498     if (BCM_FAILURE(rv)) {
   6499         soc_mem_unlock(unit, L3_IIFm);
   6500         return rv;
   6501     }
   6502 
   6503     iif.profile_flags |= _BCM_L3_IIF_PROFILE_DO_NOT_UPDATE;
   6504     iif.ip4_options_profile_id = intf_info->l3i_ip4_options_profile_id;
   6505     rv = _bcm_tr_l3_ingress_interface_set(unit, &iif, NULL, NULL);
   6506 
   6507     soc_mem_unlock(unit, L3_IIFm);
   6508     return rv;
   6509 }
   6510 
   6511 /*
   6512  * Function:
   6513  *      _bcm_td2_l3_iif_ip4_options_profile_index_get
   6514  * Purpose:
   6515  *      Get the IP_OPTION_PROFILE_INDEX of the table L3_IIF.
   6516  * Parameters:
   6517  *      unit      - (IN) unit number
   6518  *      intf_info - (IN/OUT) information of the l3 ingress interface
   6519  * Returns:
   6520  *      BCM_E_XXX
   6521  */
   6522 int
   6523 _bcm_td2_l3_iif_ip4_options_profile_index_get(int unit,
   6524                                               _bcm_l3_intf_cfg_t *intf_info)
   6525 {
   6526     _bcm_l3_ingress_intf_t iif; /* Ingress interface config. */
   6527     int                    rv = BCM_E_NONE;
   6528     vlan_tab_entry_t       vt;
   6529     vlan_mpls_entry_t      vlan_mpls;
   6530     bcm_vlan_t             vid;
   6531 
   6532     if (!soc_feature(unit, soc_feature_l3_ip4_options_profile)) {
   6533         return BCM_E_UNAVAIL;
   6534     }
   6535 
   6536     sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t));
   6537     iif.intf_id = intf_info->l3i_vid;
   6538 
   6539     if (BCM_XGS3_L3_INGRESS_INTF_MAP_MODE_ISSET(unit)) {
   6540         if (SOC_MEM_FIELD_VALID(unit, VLAN_MPLSm, L3_IIFf)) {
   6541             vid = intf_info->l3i_vid;
   6542             SOC_IF_ERROR_RETURN(
   6543                 soc_mem_read(unit, VLAN_TABm, MEM_BLOCK_ANY, vid, &vt));
   6544 
   6545             if (!soc_mem_field32_get(unit, VLAN_TABm, &vt, VALIDf)) {
   6546                 return BCM_E_NONE;
   6547             }
   6548 
   6549             sal_memset(&vlan_mpls, 0, sizeof(vlan_mpls));
   6550             BCM_IF_ERROR_RETURN(
   6551                 soc_mem_read(unit, VLAN_MPLSm, MEM_BLOCK_ANY, vid, &vlan_mpls));
   6552             iif.intf_id = soc_mem_field32_get(unit, VLAN_MPLSm,
   6553                                               &vlan_mpls, L3_IIFf);
   6554         }
   6555     }
   6556 
   6557     rv = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif);
   6558     intf_info->l3i_ip4_options_profile_id = iif.ip4_options_profile_id;
   6559 
   6560     return rv;
   6561 }
   6562 
   6563 #ifdef BCM_WARM_BOOT_SUPPORT_SW_DUMP
   6564 /* 
   6565  * Function:
   6566  *      _bcm_td2_l3_ip4_options_profile_sw_dump
   6567  * Purpose:
   6568  *      Displays IP oprion profile software state info
   6569  * Parameters:
   6570  *      unit        : (IN) Device Unit Number
   6571  * Returns:
   6572  *      NONE
   6573  */
   6574 void
   6575 _bcm_td2_l3_ip4_options_profile_sw_dump(int unit)
   6576 {
   6577     int i;
   6578 
   6579     if (!L3_INFO(unit)->l3_initialized) {
   6580         LOG_CLI((BSL_META_U(unit,
   6581                             "ERROR: L3  module not initialized on Unit:%d \n"), unit));
   6582         return;
   6583     }
   6584 
   6585     LOG_CLI((BSL_META_U(unit,
   6586                         "L3 IP Option: IP_OPTION_CONTROL_PROFILE_TABLEm info \n")));
   6587     for (i = 0; i < _BCM_IP4_OPTIONS_LEN; i++) {
   6588         if (_BCM_IP4_OPTIONS_USED_GET(unit, i)) {
   6589             LOG_CLI((BSL_META_U(unit,
   6590                                 "    Profile id:%4d    HW index:%4d\n"), i, 
   6591                      L3_INFO(unit)->ip4_profiles_hw_idx[i]));
   6592         }
   6593     }
   6594 
   6595 }
   6596 #endif /* BCM_WARM_BOOT_SUPPORT_SW_DUMP */
   6597 
   6598 #ifdef BCM_WARM_BOOT_SUPPORT
   6599 
   6600 
   6601 /* SCACHE size for WB */
   6602 int 
   6603 _bcm_td2_l3_ip4_options_profile_scache_len_get(int unit, int *wb_alloc_size)
   6604 {
   6605     if (wb_alloc_size == NULL) {
   6606         return BCM_E_PARAM;
   6607     }
   6608     *wb_alloc_size = sizeof(uint32) * _BCM_IP4_OPTIONS_LEN;
   6609 
   6610     return BCM_E_NONE;
   6611 }
   6612 
   6613 /* 
   6614  * Function:
   6615  *      _bcm_td2_l3_ip4_options_profile_reinit_hw_profiles_update
   6616  * Purpose:
   6617  *      Updates the shared memory profile tables reference counts
   6618  * Parameters:
   6619  *      unit    : (IN) Device Unit Number
   6620  * Returns:
   6621  *      BCM_E_XXX
   6622  */
   6623 STATIC int
   6624 _bcm_td2_l3_ip4_options_profile_reinit_hw_profiles_update (int unit)
   6625 {
   6626     int     i;
   6627     for (i=0; i < _BCM_IP4_OPTIONS_LEN; i++) {
   6628         if (_BCM_IP4_OPTIONS_USED_GET(unit, i)) {
   6629             BCM_IF_ERROR_RETURN(_bcm_l3_ip4_options_profile_entry_reference(unit, 
   6630                               ((L3_INFO(unit)->ip4_profiles_hw_idx[i]) * 
   6631                                _BCM_IP_OPTION_PROFILE_CHUNK), 
   6632                                _BCM_IP_OPTION_PROFILE_CHUNK));
   6633         }
   6634     }
   6635     return BCM_E_NONE;
   6636 }
   6637 
   6638 
   6639 
   6640 /* 
   6641  * Function:
   6642  *      _bcm_td2_l3_ip4_options_recover
   6643  * Purpose:
   6644  *      Recover IP Option Profile usage
   6645  * Parameters:
   6646  *      unit    : (IN) Device Unit Number
   6647  *      scache_ptr - (IN) Scache pointer
   6648  *                   (OUT) Updated Scache pointer
   6649  * Returns:
   6650  *      BCM_E_XXX
   6651  */
   6652 int
   6653 _bcm_td2_l3_ip4_options_recover(int unit, uint8 **scache_ptr)
   6654 {
   6655     uint32 hw_idx;
   6656     int    idx;
   6657     int    rv = BCM_E_NONE;
   6658     int    stable_size = 0;
   6659 
   6660     if ((scache_ptr == NULL) || (*scache_ptr == NULL)) {
   6661         return BCM_E_PARAM;
   6662     }
   6663 
   6664     if (SOC_WARM_BOOT(unit)) {
   6665         SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
   6666 
   6667         if (stable_size == 0) { /* level 1 */
   6668             /* Nothing to recover */
   6669         } else {  /* Level 2 */
   6670             /* recover from scache into book-keeping structs */
   6671             for (idx = 0; idx < _BCM_IP4_OPTIONS_LEN; idx++) {
   6672                 sal_memcpy(&hw_idx, (*scache_ptr), sizeof(uint32));
   6673                 (*scache_ptr) += sizeof(hw_idx);
   6674                 if (hw_idx != _BCM_IP_OPTION_REINIT_INVALID_HW_IDX) {
   6675                     _BCM_IP4_OPTIONS_USED_SET(unit, idx);
   6676                     L3_INFO(unit)->ip4_profiles_hw_idx[idx] = hw_idx;
   6677                 }
   6678             }
   6679             rv = _bcm_td2_l3_ip4_options_profile_reinit_hw_profiles_update(unit);
   6680         }
   6681     }
   6682     return rv;
   6683 }
   6684 
   6685 /* 
   6686  * Function:
   6687  *      _bcm_td2_l3_ip4_options_sync
   6688  * Purpose:
   6689  *      Store IP Option Profile usage table into scache.
   6690  * Parameters:
   6691  *      unit    : (IN) Device Unit Number
   6692  *      scache_ptr - (IN) Scache pointer
   6693  *                   (OUT) Updated Scache pointer
   6694  * Returns:
   6695  *      BCM_E_XXX
   6696  */
   6697 int
   6698 _bcm_td2_l3_ip4_options_sync(int unit, uint8 **scache_ptr)
   6699 {
   6700     uint32 hw_idx;
   6701     int    idx;
   6702    
   6703     if ((scache_ptr == NULL) || (*scache_ptr == NULL)) {
   6704         return BCM_E_PARAM;
   6705     }
   6706 
   6707     /* now store the state into the compressed format */
   6708     for (idx = 0; idx < _BCM_IP4_OPTIONS_LEN; idx++) {
   6709         if (_BCM_IP4_OPTIONS_USED_GET(unit, idx)) {
   6710             hw_idx = L3_INFO(unit)->ip4_profiles_hw_idx[idx];
   6711         } else {
   6712             hw_idx = _BCM_IP_OPTION_REINIT_INVALID_HW_IDX;
   6713         }
   6714         sal_memcpy((*scache_ptr), &hw_idx, sizeof(uint32));
   6715         (*scache_ptr) += sizeof(hw_idx);
   6716     }
   6717     return BCM_E_NONE;
   6718 }
   6719 #endif /* BCM_WARM_BOOT_SUPPORT */
   6720 
   6721 #ifdef ALPM_ENABLE
   6722 /* ALPM Functions */
   6723 
   6724 
   6725 /*
   6726  * Function:
   6727  *      _bcm_td2_alpm_lpm_vrf_init
   6728  * Purpose:
   6729  *      Service routine used to translate API vrf id to hw specific.
   6730  * Parameters:
   6731  *      unit      - (IN)SOC unit number.
   6732  *      lpm_cfg   - (IN)Prefix info.
   6733  *      vrf_id    - (OUT)Internal vrf id.
   6734  *      vrf_mask  - (OUT)Internal vrf mask.
   6735  * Returns:
   6736  *      BCM_E_XXX
   6737  */
   6738 STATIC int
   6739 _bcm_td2_alpm_lpm_vrf_init(int unit, _bcm_defip_cfg_t *lpm_cfg,
   6740                            int *vrf_id, int *vrf_mask)
   6741 {
   6742     /* Handle special vrf id cases. */
   6743     switch (lpm_cfg->defip_vrf) {
   6744       case BCM_L3_VRF_OVERRIDE:
   6745       case BCM_L3_VRF_GLOBAL: /* only for td2 */
   6746           *vrf_id = 0;
   6747           *vrf_mask = 0;
   6748           break;
   6749       default:
   6750           *vrf_id = lpm_cfg->defip_vrf;
   6751           *vrf_mask = SOC_VRF_MAX(unit);
   6752           break;
   6753     }
   6754 
   6755     /* In any case vrf id shouldn't exceed max field mask. */
   6756     if ((*vrf_id < 0) || (*vrf_id > SOC_VRF_MAX(unit))) {
   6757         return (BCM_E_PARAM);
   6758     }
   6759     return (BCM_E_NONE);
   6760 }
   6761 
   6762 
   6763 /*
   6764  * Function:	
   6765  *     _bcm_td2_alpm_mem_ip6_defip_set
   6766  * Purpose:
   6767  *    Set IP6 address mask field in L3_DEFIPm from defip_cfg
   6768  * Parameters: 
   6769  *    unit    - (IN) SOC unit number; 
   6770  *    lpm_key - (OUT) Buffer to fill. 
   6771  *    lpm_cfg - (IN) Route information. 
   6772  *    alpm_entry - (OUT) ALPM entry to fill
   6773  * Note:
   6774  *    See soc_mem_ip6_addr_set()
   6775  */
   6776 STATIC void
   6777 _bcm_td2_alpm_lpm64_key_init(int unit, _bcm_defip_cfg_t *lpm_cfg,
   6778                              defip_entry_t *lpm_key)
   6779 {
   6780     bcm_ip6_t mask;                      /* Subnet mask.        */
   6781     uint8 *ip6;                 /* Ip6 address.       */
   6782     uint32 ip6_word[2];         /* Temp storage.      */
   6783     int idx;                    /* Iteration index .  */
   6784 
   6785     /* Just to keep variable name short. */
   6786     ip6 = lpm_cfg->defip_ip6_addr;
   6787 
   6788     /* Create mask from prefix length. */
   6789     bcm_ip6_mask_create(mask, lpm_cfg->defip_sub_len);
   6790 
   6791     /* Apply subnet mask */
   6792     idx = lpm_cfg->defip_sub_len / 8;   /* Unchanged byte count.    */
   6793     ip6[idx] &= mask[idx];      /* Apply mask on next byte. */
   6794     for (idx++; idx < BCM_IP6_ADDRLEN; idx++) {
   6795         ip6[idx] = 0;           /* Reset rest of bytes.     */
   6796     }
   6797 
   6798     ip6_word[1] = ((ip6[0] << 24) | (ip6[1] << 16) | (ip6[2] << 8) | (ip6[3]));
   6799     ip6_word[0]= ((ip6[4] << 24) | (ip6[5] << 16) | (ip6[6] << 8) | (ip6[7]));
   6800 
   6801     /* Set IP Addr */
   6802     soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR1f, (void *)&ip6_word[1]);
   6803     soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR0f, (void *)&ip6_word[0]);
   6804 
   6805     /* Set IP MASK */
   6806     ip6_word[0] = ((mask[0] << 24) | (mask[1] << 16) | (mask[2] << 8) | (mask[3]));
   6807     soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_MASK1f, (void *)&ip6_word[0]);
   6808 
   6809     ip6_word[0] = ((mask[4] << 24) | (mask[5] << 16) | (mask[6] << 8) | (mask[7]));
   6810     soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_MASK0f, (void *)&ip6_word[0]);
   6811 }
   6812 
   6813 
   6814 /*
   6815  * Function:
   6816  *      _bcm_td2_alpm_lpm_ent_init
   6817  * Purpose:
   6818  *      Service routine used to initialize lkup key for lpm entry.
   6819  *      Also initializes the ALPM SRAM entry.
   6820  * Parameters:
   6821  *      unit      - (IN)SOC unit number.
   6822  *      lpm_cfg   - (IN)Prefix info.
   6823  *      lpm_entry - (OUT)Hw buffer to fill.
   6824  * Returns:
   6825  *      BCM_E_XXX
   6826  */
   6827 STATIC int
   6828 _bcm_td2_alpm_lpm_ent_init(int unit, _bcm_defip_cfg_t *lpm_cfg,
   6829                            defip_entry_t *lpm_entry, int nh_ecmp_idx, uint32 *flags)
   6830 {
   6831     bcm_ip_t ip4_mask;
   6832     int vrf_id;
   6833     int vrf_mask;
   6834     int ipv6;
   6835 
   6836     ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6;
   6837 
   6838     /* Extract entry  vrf id  & vrf mask. */
   6839     BCM_IF_ERROR_RETURN
   6840         (_bcm_td2_alpm_lpm_vrf_init(unit, lpm_cfg, &vrf_id, &vrf_mask));
   6841 
   6842 
   6843     /* Zero buffers. */
   6844     sal_memset(lpm_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, defip));
   6845 
   6846     /* Set hit bit. */
   6847     if (lpm_cfg->defip_flags & BCM_L3_HIT) {
   6848         soc_L3_DEFIPm_field32_set(unit, lpm_entry, HIT0f, 1);
   6849     }
   6850 
   6851     /* Set priority override bit. */
   6852     if (lpm_cfg->defip_flags & BCM_L3_RPE) {
   6853         soc_L3_DEFIPm_field32_set(unit, lpm_entry, RPE0f, 1);
   6854     }
   6855 
   6856     /* Write priority field. */
   6857     soc_L3_DEFIPm_field32_set(unit, lpm_entry, PRI0f, lpm_cfg->defip_prio);
   6858 
   6859     /* Fill next hop information. */
   6860     if (soc_feature(unit, soc_feature_generic_dest)) {
   6861         uint32 dest_type = SOC_MEM_FIF_DEST_NEXTHOP;
   6862         uint32 dest_val  = 0;
   6863         if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) {
   6864             dest_type = SOC_MEM_FIF_DEST_ECMP;
   6865             dest_val  = nh_ecmp_idx;
   6866         } else if (!(lpm_cfg->defip_flags & BCM_L3_IPMC)) {
   6867             dest_type = SOC_MEM_FIF_DEST_NEXTHOP;
   6868             dest_val  = nh_ecmp_idx;
   6869         } else {
   6870             dest_type = SOC_MEM_FIF_DEST_INVALID;
   6871         }
   6872 
   6873         if (dest_type != SOC_MEM_FIF_DEST_INVALID) {
   6874             soc_mem_field32_dest_set(unit, L3_DEFIPm, lpm_entry, DESTINATION0f,
   6875                                      dest_type, dest_val);
   6876         }
   6877     } else {
   6878         if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) {
   6879             soc_L3_DEFIPm_field32_set(unit, lpm_entry, ECMP0f, 1);
   6880             soc_L3_DEFIPm_field32_set(unit, lpm_entry, NEXT_HOP_INDEX0f,
   6881                                       nh_ecmp_idx);
   6882         } else if (!(lpm_cfg->defip_flags & BCM_L3_IPMC)) {
   6883             soc_L3_DEFIPm_field32_set(unit, lpm_entry, NEXT_HOP_INDEX0f,
   6884                                         nh_ecmp_idx);
   6885         }
   6886     }
   6887 
   6888     /* Set destination discard flag. */
   6889     if (lpm_cfg->defip_flags & BCM_L3_DST_DISCARD) {
   6890         soc_L3_DEFIPm_field32_set(unit, lpm_entry, DST_DISCARD0f, 1);
   6891     }
   6892 
   6893     /* remember src discard flag */
   6894     if (lpm_cfg->defip_flags & BCM_L3_SRC_DISCARD) {
   6895         *flags |= SOC_ALPM_RPF_SRC_DISCARD;
   6896     }
   6897 
   6898     if (soc_feature(unit, soc_feature_alpm_flex_stat)) {
   6899         *flags |= SOC_ALPM_STAT_FLEX;
   6900         soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, ENTRY_VIEW0f, 0x1);
   6901     }
   6902 
   6903     /* Set classification group id. */
   6904     soc_L3_DEFIPm_field32_set(unit, lpm_entry, CLASS_ID0f, 
   6905                               lpm_cfg->defip_lookup_class);
   6906 
   6907     /* Set Global route flag. */
   6908     if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) {
   6909         soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, GLOBAL_ROUTE0f, 0x1);
   6910     }
   6911 
   6912     /* Indicate this is an override entry */
   6913     if (BCM_L3_VRF_OVERRIDE == lpm_cfg->defip_vrf) {
   6914         soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, GLOBAL_HIGH0f, 0x1);
   6915         soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, GLOBAL_ROUTE0f, 0x1);
   6916     }
   6917 
   6918     /* Set VRF */
   6919     soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_0f, vrf_id);
   6920     soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_MASK0f, vrf_mask);
   6921 
   6922 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   6923     if (soc_feature(unit, soc_feature_ipmc_defip) &&
   6924             (lpm_cfg->defip_flags & BCM_L3_IPMC)) {
   6925         if (soc_mem_field_valid(unit, L3_DEFIPm, MULTICAST_ROUTE0f)) {
   6926             soc_L3_DEFIPm_field32_set(unit, lpm_entry, MULTICAST_ROUTE0f, 1);
   6927         } else if (soc_mem_field_valid(unit, L3_DEFIPm, DATA_TYPE0f)) {
   6928             soc_L3_DEFIPm_field32_set(unit, lpm_entry, DATA_TYPE0f, 2);
   6929         }
   6930 
   6931         if (soc_feature(unit, soc_feature_generic_dest)) {
   6932             if (lpm_cfg->defip_mc_group > 0) {
   6933                 soc_mem_field32_dest_set(unit, L3_DEFIPm, lpm_entry, DESTINATION0f,
   6934                     SOC_MEM_FIF_DEST_IPMC, lpm_cfg->defip_mc_group);
   6935             }
   6936         } else {
   6937             soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, L3MC_INDEX0f, lpm_cfg->defip_mc_group);
   6938         }
   6939 
   6940         /*
   6941          * RP ID needs uplift by _BCM_L3_DEFIP_RP_ID_BASE value, Now it wil fit in EXPECTED_L3_IIFf
   6942          */
   6943         if (lpm_cfg->defip_l3a_rp != BCM_IPMC_RP_ID_INVALID) {
   6944             soc_L3_DEFIPm_field32_set(unit, lpm_entry, EXPECTED_L3_IIF0f, 
   6945                                     _BCM_DEFIP_IPMC_RP_SET(lpm_cfg->defip_l3a_rp));
   6946         } else if ((lpm_cfg->defip_ipmc_flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) && 
   6947                 (lpm_cfg->defip_expected_intf != 0))  {
   6948 
   6949             soc_L3_DEFIPm_field32_set(unit, lpm_entry, EXPECTED_L3_IIF0f, lpm_cfg->defip_expected_intf);
   6950 
   6951             if (lpm_cfg->defip_ipmc_flags & BCM_IPMC_RPF_FAIL_DROP) {
   6952                 soc_L3_DEFIPm_field32_set(unit, lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_DROP0f, 1);
   6953             }
   6954             if (lpm_cfg->defip_ipmc_flags & BCM_IPMC_RPF_FAIL_TOCPU) {
   6955                 soc_L3_DEFIPm_field32_set(unit, lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPU0f, 1);
   6956             }
   6957         }
   6958     }
   6959 #endif
   6960 
   6961     if (ipv6) {
   6962         /* Set prefix ip address & mask. */
   6963         _bcm_td2_alpm_lpm64_key_init(unit, lpm_cfg,lpm_entry);
   6964 
   6965         /* Set second part valid bit. */
   6966         soc_L3_DEFIPm_field32_set(unit, lpm_entry, VALID1f, 1);
   6967 
   6968         /* Set mode to ipv6 */
   6969         soc_L3_DEFIPm_field32_set(unit, lpm_entry, MODE0_f(unit), 1);
   6970         soc_L3_DEFIPm_field32_set(unit, lpm_entry, MODE1_f(unit), 1);
   6971 
   6972         /* Set Virtual Router id */
   6973         soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_1f, vrf_id);
   6974         soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_MASK1f, vrf_mask);
   6975     } else {
   6976         ip4_mask = BCM_IP4_MASKLEN_TO_ADDR(lpm_cfg->defip_sub_len);
   6977         /* Apply subnet mask. */
   6978         lpm_cfg->defip_ip_addr &= ip4_mask;
   6979 
   6980         /* Set address to the buffer. */
   6981         soc_L3_DEFIPm_field32_set(unit, lpm_entry, IP_ADDR0f,
   6982                                   lpm_cfg->defip_ip_addr);
   6983         soc_L3_DEFIPm_field32_set(unit, lpm_entry, IP_ADDR_MASK0f, ip4_mask);
   6984     }
   6985     soc_L3_DEFIPm_field32_set(unit, lpm_entry, VALID0f, 1);
   6986 
   6987     /* Set Mode Masks */
   6988     soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, MODE_MASK0_f(unit),
   6989                         (1 << soc_mem_field_length(unit, L3_DEFIPm, MODE_MASK0_f(unit))) - 1);
   6990     soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, MODE_MASK1_f(unit),
   6991                         (1 << soc_mem_field_length(unit, L3_DEFIPm, MODE_MASK1_f(unit))) - 1);
   6992 
   6993     /* Set Entry Type Masks */
   6994     soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, ENTRY_TYPE0_f(unit),
   6995                         (1 << soc_mem_field_length(unit, L3_DEFIPm, ENTRY_TYPE0_f(unit))) - 1);
   6996     soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, ENTRY_TYPE1_f(unit),
   6997                         (1 << soc_mem_field_length(unit, L3_DEFIPm, ENTRY_TYPE1_f(unit))) - 1);
   6998     /*
   6999      * Note ipv4 entries are expected to reside in part 0 of the entry.
   7000      */
   7001 
   7002     /* apply for ALPM and Global high */
   7003     /* Base counter index. */
   7004     soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, FLEX_CTR_BASE_COUNTER_IDX0f,
   7005                         lpm_cfg->defip_flex_ctr_base_id);
   7006     /* Counter offset mode. */
   7007     soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, FLEX_CTR_OFFSET_MODE0f,
   7008                         lpm_cfg->defip_flex_ctr_mode);
   7009     /* Counter pool number. */
   7010     soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, FLEX_CTR_POOL_NUMBER0f,
   7011                         lpm_cfg->defip_flex_ctr_pool);
   7012     return (BCM_E_NONE);
   7013 }
   7014 
   7015 /*
   7016  * Function:    
   7017  *     _bcm_td2_alpm_lpm128_addr_init
   7018  * Purpose:  
   7019  *     Set IP6 address field in memory from ip6 addr type. 
   7020  * Parameters: 
   7021  *     unit  - (IN) BCM device number. 
   7022  *     mem   - (IN) Memory id.
   7023  *     entry - (IN) HW entry buffer.
   7024  *     ip6   - (IN) SW ip6 address buffer.
   7025  * Returns:      void
   7026  */
   7027 STATIC void
   7028 _bcm_td2_alpm_lpm128_addr_init(int unit, soc_mem_t mem, uint32 *entry,
   7029                                const ip6_addr_t ip6)
   7030 {
   7031     uint32              ip6_field[4];
   7032     ip6_field[3] = ((ip6[12] << 24)| (ip6[13] << 16) |
   7033                     (ip6[14] << 8) | (ip6[15] << 0));
   7034     soc_mem_field_set(unit, mem, entry, IP_ADDR0_LWRf, &ip6_field[3]);
   7035     ip6_field[2] = ((ip6[8] << 24) | (ip6[9] << 16) |
   7036                     (ip6[10] << 8) | (ip6[11] << 0));
   7037     soc_mem_field_set(unit, mem, entry, IP_ADDR1_LWRf, &ip6_field[2]);
   7038     ip6_field[1] = ((ip6[4] << 24) | (ip6[5] << 16) |
   7039                     (ip6[6] << 8)  | (ip6[7] << 0));
   7040     soc_mem_field_set(unit, mem, entry, IP_ADDR0_UPRf, &ip6_field[1]);
   7041     ip6_field[0] = ((ip6[0] << 24) | (ip6[1] << 16) |
   7042                     (ip6[2] << 8)  | (ip6[3] << 0));
   7043     soc_mem_field_set(unit, mem, entry, IP_ADDR1_UPRf, ip6_field);
   7044 }
   7045 
   7046 /*
   7047  * Function:    
   7048  *     _bcm_td2_alpm_lpm128_mask_init
   7049  * Purpose:  
   7050  *     Set IP6 mask field in memory from ip6 addr type. 
   7051  * Parameters: 
   7052  *     unit  - (IN) BCM device number. 
   7053  *     mem   - (IN) Memory id.
   7054  *     entry - (IN) HW entry buffer.
   7055  *     ip6   - (IN) SW ip6 address buffer.
   7056  * Returns:      void
   7057  */
   7058 STATIC void
   7059 _bcm_td2_alpm_lpm128_mask_init(int unit, soc_mem_t mem, uint32 *entry,
   7060                                const ip6_addr_t ip6)
   7061 {
   7062     uint32              ip6_field[4];
   7063     ip6_field[3] = ((ip6[12] << 24)| (ip6[13] << 16) |
   7064                     (ip6[14] << 8) | (ip6[15] << 0));
   7065     soc_mem_field_set(unit, mem, entry, IP_ADDR_MASK0_LWRf, &ip6_field[3]);
   7066     ip6_field[2] = ((ip6[8] << 24) | (ip6[9] << 16) |
   7067                     (ip6[10] << 8) | (ip6[11] << 0));
   7068     soc_mem_field_set(unit, mem, entry, IP_ADDR_MASK1_LWRf, &ip6_field[2]);
   7069     ip6_field[1] = ((ip6[4] << 24) | (ip6[5] << 16) |
   7070                     (ip6[6] << 8)  | (ip6[7] << 0));
   7071     soc_mem_field_set(unit, mem, entry, IP_ADDR_MASK0_UPRf, &ip6_field[1]);
   7072     ip6_field[0] = ((ip6[0] << 24) | (ip6[1] << 16) |
   7073                     (ip6[2] << 8)  | (ip6[3] << 0));
   7074     soc_mem_field_set(unit, mem, entry, IP_ADDR_MASK1_UPRf, ip6_field);
   7075 }
   7076 
   7077 STATIC int
   7078 _bcm_td2_alpm_lpm128_init(int unit, _bcm_defip_cfg_t *lpm_cfg,
   7079              defip_pair_128_entry_t *lpm_entry, int nh_ecmp_idx, uint32 *flags)
   7080 {
   7081     int vrf_id;
   7082     int vrf_mask;
   7083     bcm_ip6_t mask;                          /* Subnet mask.              */
   7084 
   7085     /* Extract entry  vrf id  & vrf mask. */
   7086     BCM_IF_ERROR_RETURN
   7087         (_bcm_td2_alpm_lpm_vrf_init(unit, lpm_cfg, &vrf_id, &vrf_mask));
   7088 
   7089     /* Zero buffers. */
   7090     sal_memset(lpm_entry, 0, sizeof(*lpm_entry));
   7091 
   7092     /* Set hit bit. */
   7093     if (lpm_cfg->defip_flags & BCM_L3_HIT) {
   7094         soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, HITf, 1);
   7095     }
   7096 
   7097     /* Set priority override bit. */
   7098     if (lpm_cfg->defip_flags & BCM_L3_RPE) {
   7099         soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, RPEf, 1);
   7100     }
   7101 
   7102     /* Write priority field. */
   7103     soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, PRIf, lpm_cfg->defip_prio);
   7104 
   7105     /* Fill next hop information. */
   7106     if (soc_feature(unit, soc_feature_generic_dest)) {
   7107         uint32 dest_type = SOC_MEM_FIF_DEST_NEXTHOP;
   7108         uint32 dest_val  = 0;
   7109         if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) {
   7110             dest_type = SOC_MEM_FIF_DEST_ECMP;
   7111             dest_val  = nh_ecmp_idx;
   7112         } else if (!(lpm_cfg->defip_flags & BCM_L3_IPMC)) {
   7113             dest_type = SOC_MEM_FIF_DEST_NEXTHOP;
   7114             dest_val  = nh_ecmp_idx;
   7115         } else {
   7116             dest_type = SOC_MEM_FIF_DEST_INVALID;
   7117         }
   7118 
   7119         if (dest_type != SOC_MEM_FIF_DEST_INVALID) {
   7120             soc_mem_field32_dest_set(unit, L3_DEFIP_PAIR_128m, lpm_entry,
   7121                                      DESTINATIONf, dest_type, dest_val);
   7122         }
   7123     } else {
   7124         if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) {
   7125             soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, ECMPf, 1);
   7126             soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, NEXT_HOP_INDEXf,
   7127                                       nh_ecmp_idx);
   7128         } else if (!(lpm_cfg->defip_flags & BCM_L3_IPMC)) {
   7129             soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, NEXT_HOP_INDEXf,
   7130                                                 nh_ecmp_idx);
   7131         }
   7132     }
   7133 
   7134     /* Set destination discard flag. */
   7135     if (lpm_cfg->defip_flags & BCM_L3_DST_DISCARD) {
   7136         soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, DST_DISCARDf, 1);
   7137     }
   7138 
   7139     /* remember src discard flag */
   7140     if (lpm_cfg->defip_flags & BCM_L3_SRC_DISCARD) {
   7141         *flags |= SOC_ALPM_RPF_SRC_DISCARD;
   7142     }
   7143 
   7144     if (soc_feature(unit, soc_feature_alpm_flex_stat)) {
   7145         *flags |= SOC_ALPM_STAT_FLEX;
   7146         soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, ENTRY_VIEWf, 0x1);
   7147     }
   7148 
   7149     /* Set classification group id. */
   7150     soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, CLASS_IDf, 
   7151                               lpm_cfg->defip_lookup_class);
   7152 
   7153     /* Set Global route flag. */
   7154     if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) {
   7155         soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, GLOBAL_ROUTEf, 0x1);
   7156     }
   7157 
   7158     /* Indicate this is an override entry */
   7159     if (BCM_L3_VRF_OVERRIDE == lpm_cfg->defip_vrf) {
   7160         soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, GLOBAL_HIGHf, 0x1);
   7161         soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, GLOBAL_ROUTEf, 0x1);
   7162     }
   7163 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   7164     if (soc_feature(unit, soc_feature_ipmc_defip) &&
   7165             (lpm_cfg->defip_flags & BCM_L3_IPMC)) {
   7166         if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, MULTICAST_ROUTEf)) {
   7167             soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, MULTICAST_ROUTEf, 1);
   7168         } else if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, DATA_TYPEf)) {
   7169             soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, DATA_TYPEf, 2);
   7170         }
   7171 
   7172         if (soc_feature(unit, soc_feature_generic_dest)) {
   7173             if (lpm_cfg->defip_mc_group > 0) {
   7174                 soc_mem_field32_dest_set(unit, L3_DEFIP_PAIR_128m, lpm_entry,
   7175                                          DESTINATIONf, SOC_MEM_FIF_DEST_IPMC,
   7176                                          lpm_cfg->defip_mc_group);
   7177             }
   7178         } else {
   7179             soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, L3MC_INDEXf, lpm_cfg->defip_mc_group);
   7180         }
   7181 
   7182         /*
   7183          * RP ID needs uplift by _BCM_L3_DEFIP_RP_ID_BASE value, Now it wil fit in EXPECTED_L3_IIFf
   7184          */
   7185         if (lpm_cfg->defip_l3a_rp != BCM_IPMC_RP_ID_INVALID) {
   7186             soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, 
   7187                                   EXPECTED_L3_IIFf, _BCM_DEFIP_IPMC_RP_SET(lpm_cfg->defip_l3a_rp));
   7188         } else if ((lpm_cfg->defip_ipmc_flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) &&
   7189                 (lpm_cfg->defip_expected_intf != 0))  {
   7190 
   7191             soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, EXPECTED_L3_IIFf, lpm_cfg->defip_expected_intf);
   7192 
   7193             if (lpm_cfg->defip_ipmc_flags & BCM_IPMC_RPF_FAIL_DROP) {
   7194                 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_DROPf, 1);
   7195             }
   7196             if (lpm_cfg->defip_ipmc_flags & BCM_IPMC_RPF_FAIL_TOCPU) {
   7197                 soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPUf, 1);
   7198             }
   7199         }
   7200     }
   7201 #endif
   7202 
   7203     /* Create mask from prefix length. */
   7204     bcm_ip6_mask_create(mask, lpm_cfg->defip_sub_len);
   7205 
   7206     /* Apply mask on address. */
   7207     bcm_xgs3_l3_mask6_apply(mask, lpm_cfg->defip_ip6_addr);
   7208 
   7209     /* Set prefix ip address & mask. */
   7210     _bcm_td2_alpm_lpm128_addr_init(unit, L3_DEFIP_PAIR_128m,
   7211                                 (uint32 *) lpm_entry, lpm_cfg->defip_ip6_addr);
   7212 
   7213     _bcm_td2_alpm_lpm128_mask_init(unit, L3_DEFIP_PAIR_128m,
   7214                                    (uint32 *) lpm_entry, mask);
   7215 
   7216     /* Set Virtual Router id */
   7217     soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_0_LWRf, vrf_id);
   7218     soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_1_LWRf, vrf_id);
   7219     soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_0_UPRf, vrf_id);
   7220     soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_1_UPRf, vrf_id);
   7221 
   7222     soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_MASK0_LWRf, 
   7223                                        vrf_mask);
   7224     soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_MASK1_LWRf, 
   7225                                        vrf_mask);
   7226     soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_MASK0_UPRf, 
   7227                                        vrf_mask);
   7228     soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VRF_ID_MASK1_UPRf, 
   7229                                        vrf_mask);
   7230 
   7231     soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VALID0_LWRf, 1);
   7232     soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VALID1_LWRf, 1);
   7233     soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VALID0_UPRf, 1);
   7234     soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, VALID1_UPRf, 1);
   7235 
   7236     /* Set mode to ipv6-128 */
   7237     soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, MODE0_LWR_f(unit), 3);
   7238     soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, MODE1_LWR_f(unit), 3);
   7239     soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, MODE0_UPR_f(unit), 3);
   7240     soc_L3_DEFIP_PAIR_128m_field32_set(unit, lpm_entry, MODE1_UPR_f(unit), 3);
   7241 
   7242     /* Set Mode Masks */
   7243     soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, MODE_MASK0_LWR_f(unit),
   7244     (1 << soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, MODE_MASK0_LWR_f(unit))) - 1);
   7245     soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, MODE_MASK1_LWR_f(unit),
   7246     (1 << soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, MODE_MASK1_LWR_f(unit))) - 1);
   7247     soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, MODE_MASK0_UPR_f(unit),
   7248     (1 << soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, MODE_MASK0_UPR_f(unit))) - 1);
   7249     soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, MODE_MASK1_UPR_f(unit),
   7250     (1 << soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, MODE_MASK1_UPR_f(unit))) - 1);
   7251 
   7252     /* Set Entry Type Masks */
   7253     soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, ENTRY_TYPE0_LWR_f(unit),
   7254      (1<<soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, ENTRY_TYPE0_LWR_f(unit))) - 1);
   7255     soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, ENTRY_TYPE1_LWR_f(unit),
   7256      (1<<soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, ENTRY_TYPE1_LWR_f(unit))) - 1);
   7257     soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, ENTRY_TYPE0_UPR_f(unit),
   7258      (1<<soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, ENTRY_TYPE0_UPR_f(unit))) - 1);
   7259     soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, ENTRY_TYPE1_UPR_f(unit),
   7260      (1<<soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, ENTRY_TYPE1_UPR_f(unit))) - 1);
   7261 
   7262     /* Base counter index. */
   7263     soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, FLEX_CTR_BASE_COUNTER_IDXf,
   7264                         lpm_cfg->defip_flex_ctr_base_id);
   7265     /* Counter offset mode. */
   7266     soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, FLEX_CTR_OFFSET_MODEf,
   7267                         lpm_cfg->defip_flex_ctr_mode);
   7268     /* Counter pool number. */
   7269     soc_mem_field32_set(unit, L3_DEFIP_PAIR_128m, lpm_entry, FLEX_CTR_POOL_NUMBERf,
   7270                         lpm_cfg->defip_flex_ctr_pool);
   7271     return (BCM_E_NONE);
   7272 }
   7273 
   7274 
   7275 /*
   7276  * Function:
   7277  *     _bcm_td2_alpm_lpm64_key_parse
   7278  * Purpose:
   7279  *    Set an IP6 address field in L3_DEFIPm
   7280  * Note:
   7281  *    See soc_mem_ip6_addr_set()
   7282  */
   7283 STATIC void
   7284 _bcm_td2_alpm_lpm64_key_parse(int unit, const void *lpm_key,
   7285                               _bcm_defip_cfg_t *lpm_cfg)
   7286 {
   7287     uint8 *ip6;                 /* Ip6 address.       */
   7288     uint8 mask[BCM_IP6_ADDRLEN];        /* Subnet mask.       */
   7289     uint32 ip6_word;            /* Temp storage.      */
   7290 
   7291     sal_memset(mask, 0, sizeof (bcm_ip6_t));
   7292 
   7293     /* Just to keep variable name short. */
   7294     ip6 = lpm_cfg->defip_ip6_addr;
   7295     sal_memset(ip6, 0, sizeof (bcm_ip6_t));
   7296 
   7297     soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR1f, &ip6_word);
   7298     ip6[0] = (uint8) ((ip6_word >> 24) & 0xff);
   7299     ip6[1] = (uint8) ((ip6_word >> 16) & 0xff);
   7300     ip6[2] = (uint8) ((ip6_word >> 8) & 0xff);
   7301     ip6[3] = (uint8) (ip6_word & 0xff);
   7302 
   7303     soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR0f, &ip6_word);
   7304     ip6[4] = (uint8) ((ip6_word >> 24) & 0xff);
   7305     ip6[5] = (uint8) ((ip6_word >> 16) & 0xff);
   7306     ip6[6] = (uint8) ((ip6_word >> 8) & 0xff);
   7307     ip6[7] = (uint8) (ip6_word & 0xff);
   7308 
   7309     soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_MASK1f, &ip6_word);
   7310     mask[0] = (uint8) ((ip6_word >> 24) & 0xff);
   7311     mask[1] = (uint8) ((ip6_word >> 16) & 0xff);
   7312     mask[2] = (uint8) ((ip6_word >> 8) & 0xff);
   7313     mask[3] = (uint8) (ip6_word & 0xff);
   7314 
   7315     soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_MASK0f, &ip6_word);
   7316     mask[4] = (uint8) ((ip6_word >> 24) & 0xff);
   7317     mask[5] = (uint8) ((ip6_word >> 16) & 0xff);
   7318     mask[6] = (uint8) ((ip6_word >> 8) & 0xff);
   7319     mask[7] = (uint8) (ip6_word & 0xff);
   7320 
   7321     lpm_cfg->defip_sub_len = bcm_ip6_mask_length(mask);
   7322 }
   7323 
   7324 /*
   7325  * Function:
   7326  *      _bcm_td2_alpm_lpm_key_parse
   7327  * Purpose:
   7328  *      Parse entry key from DEFIP table.
   7329  * Parameters:
   7330  *      unit        - (IN)SOC unit number.
   7331  *      lpm_cfg     - (OUT)Buffer to fill defip information. 
   7332  *      lpm_entry   - (IN) Buffer read from hw. 
   7333  * Returns:
   7334  *      void
   7335  */
   7336 STATIC void
   7337 _bcm_td2_alpm_lpm_key_parse(int unit, _bcm_defip_cfg_t *lpm_cfg,
   7338                             defip_entry_t *lpm_entry)
   7339 {
   7340     bcm_ip_t v4_mask;
   7341     int ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6;
   7342 
   7343     /* Set prefix ip address & mask. */
   7344     if (ipv6) {
   7345         _bcm_td2_alpm_lpm64_key_parse(unit, lpm_entry, lpm_cfg);
   7346     } else {
   7347         /* Get ipv4 address. */
   7348         lpm_cfg->defip_ip_addr =
   7349             soc_L3_DEFIPm_field32_get(unit, lpm_entry, IP_ADDR0f);
   7350 
   7351         /* Get subnet mask. */
   7352         v4_mask = soc_L3_DEFIPm_field32_get(unit, lpm_entry, IP_ADDR_MASK0f);
   7353 
   7354         /* Fill mask length. */
   7355         lpm_cfg->defip_sub_len = bcm_ip_mask_length(v4_mask);
   7356     }
   7357 
   7358     /* Get Virtual Router id */
   7359     soc_alpm_lpm_vrf_get(unit, lpm_entry, &lpm_cfg->defip_vrf, NULL);
   7360     return;
   7361 }
   7362 
   7363 
   7364 /*
   7365  * Function:
   7366  *      _bcm_td2_alpm_lpm_data_parse
   7367  * Purpose:
   7368  *      Parse an entry from DEFIP table.
   7369  * Parameters:
   7370  *      unit        - (IN)SOC unit number.
   7371  *      lpm_cfg     - (OUT)Buffer to fill defip information.
   7372  *      nh_ecmp_idx - (OUT)Next hop index or ecmp group id.
   7373  *      lpm_entry   - (IN) Buffer read from hw.
   7374  * Returns:
   7375  *      void
   7376  */
   7377 STATIC INLINE void
   7378 _bcm_td2_alpm_lpm_data_parse(int unit, _bcm_defip_cfg_t *lpm_cfg, int *p_nh_ecmp_idx,
   7379                              defip_entry_t *lpm_entry)
   7380 {
   7381     int is_ecmp = 0;
   7382     uint32 nh_ecmp_idx = 0;
   7383     int ipv6 = soc_L3_DEFIPm_field32_get(unit, lpm_entry, MODE0_f(unit));
   7384 
   7385     /* Reset entry flags first. */
   7386     lpm_cfg->defip_flags = 0;
   7387 
   7388     /* Check if entry points to ecmp group. */
   7389     if (soc_feature(unit, soc_feature_generic_dest)) {
   7390         uint32 dest_type = SOC_MEM_FIF_DEST_INVALID;
   7391         nh_ecmp_idx = soc_mem_field32_dest_get(unit, L3_DEFIPm, lpm_entry,
   7392                                                DESTINATION0f, &dest_type);
   7393         if (dest_type == SOC_MEM_FIF_DEST_ECMP) {
   7394             is_ecmp = 1;
   7395         } else if (dest_type != SOC_MEM_FIF_DEST_NEXTHOP) {
   7396             nh_ecmp_idx = 0;
   7397         }
   7398     } else {
   7399         is_ecmp = soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP0f);
   7400         if (is_ecmp) {
   7401             nh_ecmp_idx = soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP_PTR0f);
   7402         } else {
   7403             nh_ecmp_idx = soc_L3_DEFIPm_field32_get(unit, lpm_entry, NEXT_HOP_INDEX0f);
   7404         }
   7405     }
   7406 
   7407     if (is_ecmp) {
   7408         /* Mark entry as ecmp */
   7409         lpm_cfg->defip_ecmp = 1;
   7410         lpm_cfg->defip_flags |= BCM_L3_MULTIPATH;
   7411 
   7412         /* Get ecmp group id. */
   7413         if (p_nh_ecmp_idx) {
   7414             *p_nh_ecmp_idx = nh_ecmp_idx;
   7415         }
   7416     } else {
   7417         /* Mark entry as non-ecmp. */
   7418         lpm_cfg->defip_ecmp = 0;
   7419 
   7420         /* Reset ecmp group next hop count. */
   7421         lpm_cfg->defip_ecmp_count = 0;
   7422 
   7423         /* Get next hop index. */
   7424         if (p_nh_ecmp_idx) {
   7425             *p_nh_ecmp_idx = nh_ecmp_idx;
   7426         }
   7427     }
   7428     /* Get entry priority. */
   7429     lpm_cfg->defip_prio = soc_L3_DEFIPm_field32_get(unit, lpm_entry, PRI0f);
   7430 
   7431     /* Get hit bit. */
   7432     if (!ALPM_CTRL(unit).hit_bits_skip &&
   7433         soc_L3_DEFIPm_field32_get(unit, lpm_entry, HIT0f)) {
   7434         lpm_cfg->defip_flags |= BCM_L3_HIT;
   7435     }
   7436 
   7437     /* Get priority override bit. */
   7438     if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, RPE0f)) {
   7439         lpm_cfg->defip_flags |= BCM_L3_RPE;
   7440     }
   7441 
   7442     /* Get destination discard flag. */
   7443     if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, DST_DISCARD0f)) {
   7444         if(soc_L3_DEFIPm_field32_get(unit, lpm_entry, DST_DISCARD0f)) {
   7445             lpm_cfg->defip_flags |= BCM_L3_DST_DISCARD;
   7446         }
   7447     }
   7448 
   7449 #if defined(BCM_TRX_SUPPORT)
   7450     /* Set classification group id. */
   7451     if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, CLASS_ID0f)) {
   7452         lpm_cfg->defip_lookup_class = 
   7453             soc_L3_DEFIPm_field32_get(unit, lpm_entry, CLASS_ID0f);
   7454     }
   7455 #endif /* BCM_TRX_SUPPORT */
   7456 
   7457 
   7458     if (ipv6) {
   7459         lpm_cfg->defip_flags |= BCM_L3_IP6;
   7460         /* Get hit bit from the second part of the entry. */
   7461         if (!ALPM_CTRL(unit).hit_bits_skip &&
   7462             soc_L3_DEFIPm_field32_get(unit, lpm_entry, HIT1f)) {
   7463             lpm_cfg->defip_flags |= BCM_L3_HIT;
   7464         }
   7465 
   7466         /* Get priority override bit from the second part of the entry. */
   7467         if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, RPE1f)) {
   7468             lpm_cfg->defip_flags |= BCM_L3_RPE;
   7469         }
   7470     }
   7471 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   7472     if (soc_feature(unit, soc_feature_ipmc_defip)) {
   7473         int ipmc_route = 0;
   7474         if (soc_mem_field_valid(unit, L3_DEFIPm, MULTICAST_ROUTE0f)) {
   7475             ipmc_route = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, MULTICAST_ROUTE0f);
   7476         } else if (soc_mem_field_valid(unit, L3_DEFIPm, DATA_TYPE0f)) {
   7477             if (soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, DATA_TYPE0f) == 2) {
   7478                 ipmc_route = 1;
   7479             } else {
   7480                 ipmc_route = 0;
   7481             }
   7482         }
   7483 
   7484         if (ipmc_route) {
   7485             int val;
   7486 
   7487             lpm_cfg->defip_flags |= BCM_L3_IPMC;
   7488             if (p_nh_ecmp_idx) {
   7489                 *p_nh_ecmp_idx = BCM_XGS3_L3_INVALID_INDEX;
   7490             }
   7491             if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_DROP0f)) {
   7492                 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RPF_FAIL_DROP;
   7493             }
   7494             if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPU0f)) {
   7495                 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RPF_FAIL_TOCPU;
   7496             }
   7497             /*
   7498              * RP ID and ExpectedIIF are overlaid.
   7499              */
   7500             val = soc_L3_DEFIPm_field32_get(unit, lpm_entry, EXPECTED_L3_IIF0f);
   7501 
   7502             if (soc_feature(unit, soc_feature_l3defip_rp_l3iif_resolve)) {
   7503                 int rpa_id_mask = (1 << soc_mem_field_length(unit, L3_DEFIPm, RPA_ID0f)) - 1;
   7504                 /*
   7505                  * 1) If value is more than RPA_ID field then its l3_iif.
   7506                  *    N/A for TD3/MV2/HX5 to support warmboot.
   7507                  * 2) When RPF FAIL DROP/TOCPU flags are set then its l3iif valid
   7508                  */
   7509                 if ((lpm_cfg->defip_ipmc_flags &
   7510                      (BCM_IPMC_RPF_FAIL_DROP | BCM_IPMC_RPF_FAIL_TOCPU)) ||
   7511                     (!(SOC_IS_TRIDENT3(unit) || SOC_IS_MAVERICK2(unit) ||
   7512                        SOC_IS_HELIX5(unit)) && (val > rpa_id_mask))) {
   7513                     lpm_cfg->defip_expected_intf = val;
   7514                     if (0 != lpm_cfg->defip_expected_intf) {
   7515                         lpm_cfg->defip_ipmc_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK;
   7516                     }
   7517                     lpm_cfg->defip_l3a_rp = BCM_IPMC_RP_ID_INVALID;
   7518                 } else {
   7519                     lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RP_ID_EXPECTED_INTF_RESOLVE;
   7520                     lpm_cfg->defip_l3a_rp = val & rpa_id_mask;
   7521                     lpm_cfg->defip_expected_intf = val;
   7522                 }
   7523             } else if (_BCM_DEFIP_IPMC_RP_IS_SET(val)) {
   7524                lpm_cfg->defip_l3a_rp = _BCM_DEFIP_IPMC_RP_GET(val);
   7525             } else {
   7526                lpm_cfg->defip_expected_intf = val;
   7527 
   7528                 if (0 != lpm_cfg->defip_expected_intf) {
   7529                     lpm_cfg->defip_ipmc_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK;
   7530                 }
   7531                 lpm_cfg->defip_l3a_rp = BCM_IPMC_RP_ID_INVALID;
   7532             }
   7533 
   7534             if (soc_feature(unit, soc_feature_generic_dest)) {
   7535                 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID;
   7536                 uint32 dest_value = 0;
   7537                 dest_value = soc_mem_field32_dest_get(unit,
   7538                         L3_DEFIPm, lpm_entry,
   7539                         DESTINATION0f, &dest_type);
   7540                 if (dest_type == SOC_MEM_FIF_DEST_IPMC) {
   7541                     lpm_cfg->defip_mc_group = dest_value;
   7542                 } else {
   7543                     lpm_cfg->defip_mc_group = 0;
   7544                 }
   7545             } else {
   7546                 lpm_cfg->defip_mc_group = soc_mem_field32_get(unit, L3_DEFIPm,
   7547                                                 lpm_entry, L3MC_INDEX0f);
   7548             }
   7549         }
   7550     }
   7551 #endif
   7552 
   7553 
   7554     /* Read base counter index. */
   7555     lpm_cfg->defip_flex_ctr_base_id =
   7556         soc_L3_DEFIPm_field32_get(unit, lpm_entry, FLEX_CTR_BASE_COUNTER_IDX0f);
   7557     /* Read counter offset mode. */
   7558     lpm_cfg->defip_flex_ctr_mode =
   7559         soc_L3_DEFIPm_field32_get(unit, lpm_entry, FLEX_CTR_OFFSET_MODE0f);
   7560     /* Read counter pool number. */
   7561     lpm_cfg->defip_flex_ctr_pool =
   7562         soc_L3_DEFIPm_field32_get(unit, lpm_entry, FLEX_CTR_POOL_NUMBER0f);
   7563 
   7564     return;
   7565 }
   7566 
   7567 
   7568 /*
   7569  * Function:
   7570  *     _bcm_td2_alpm_lpm128_mask_parse
   7571  * Purpose:
   7572  *     Read IP6 mask field from memory field to ip6_addr_t buffer.
   7573  * Parameters:
   7574  *     unit  - (IN) BCM device number.
   7575  *     mem   - (IN) Memory id.
   7576  *     entry - (IN) HW entry buffer.
   7577  *     ip6   - (OUT) SW ip6 address buffer.
   7578  * Returns:      void
   7579  */
   7580 STATIC void
   7581 _bcm_td2_alpm_lpm128_mask_parse(int unit, soc_mem_t mem, const void *entry,
   7582                                 ip6_addr_t ip6)
   7583 {
   7584     uint32              ip6_field[4];
   7585     soc_mem_field_get(unit, mem, entry, IP_ADDR_MASK0_LWRf, (uint32 *)&ip6_field[3]);
   7586     ip6[12] = (uint8) (ip6_field[3] >> 24);
   7587     ip6[13] = (uint8) (ip6_field[3] >> 16 & 0xff);
   7588     ip6[14] = (uint8) (ip6_field[3] >> 8 & 0xff);
   7589     ip6[15] = (uint8) (ip6_field[3] & 0xff);
   7590     soc_mem_field_get(unit, mem, entry, IP_ADDR_MASK1_LWRf, (uint32 *)&ip6_field[2]);
   7591     ip6[8] = (uint8) (ip6_field[2] >> 24);
   7592     ip6[9] = (uint8) (ip6_field[2] >> 16 & 0xff);
   7593     ip6[10] = (uint8) (ip6_field[2] >> 8 & 0xff);
   7594     ip6[11] = (uint8) (ip6_field[2] & 0xff);
   7595     soc_mem_field_get(unit, mem, entry, IP_ADDR_MASK0_UPRf, (uint32 *)&ip6_field[1]);
   7596     ip6[4] = (uint8) (ip6_field[1] >> 24);
   7597     ip6[5] = (uint8) (ip6_field[1] >> 16 & 0xff);
   7598     ip6[6] =(uint8) (ip6_field[1] >> 8 & 0xff);
   7599     ip6[7] =(uint8) (ip6_field[1] & 0xff);
   7600     soc_mem_field_get(unit, mem, entry, IP_ADDR_MASK1_UPRf, ip6_field);
   7601     ip6[0] =(uint8) (ip6_field[0] >> 24);
   7602     ip6[1] =(uint8) (ip6_field[0] >> 16 & 0xff);
   7603     ip6[2] =(uint8) (ip6_field[0] >> 8 & 0xff);
   7604     ip6[3] =(uint8) (ip6_field[0] & 0xff);
   7605 }
   7606 
   7607 /*
   7608  * Function:
   7609  *     _bcm_td2_alpm_lpm128_addr_parse
   7610  * Purpose:
   7611  *     Read IP6 address field from memory field to ip6_addr_t buffer.
   7612  * Parameters:
   7613  *     unit  - (IN) BCM device number.
   7614  *     mem   - (IN) Memory id.
   7615  *     entry - (IN) HW entry buffer.
   7616  *     ip6   - (OUT) SW ip6 address buffer.
   7617  * Returns:      void
   7618  */
   7619 STATIC void
   7620 _bcm_td2_alpm_lpm128_addr_parse(int unit, soc_mem_t mem, const void *entry,
   7621                                 ip6_addr_t ip6)
   7622 {
   7623     uint32              ip6_field[4];
   7624     soc_mem_field_get(unit, mem, entry, IP_ADDR0_LWRf, (uint32 *)&ip6_field[3]);
   7625     ip6[12] = (uint8) (ip6_field[3] >> 24);
   7626     ip6[13] = (uint8) (ip6_field[3] >> 16 & 0xff);
   7627     ip6[14] = (uint8) (ip6_field[3] >> 8 & 0xff);
   7628     ip6[15] = (uint8) (ip6_field[3] & 0xff);
   7629     soc_mem_field_get(unit, mem, entry, IP_ADDR1_LWRf, (uint32 *)&ip6_field[2]);
   7630     ip6[8] = (uint8) (ip6_field[2] >> 24);
   7631     ip6[9] = (uint8) (ip6_field[2] >> 16 & 0xff);
   7632     ip6[10] = (uint8) (ip6_field[2] >> 8 & 0xff);
   7633     ip6[11] = (uint8) (ip6_field[2] & 0xff);
   7634     soc_mem_field_get(unit, mem, entry, IP_ADDR0_UPRf, (uint32 *)&ip6_field[1]);
   7635     ip6[4] = (uint8) (ip6_field[1] >> 24);
   7636     ip6[5] = (uint8) (ip6_field[1] >> 16 & 0xff);
   7637     ip6[6] =(uint8) (ip6_field[1] >> 8 & 0xff);
   7638     ip6[7] =(uint8) (ip6_field[1] & 0xff);
   7639     soc_mem_field_get(unit, mem, entry, IP_ADDR1_UPRf, ip6_field);
   7640     ip6[0] =(uint8) (ip6_field[0] >> 24);
   7641     ip6[1] =(uint8) (ip6_field[0] >> 16 & 0xff);
   7642     ip6[2] =(uint8) (ip6_field[0] >> 8 & 0xff);
   7643     ip6[3] =(uint8) (ip6_field[0] & 0xff);
   7644 }
   7645 
   7646 /*
   7647  * Function:
   7648  *      _bcm_td2_alpm_lpm128_key_parse
   7649  * Purpose:
   7650  *      Parse route entry key from L3_DEFIP_PAIR_128 table.
   7651  * Parameters:
   7652  *      unit        - (IN)SOC unit number.
   7653  *      entry       - (IN)Hw entry buffer.
   7654  *      lpm_cfg     - (IN/OUT)Buffer to fill defip information.
   7655  * Returns:
   7656  *      BCM_E_XXX
   7657  */
   7658 STATIC int
   7659 _bcm_td2_alpm_lpm128_key_parse(int unit, uint32 *hw_entry,
   7660                                _bcm_defip_cfg_t *lpm_cfg)
   7661 {
   7662     soc_mem_t mem = L3_DEFIP_PAIR_128m;  /* Route table memory. */
   7663     bcm_ip6_t mask;                      /* Subnet mask.        */
   7664 
   7665     /* Input parameters check. */
   7666     if ((lpm_cfg == NULL) || (hw_entry == NULL)) {
   7667         return (BCM_E_PARAM);
   7668     }
   7669 
   7670     /* Extract ip6 address. */
   7671     _bcm_td2_alpm_lpm128_addr_parse(unit,mem, hw_entry,
   7672                                     lpm_cfg->defip_ip6_addr);
   7673 
   7674     /* Extract subnet mask. */
   7675     _bcm_td2_alpm_lpm128_mask_parse(unit, mem, hw_entry, mask);
   7676     lpm_cfg->defip_sub_len = bcm_ip6_mask_length(mask);
   7677 
   7678     /* Extract vrf id & vrf mask. */
   7679     if(!soc_mem_field32_get(unit, mem, hw_entry, VRF_ID_MASK0_LWRf)) {
   7680         lpm_cfg->defip_vrf = BCM_L3_VRF_OVERRIDE;
   7681     } else {
   7682         lpm_cfg->defip_vrf = soc_mem_field32_get(unit, mem, hw_entry,
   7683                                                  VRF_ID_0_LWRf);
   7684     }
   7685     return (BCM_E_NONE);
   7686 }
   7687 
   7688 
   7689 STATIC INLINE void
   7690 _bcm_td2_alpm_lpm128_data_parse(int unit, _bcm_defip_cfg_t *lpm_cfg,
   7691                                 int *p_nh_ecmp_idx, defip_pair_128_entry_t *lpm_entry)
   7692 {
   7693     int is_ecmp = 0;
   7694     uint32 nh_ecmp_idx = 0;
   7695     soc_mem_t mem = L3_DEFIP_PAIR_128m;
   7696     int ipv6 = soc_mem_field32_get(unit, mem, lpm_entry, MODE0_LWR_f(unit));
   7697 
   7698     /* Reset entry flags first. */
   7699     lpm_cfg->defip_flags = 0;
   7700 
   7701     /* Check if entry points to ecmp group. */
   7702     if (soc_feature(unit, soc_feature_generic_dest)) {
   7703         uint32 dest_type = SOC_MEM_FIF_DEST_INVALID;
   7704         nh_ecmp_idx = soc_mem_field32_dest_get(unit, mem, lpm_entry,
   7705                                                DESTINATIONf, &dest_type);
   7706         if (dest_type == SOC_MEM_FIF_DEST_ECMP) {
   7707             is_ecmp = 1;
   7708         } else if (dest_type != SOC_MEM_FIF_DEST_NEXTHOP) {
   7709             nh_ecmp_idx = 0;
   7710         }
   7711     } else {
   7712         is_ecmp = soc_mem_field32_get(unit, mem, lpm_entry, ECMPf);
   7713         if (is_ecmp) {
   7714             nh_ecmp_idx = soc_mem_field32_get(unit, mem, lpm_entry, ECMP_PTRf);
   7715         } else {
   7716             nh_ecmp_idx = soc_mem_field32_get(unit, mem, lpm_entry, NEXT_HOP_INDEXf);
   7717         }
   7718     }
   7719 
   7720     if (is_ecmp) {
   7721         /* Mark entry as ecmp */
   7722         lpm_cfg->defip_ecmp = 1;
   7723         lpm_cfg->defip_flags |= BCM_L3_MULTIPATH;
   7724 
   7725         /* Get ecmp group id. */
   7726         if (p_nh_ecmp_idx) {
   7727             *p_nh_ecmp_idx = nh_ecmp_idx;
   7728         }
   7729     } else {
   7730         /* Mark entry as non-ecmp. */
   7731         lpm_cfg->defip_ecmp = 0;
   7732 
   7733         /* Reset ecmp group next hop count. */
   7734         lpm_cfg->defip_ecmp_count = 0;
   7735 
   7736         /* Get next hop index. */
   7737         if (p_nh_ecmp_idx) {
   7738             *p_nh_ecmp_idx = nh_ecmp_idx;
   7739         }
   7740     }
   7741     /* Get entry priority. */
   7742     lpm_cfg->defip_prio = 
   7743                     soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, PRIf);
   7744 
   7745     /* Get hit bit. */
   7746     if (!ALPM_CTRL(unit).hit_bits_skip &&
   7747         soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, HITf)) {
   7748         lpm_cfg->defip_flags |= BCM_L3_HIT;
   7749     }
   7750 
   7751     /* Get priority override bit. */
   7752     if (soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, RPEf)) {
   7753         lpm_cfg->defip_flags |= BCM_L3_RPE;
   7754     }
   7755 
   7756     /* Get destination discard flag. */
   7757     if (SOC_MEM_FIELD_VALID(unit, L3_DEFIP_PAIR_128m, DST_DISCARDf)) {
   7758         if(soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, DST_DISCARDf)) {
   7759             lpm_cfg->defip_flags |= BCM_L3_DST_DISCARD;
   7760         }
   7761     }
   7762 
   7763 #if defined(BCM_TRX_SUPPORT)
   7764     /* Set classification group id. */
   7765     if (SOC_MEM_FIELD_VALID(unit, L3_DEFIP_PAIR_128m, CLASS_IDf)) {
   7766         lpm_cfg->defip_lookup_class = 
   7767             soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, CLASS_IDf);
   7768     }
   7769 #endif /* BCM_TRX_SUPPORT */
   7770 
   7771     if (ipv6) {
   7772         lpm_cfg->defip_flags |= BCM_L3_IP6;
   7773         /* Get hit bit from the second part of the entry. */
   7774         if (!ALPM_CTRL(unit).hit_bits_skip &&
   7775             soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, HITf)) {
   7776             lpm_cfg->defip_flags |= BCM_L3_HIT;
   7777         }
   7778 
   7779         /* Get priority override bit from the second part of the entry. */
   7780         if (soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, RPEf)) {
   7781             lpm_cfg->defip_flags |= BCM_L3_RPE;
   7782         }
   7783     }
   7784 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   7785     if (soc_feature(unit, soc_feature_ipmc_defip)) {
   7786         int is_ipmc = 0;
   7787 
   7788         if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, MULTICAST_ROUTEf)) {
   7789             is_ipmc = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m,
   7790                                           lpm_entry, MULTICAST_ROUTEf);
   7791         } else if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, DATA_TYPEf)) {
   7792             if (soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m,
   7793                                     lpm_entry, DATA_TYPEf) == 2) {
   7794                 is_ipmc = 1;
   7795             } else {
   7796                 is_ipmc = 0;
   7797             }
   7798         }
   7799 
   7800         if (is_ipmc) {
   7801             int val;
   7802             lpm_cfg->defip_flags |= BCM_L3_IPMC;
   7803 
   7804             if (p_nh_ecmp_idx) {
   7805                 *p_nh_ecmp_idx = BCM_XGS3_L3_INVALID_INDEX;
   7806             }
   7807             if (soc_L3_DEFIP_PAIR_128m_field32_get(unit,
   7808                         lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_DROPf)) {
   7809                 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RPF_FAIL_DROP;
   7810             }
   7811             if (soc_L3_DEFIP_PAIR_128m_field32_get(unit,
   7812                         lpm_entry, IPMC_EXPECTED_L3_IIF_MISMATCH_TOCPUf)) {
   7813                 lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RPF_FAIL_TOCPU;
   7814             }
   7815             /*
   7816              * RP ID and ExpectedIIF are overlaid.
   7817              */
   7818             val = soc_L3_DEFIP_PAIR_128m_field32_get(unit,
   7819                                                    lpm_entry, EXPECTED_L3_IIFf);
   7820             if (soc_feature(unit, soc_feature_l3defip_rp_l3iif_resolve)) {
   7821                 int rpa_id_mask = (1 << soc_mem_field_length(unit, L3_DEFIP_PAIR_128m, RPA_IDf)) - 1;
   7822                 /*
   7823                  * 1) If value is more than RPA_ID field then its l3_iif.
   7824                  *    N/A for TD3/MV2/HX5 to support warmboot.
   7825                  * 2) When RPF FAIL DROP/TOCPU flags are set then its l3iif valid
   7826                  */
   7827                 if ((lpm_cfg->defip_ipmc_flags &
   7828                      (BCM_IPMC_RPF_FAIL_DROP | BCM_IPMC_RPF_FAIL_TOCPU)) ||
   7829                     (!(SOC_IS_TRIDENT3(unit) || SOC_IS_MAVERICK2(unit) ||
   7830                        SOC_IS_HELIX5(unit)) && (val > rpa_id_mask))) {
   7831                     lpm_cfg->defip_expected_intf = val;
   7832                     if (0 != lpm_cfg->defip_expected_intf) {
   7833                         lpm_cfg->defip_ipmc_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK;
   7834                     }
   7835                     lpm_cfg->defip_l3a_rp = BCM_IPMC_RP_ID_INVALID;
   7836                 } else {
   7837                     lpm_cfg->defip_ipmc_flags |= BCM_IPMC_RP_ID_EXPECTED_INTF_RESOLVE;
   7838                     lpm_cfg->defip_l3a_rp = val & rpa_id_mask;
   7839                     lpm_cfg->defip_expected_intf = val;
   7840                 }
   7841             } else if (_BCM_DEFIP_IPMC_RP_IS_SET(val)) {
   7842                 lpm_cfg->defip_l3a_rp = _BCM_DEFIP_IPMC_RP_GET(val);
   7843             } else {
   7844                 lpm_cfg->defip_expected_intf = val;
   7845 
   7846                 if (0 != lpm_cfg->defip_expected_intf) {
   7847                     lpm_cfg->defip_ipmc_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK;
   7848                 }
   7849                 lpm_cfg->defip_l3a_rp = BCM_IPMC_RP_ID_INVALID;
   7850             }
   7851 
   7852             if (soc_feature(unit, soc_feature_generic_dest)) {
   7853                 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID;
   7854                 uint32 dest_value = 0;
   7855                 dest_value = soc_mem_field32_dest_get(unit, mem, lpm_entry,
   7856                                                        DESTINATIONf, &dest_type);
   7857                 if (dest_type == SOC_MEM_FIF_DEST_IPMC) {
   7858                     lpm_cfg->defip_mc_group = dest_value;
   7859                 } else {
   7860                     lpm_cfg->defip_mc_group = 0;
   7861                 }
   7862             } else {
   7863                 lpm_cfg->defip_mc_group = soc_L3_DEFIP_PAIR_128m_field32_get(unit,
   7864                                                 lpm_entry, L3MC_INDEXf);
   7865             }
   7866         }
   7867     }
   7868 #endif
   7869 
   7870 
   7871     /* Read base counter index. */
   7872     lpm_cfg->defip_flex_ctr_base_id =
   7873         soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, FLEX_CTR_BASE_COUNTER_IDXf);
   7874     /* Read counter offset mode. */
   7875     lpm_cfg->defip_flex_ctr_mode =
   7876         soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, FLEX_CTR_OFFSET_MODEf);
   7877     /* Read counter pool number. */
   7878     lpm_cfg->defip_flex_ctr_pool =
   7879         soc_L3_DEFIP_PAIR_128m_field32_get(unit, lpm_entry, FLEX_CTR_POOL_NUMBERf);
   7880 
   7881     return;
   7882 }
   7883 
   7884 /*
   7885  * Function:
   7886  *      _bcm_td2_alpm_l3_defip_mem_get
   7887  * Purpose:
   7888  *      Resolve route table memory for a given route entry.
   7889  * Parameters:
   7890  *      unit       - (IN)SOC unit number.
   7891  *      flags      - (IN)IPv6/IPv4 route.
   7892  *      plen       - (IN)Prefix length.
   7893  *      mem        - (OUT)Route table memory.
   7894  * Returns:
   7895  *      BCM_E_XXX
   7896  */
   7897 STATIC int
   7898 _bcm_td2_alpm_l3_defip_mem_get(int unit, uint32 flags, int plen, soc_mem_t *mem)
   7899 {
   7900     soc_mem_t defip_mem = L3_DEFIPm;
   7901     soc_mem_t defip_pair_mem = L3_DEFIP_PAIR_128m;
   7902 
   7903     if (SOC_MEM_IS_VALID(unit, L3_DEFIP_LEVEL1m)) {
   7904         defip_mem = L3_DEFIP_LEVEL1m;
   7905         defip_pair_mem = L3_DEFIP_PAIR_LEVEL1m;
   7906     }
   7907 
   7908     /* Default value */
   7909     if (mem) {
   7910         *mem = defip_mem;
   7911     }
   7912     if ((flags & BCM_L3_IP6)) {
   7913         if (soc_mem_index_count(unit, defip_pair_mem) > 0) {
   7914             if (mem) {
   7915                 *mem = defip_pair_mem;
   7916             }
   7917             return BCM_E_NONE;
   7918         }
   7919         /* no v6-128 config. allow only v6-64 */
   7920         if (plen > 64) {
   7921             LOG_ERROR(BSL_LS_BCM_L3,
   7922                       (BSL_META_U(unit,
   7923                                   "Cannot allow prefix length > 64 in "
   7924                                   "%s\n"), SOC_MEM_NAME(unit, defip_mem)));
   7925             return BCM_E_PARAM;
   7926         }
   7927     } else if (BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) == 0) {
   7928         /* no l3_defip. cannot insert ipv4 */
   7929         LOG_ERROR(BSL_LS_BCM_L3,
   7930                   (BSL_META_U(unit,
   7931                               "Cannot allow ipv4 routes in "
   7932                               "%s\n"), SOC_MEM_NAME(unit, defip_pair_mem)));
   7933         return BCM_E_PARAM;
   7934     }
   7935 
   7936     return BCM_E_NONE;
   7937 }
   7938 
   7939 
   7940 /*
   7941  * Function:
   7942  *      _bcm_td2_alpm_128_clear_hit
   7943  * Purpose:
   7944  *      Clear prefix entry hit bit.
   7945  * Parameters:
   7946  *      unit      - (IN)SOC unit number.
   7947  *      key_data  - (IN) LPM key_data.
   7948  * Returns:
   7949  *      BCM_E_XXX
   7950  */
   7951 STATIC int
   7952 _bcm_td2_alpm_128_clear_hit(int u, void *key_data, int index, int flex)
   7953 {
   7954     soc_mem_t   mem;
   7955     uint32      e[SOC_MAX_MEM_FIELD_WORDS];
   7956     uint32      hit = 0;
   7957 
   7958     mem = L3_DEFIP_ALPM_IPV6_128m;
   7959 
   7960     BCM_IF_ERROR_RETURN(
   7961         soc_mem_read_no_cache(u, 0, mem, 0, MEM_BLOCK_ANY, index, e));
   7962     if (SOC_MEM_FIELD_VALID(u, mem, HITf)) {
   7963         hit = soc_mem_field32_get(u, mem, e, HITf);
   7964         if (hit) {
   7965             soc_mem_field32_set(u, mem, e, HITf, 0);
   7966             BCM_IF_ERROR_RETURN(soc_mem_write(u, mem, MEM_BLOCK_ALL, index, e));
   7967         }
   7968     }
   7969 
   7970     return SOC_E_NONE;
   7971 }
   7972 
   7973 /*
   7974  * Function:
   7975  *      _bcm_td2_alpm_clear_hit
   7976  * Purpose:
   7977  *      Clear prefix entry hit bit.
   7978  * Parameters:
   7979  *      unit      - (IN)SOC unit number.
   7980  *      key_data  - (IN) LPM key_data.
   7981  * Returns:
   7982  *      BCM_E_XXX
   7983  */
   7984 STATIC int
   7985 _bcm_td2_alpm_clear_hit(int u, void *key_data, int index, int flex)
   7986 {
   7987     int         ipv6;
   7988     soc_mem_t   mem;
   7989     uint32      e[SOC_MAX_MEM_FIELD_WORDS];
   7990     uint32      hit = 0;
   7991 
   7992     ipv6 = soc_mem_field32_get(u, L3_DEFIPm, key_data, MODE0_f(u));
   7993 
   7994     mem = (ipv6) ? (flex ? L3_DEFIP_ALPM_IPV6_64_1m : L3_DEFIP_ALPM_IPV6_64m) :
   7995                    (flex ? L3_DEFIP_ALPM_IPV4_1m : L3_DEFIP_ALPM_IPV4m);
   7996 
   7997     BCM_IF_ERROR_RETURN(
   7998         soc_mem_read_no_cache(u, 0, mem, 0, MEM_BLOCK_ANY, index, e));
   7999     if (SOC_MEM_FIELD_VALID(u, mem, HITf)) {
   8000         hit = soc_mem_field32_get(u, mem, e, HITf);
   8001         if (hit) {
   8002             soc_mem_field32_set(u, mem, e, HITf, 0);
   8003             BCM_IF_ERROR_RETURN(soc_mem_write(u, mem, MEM_BLOCK_ALL, index, e));
   8004         }
   8005     }
   8006 
   8007     return SOC_E_NONE;
   8008 }
   8009 
   8010 
   8011 /*
   8012  * Function:
   8013  *      _bcm_td2_alpm_get
   8014  * Purpose:
   8015  *      Get an entry from DEFIP table.
   8016  * Parameters:
   8017  *      unit        - (IN)SOC unit number.
   8018  *      lpm_cfg     - (IN)Buffer to fill defip information. 
   8019  *      nh_ecmp_idx - (IN)Next hop or ecmp group index
   8020  * Returns:
   8021  *      BCM_E_XXX
   8022  */
   8023 int
   8024 _bcm_td2_alpm_get(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx)
   8025 {
   8026     defip_entry_t lpm_key;      /* Route lookup key.        */
   8027     defip_entry_t lpm_entry;    /* Search result buffer.    */
   8028     defip_pair_128_entry_t lpm_128_key;
   8029     defip_pair_128_entry_t lpm_128_entry;
   8030     int clear_hit;              /* Clear hit indicator.     */
   8031     int rv = 0;                 /* Operation return status. */
   8032     uint32 flags = 0;
   8033     soc_mem_t   mem;
   8034 
   8035     /* Input parameters check */
   8036     if (NULL == lpm_cfg) {
   8037         return (BCM_E_PARAM);
   8038     }
   8039     
   8040     /* Zero buffers. */
   8041     sal_memset(&lpm_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, defip));
   8042     sal_memset(&lpm_key, 0, BCM_XGS3_L3_ENT_SZ(unit, defip));
   8043     sal_memset(&lpm_128_entry, 0, sizeof(lpm_128_entry));
   8044     sal_memset(&lpm_128_key, 0, sizeof(lpm_128_key));
   8045 
   8046     /* Check if clear hit bit required. */
   8047     clear_hit = lpm_cfg->defip_flags & BCM_L3_HIT_CLEAR;
   8048 
   8049     BCM_IF_ERROR_RETURN(_bcm_td2_alpm_l3_defip_mem_get(unit, lpm_cfg->defip_flags,
   8050                                               lpm_cfg->defip_sub_len, &mem));
   8051     switch (mem) {
   8052       case L3_DEFIP_PAIR_128m:
   8053        /* Initialize lkup key. */
   8054         BCM_IF_ERROR_RETURN(_bcm_td2_alpm_lpm128_init(unit, lpm_cfg,
   8055                              &lpm_128_key, 0, &flags));
   8056         /* Perform hw lookup. */
   8057         if (SOC_IS_TRIDENT2(unit) || SOC_IS_TRIDENT2PLUS(unit)) {
   8058             rv = soc_alpm_128_lookup(unit, &lpm_128_key, &lpm_128_entry, 
   8059                                      &lpm_cfg->defip_index, &lpm_cfg->defip_alpm_cookie);
   8060         }
   8061 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   8062         else {
   8063             rv = soc_th_alpm_128_lookup(unit, &lpm_128_key, &lpm_128_entry, 
   8064                                      &lpm_cfg->defip_index, &lpm_cfg->defip_alpm_cookie);
   8065         }
   8066 #endif
   8067 
   8068         BCM_IF_ERROR_RETURN(rv);
   8069 
   8070         /* Parse hw buffer to defip entry. */
   8071         _bcm_td2_alpm_lpm128_data_parse(unit, lpm_cfg, nh_ecmp_idx, &lpm_128_entry);
   8072 
   8073         break;
   8074 
   8075       default:
   8076         /* Initialize lkup key. */
   8077         BCM_IF_ERROR_RETURN(_bcm_td2_alpm_lpm_ent_init(unit, lpm_cfg, &lpm_key, 0,
   8078                                                     &flags));
   8079         /* Perform hw lookup. */
   8080         if (SOC_IS_TRIDENT2(unit) || SOC_IS_TRIDENT2PLUS(unit)) {
   8081             rv = soc_alpm_lookup(unit, &lpm_key, &lpm_entry, &lpm_cfg->defip_index,
   8082                             &lpm_cfg->defip_alpm_cookie);
   8083         }
   8084 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   8085         else {
   8086             rv = soc_th_alpm_lookup(unit, &lpm_key, &lpm_entry, &lpm_cfg->defip_index,
   8087                                 &lpm_cfg->defip_alpm_cookie);
   8088         }
   8089 #endif
   8090 
   8091         BCM_IF_ERROR_RETURN(rv);
   8092 
   8093         /* Parse hw buffer to defip entry. */
   8094         _bcm_td2_alpm_lpm_data_parse(unit, lpm_cfg, nh_ecmp_idx, &lpm_entry);
   8095         break;
   8096     }
   8097 
   8098     /* Clear the HIT bit */
   8099     if (clear_hit && BCM_SUCCESS(rv)) {
   8100         if (mem == L3_DEFIP_PAIR_128m) {
   8101             BCM_IF_ERROR_RETURN(
   8102                 _bcm_td2_alpm_128_clear_hit(unit, &lpm_128_key,
   8103                     ALPM_ENT_INDEX(lpm_cfg->defip_index),
   8104                     flags & SOC_ALPM_STAT_FLEX));
   8105         } else {
   8106             BCM_IF_ERROR_RETURN(
   8107                 _bcm_td2_alpm_clear_hit(unit, &lpm_key,
   8108                     ALPM_ENT_INDEX(lpm_cfg->defip_index),
   8109                     flags & SOC_ALPM_STAT_FLEX));
   8110         }
   8111     }
   8112     return (BCM_E_NONE);
   8113 }
   8114 
   8115 /*
   8116  * Function:
   8117  *      _bcm_td2_alpm_add
   8118  * Purpose:
   8119  *      Add an entry to DEFIP table.
   8120  * Parameters:
   8121  *      unit        - (IN)SOC unit number.
   8122  *      lpm_cfg     - (IN)Buffer to fill defip information. 
   8123  *      nh_ecmp_idx - (IN)Next hop or ecmp group index.
   8124  * Returns:
   8125  *      BCM_E_XXX
   8126  */
   8127 int
   8128 _bcm_td2_alpm_add(int unit, _bcm_defip_cfg_t *lpm_cfg, int nh_ecmp_idx)
   8129 {
   8130     defip_entry_t lpm_entry;
   8131     defip_pair_128_entry_t lpm_128_entry;
   8132     int rv = 0;                     /* Operation return status. */
   8133     uint32  flags= 0;
   8134     soc_mem_t   mem;
   8135 
   8136     /* Input parameters check */
   8137     if (NULL == lpm_cfg) {
   8138         return (BCM_E_PARAM);
   8139     }
   8140 
   8141     BCM_IF_ERROR_RETURN(_bcm_td2_alpm_l3_defip_mem_get(unit, lpm_cfg->defip_flags,
   8142                                               lpm_cfg->defip_sub_len, &mem));
   8143     switch (mem) {
   8144       case L3_DEFIP_PAIR_128m:
   8145         BCM_IF_ERROR_RETURN(_bcm_td2_alpm_lpm128_init(unit, lpm_cfg,
   8146                             &lpm_128_entry, nh_ecmp_idx, &flags));
   8147         if (SOC_IS_TRIDENT2(unit) || SOC_IS_TRIDENT2PLUS(unit)) {
   8148             rv = soc_alpm_128_insert(unit, &lpm_128_entry, flags, 
   8149                                     lpm_cfg->defip_index, lpm_cfg->defip_alpm_cookie);
   8150         }
   8151 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   8152         else {
   8153             rv = soc_th_alpm_128_insert(unit, &lpm_128_entry, flags, 
   8154                                     lpm_cfg->defip_index, lpm_cfg->defip_alpm_cookie);        
   8155         }
   8156 #endif
   8157         break;
   8158       default:
   8159         /* 
   8160          * Initialize hw buffer from lpm configuration. 
   8161          * NOTE: DON'T MOVE _bcm_fb_defip_ent_init CALL UP, 
   8162          * We want to copy flags & nh info, avoid  ipv6 mask & address 
   8163          * corruption
   8164          */
   8165         BCM_IF_ERROR_RETURN(_bcm_td2_alpm_lpm_ent_init(unit, lpm_cfg, &lpm_entry,
   8166                             nh_ecmp_idx, &flags));
   8167 
   8168         /* Write buffer to hw. */
   8169         if (SOC_IS_TRIDENT2(unit) || SOC_IS_TRIDENT2PLUS(unit)) {
   8170             rv = soc_alpm_insert(unit, &lpm_entry, flags, lpm_cfg->defip_index, 
   8171                                 lpm_cfg->defip_alpm_cookie);
   8172         }
   8173 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   8174         else {
   8175             rv = soc_th_alpm_insert(unit, &lpm_entry, flags, lpm_cfg->defip_index, 
   8176                                 lpm_cfg->defip_alpm_cookie);
   8177         }
   8178 #endif
   8179         break;
   8180     }
   8181 
   8182     /* If new route added increment total number of routes.  */
   8183     /* Lack of index indicates a new route. */
   8184     if ((rv >= 0) && !(lpm_cfg->defip_alpm_cookie & SOC_ALPM_LOOKUP_HIT ||
   8185                        lpm_cfg->defip_alpm_cookie & SOC_ALPM_LPM_LOOKUP_HIT)) {
   8186         BCM_XGS3_L3_DEFIP_CNT_INC(unit, (lpm_cfg->defip_flags & BCM_L3_IP6));
   8187     }
   8188     return rv;
   8189 }
   8190 
   8191 /*
   8192  * Function:
   8193  *      _bcm_fb_lpm_del
   8194  * Purpose:
   8195  *      Delete an entry from DEFIP table.
   8196  * Parameters:
   8197  *      unit    - (IN)SOC unit number.
   8198  *      lpm_cfg - (IN)Buffer to fill defip information. 
   8199  * Returns:
   8200  *      BCM_E_XXX
   8201  */
   8202 int
   8203 _bcm_td2_alpm_del(int unit, _bcm_defip_cfg_t *lpm_cfg)
   8204 {
   8205     int rv = 0;                 /* Operation return status. */
   8206     defip_entry_t lpm_entry;    /* Search result buffer.    */
   8207     defip_pair_128_entry_t lpm_128_entry;    /* Search result buffer.    */
   8208     uint32 flags;
   8209     soc_mem_t   mem;
   8210 
   8211     /* Input parameters check */
   8212     if (NULL == lpm_cfg) {
   8213         return (BCM_E_PARAM);
   8214     }
   8215 
   8216     /* Zero buffers. */
   8217     sal_memset(&lpm_entry, 0, BCM_XGS3_L3_ENT_SZ(unit, defip));
   8218     sal_memset(&lpm_128_entry, 0, sizeof(lpm_128_entry));
   8219 
   8220     BCM_IF_ERROR_RETURN(_bcm_td2_alpm_l3_defip_mem_get(unit, lpm_cfg->defip_flags,
   8221                                               lpm_cfg->defip_sub_len, &mem));
   8222     
   8223     switch (mem) {
   8224       case L3_DEFIP_PAIR_128m:
   8225         /* Initialize hw buffer deletion key. */
   8226         BCM_IF_ERROR_RETURN(_bcm_td2_alpm_lpm128_init(unit, lpm_cfg,
   8227                                                    &lpm_128_entry, 0, &flags));
   8228         if (SOC_IS_TRIDENT2(unit) || SOC_IS_TRIDENT2PLUS(unit)) {
   8229             rv = soc_alpm_128_delete(unit, &lpm_128_entry, lpm_cfg->defip_index,
   8230                                     lpm_cfg->defip_alpm_cookie);
   8231         }
   8232 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   8233         else {
   8234             rv = soc_th_alpm_128_delete(unit, &lpm_128_entry, lpm_cfg->defip_index,
   8235                                     lpm_cfg->defip_alpm_cookie);
   8236         }
   8237 #endif
   8238         break;
   8239       default:
   8240         /* Initialize hw buffer deletion key. */
   8241         BCM_IF_ERROR_RETURN(_bcm_td2_alpm_lpm_ent_init(unit, lpm_cfg, &lpm_entry, 0,
   8242                                                &flags));
   8243         /* Write buffer to hw. */
   8244         if (SOC_IS_TRIDENT2(unit) || SOC_IS_TRIDENT2PLUS(unit)) {
   8245             rv = soc_alpm_delete(unit, &lpm_entry, lpm_cfg->defip_index,
   8246                                     lpm_cfg->defip_alpm_cookie);
   8247         }
   8248 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT)
   8249         else {
   8250             rv = soc_th_alpm_delete(unit, &lpm_entry, lpm_cfg->defip_index,
   8251                                     lpm_cfg->defip_alpm_cookie);
   8252         }
   8253 #endif
   8254         break;
   8255     }
   8256 
   8257     /* If route deleted, decrement total number of routes.  */
   8258     if (rv >= 0) {
   8259         BCM_XGS3_L3_DEFIP_CNT_DEC(unit, lpm_cfg->defip_flags & BCM_L3_IP6);
   8260     }
   8261     return rv;
   8262 }
   8263 
   8264 /*
   8265  * Function:
   8266  *     _bcm_fb_mem_ip6_defip_get
   8267  * Purpose:
   8268  *    Get IP6 address mask field in ALPM mem to defip_cfg
   8269  * Note:
   8270  *    See soc_mem_ip6_addr_set()
   8271  */
   8272 STATIC void
   8273 _bcm_td2_alpm_ent64_key_parse(int unit, const void *alpm_key, soc_mem_t mem,
   8274                               _bcm_defip_cfg_t *lpm_cfg)
   8275 {
   8276     uint8 *ip6;                 /* Ip6 address.       */
   8277     uint8 mask[BCM_IP6_ADDRLEN];        /* Subnet mask.       */
   8278     uint32 ip6_word[2];            /* Temp storage.      */
   8279 
   8280     sal_memset(mask, 0, sizeof (bcm_ip6_t));
   8281 
   8282     /* Just to keep variable name short. */
   8283     ip6 = lpm_cfg->defip_ip6_addr;
   8284     sal_memset(ip6, 0, sizeof (bcm_ip6_t));
   8285 
   8286     soc_mem_field_get(unit, mem, alpm_key, KEYf, &ip6_word[0]);
   8287     ip6[0] = (uint8) ((ip6_word[1] >> 24) & 0xff);
   8288     ip6[1] = (uint8) ((ip6_word[1] >> 16) & 0xff);
   8289     ip6[2] = (uint8) ((ip6_word[1] >> 8) & 0xff);
   8290     ip6[3] = (uint8) (ip6_word[1] & 0xff);
   8291 
   8292     ip6[4] = (uint8) ((ip6_word[0] >> 24) & 0xff);
   8293     ip6[5] = (uint8) ((ip6_word[0] >> 16) & 0xff);
   8294     ip6[6] = (uint8) ((ip6_word[0] >> 8) & 0xff);
   8295     ip6[7] = (uint8) (ip6_word[0] & 0xff);
   8296 
   8297     lpm_cfg->defip_sub_len = soc_mem_field32_get(unit, mem, alpm_key, LENGTHf);
   8298 }
   8299 
   8300 /*
   8301  * Function:
   8302  *      _bcm_td2_alpm_ent_key_parse
   8303  * Purpose:
   8304  *      Parse entry key from ALPM table.
   8305  * Parameters:
   8306  *      unit        - (IN) SOC unit number.
   8307  *      lpm_cfg     - (OUT)Buffer to fill defip information. 
   8308  *      *lpm_entry  - (IN) Pointer to lpm buffer read from hw. 
   8309  *      alpm_mem    - (IN) ALPM memory type.
   8310  *      *alpm_entry - (IN) Pointer to alpm entry read from SRAM bank.
   8311  * Returns:
   8312  *      void
   8313  */
   8314 STATIC void
   8315 _bcm_td2_alpm_ent_key_parse(int unit, _bcm_defip_cfg_t *lpm_cfg,
   8316                             defip_entry_t *lpm_entry, soc_mem_t alpm_mem,
   8317                             void *alpm_entry)
   8318 {
   8319     bcm_ip_t v4_mask;
   8320     int ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6;
   8321 
   8322     /* Set prefix ip address & mask. */
   8323     if (ipv6) {
   8324         _bcm_td2_alpm_ent64_key_parse(unit, alpm_entry, alpm_mem, lpm_cfg);
   8325     } else {
   8326         /* Get ipv4 address. */
   8327         lpm_cfg->defip_ip_addr = soc_mem_field32_get(unit, alpm_mem, 
   8328                                                      alpm_entry, KEYf);
   8329 
   8330         /* Get subnet mask. */
   8331         v4_mask = soc_mem_field32_get(unit, alpm_mem, alpm_entry, LENGTHf);
   8332         if (v4_mask) {
   8333             v4_mask = ~((1 << (32 - v4_mask)) - 1);
   8334         }
   8335 
   8336         /* Fill mask length. */
   8337         lpm_cfg->defip_sub_len = bcm_ip_mask_length(v4_mask);
   8338     }
   8339 
   8340     /* Get Virtual Router id */
   8341     soc_alpm_lpm_vrf_get(unit, lpm_entry, &lpm_cfg->defip_vrf, NULL);
   8342     return;
   8343 }
   8344 
   8345 /*
   8346  * Function:
   8347  *      _bcm_td2_alpm_ent_data_parse
   8348  * Purpose:
   8349  *      Parse an entry from DEFIP table.
   8350  * Parameters:
   8351  *      unit        - (IN)SOC unit number.
   8352  *      lpm_cfg     - (OUT)Buffer to fill defip information. 
   8353  *      nh_ecmp_idx - (OUT)Next hop index or ecmp group id.  
   8354  *      alpm_entry   - (IN) Buffer read from hw.
   8355  * Returns:
   8356  *      void
   8357  */
   8358 STATIC void
   8359 _bcm_td2_alpm_ent_data_parse(int unit, _bcm_defip_cfg_t *lpm_cfg, int *p_nh_ecmp_idx,
   8360                              soc_mem_t alpm_mem, void *alpm_entry)
   8361 {
   8362 
   8363     int is_ecmp = 0;
   8364     uint32 nh_ecmp_idx = 0;
   8365 
   8366     /* Check if entry points to ecmp group. */
   8367     if (soc_feature(unit, soc_feature_generic_dest)) {
   8368         uint32 dest_type = SOC_MEM_FIF_DEST_INVALID;
   8369         nh_ecmp_idx = soc_mem_field32_dest_get(unit, alpm_mem, alpm_entry,
   8370                                                DESTINATIONf, &dest_type);
   8371         if (dest_type == SOC_MEM_FIF_DEST_ECMP) {
   8372             is_ecmp = 1;
   8373         } else if (dest_type != SOC_MEM_FIF_DEST_NEXTHOP) {
   8374             nh_ecmp_idx = 0;
   8375         }
   8376     } else if (!(SOC_IS_HURRICANEX(unit))) {
   8377         is_ecmp = soc_mem_field32_get(unit, alpm_mem, alpm_entry, ECMPf);
   8378         if (is_ecmp) {
   8379             nh_ecmp_idx = soc_mem_field32_get(unit, alpm_mem, alpm_entry, ECMP_PTRf);
   8380         } else {
   8381             nh_ecmp_idx = soc_mem_field32_get(unit, alpm_mem, alpm_entry, NEXT_HOP_INDEXf);
   8382         }
   8383     } else {
   8384         nh_ecmp_idx = soc_mem_field32_get(unit, alpm_mem, alpm_entry, NEXT_HOP_INDEXf);
   8385     }
   8386 
   8387     /* Reset entry flags first. */
   8388     lpm_cfg->defip_flags = 0;
   8389 
   8390     /* Check if entry points to ecmp group. */
   8391     /* hurricane does not have ecmp flag*/
   8392     if ((!(SOC_IS_HURRICANEX(unit))) && is_ecmp) {
   8393         /* Mark entry as ecmp */
   8394         lpm_cfg->defip_ecmp = 1;
   8395         lpm_cfg->defip_flags |= BCM_L3_MULTIPATH;
   8396 
   8397         /* Get ecmp group id. */
   8398         if (p_nh_ecmp_idx) {
   8399             *p_nh_ecmp_idx = nh_ecmp_idx;
   8400         }
   8401     } else {
   8402         /* Mark entry as non-ecmp. */
   8403         lpm_cfg->defip_ecmp = 0;
   8404 
   8405         /* Reset ecmp group next hop count. */
   8406         lpm_cfg->defip_ecmp_count = 0;
   8407 
   8408         /* Get next hop index. */
   8409         if (p_nh_ecmp_idx) {
   8410             *p_nh_ecmp_idx = nh_ecmp_idx;
   8411         }
   8412     }
   8413     /* Get entry priority. */
   8414     lpm_cfg->defip_prio = soc_mem_field32_get(unit, alpm_mem, alpm_entry, 
   8415                                              PRIf);
   8416 
   8417     /* Get hit bit. */
   8418     if (!ALPM_CTRL(unit).hit_bits_skip &&
   8419         soc_mem_field32_get(unit, alpm_mem, alpm_entry, HITf)) {
   8420         lpm_cfg->defip_flags |= BCM_L3_HIT;
   8421     }
   8422 
   8423     /* Get priority override bit. */
   8424     if (soc_mem_field32_get(unit, alpm_mem, alpm_entry, RPEf)) {
   8425         lpm_cfg->defip_flags |= BCM_L3_RPE;
   8426     }
   8427 
   8428     /* Get destination discard flag. */
   8429     if (SOC_MEM_FIELD_VALID(unit, alpm_mem, DST_DISCARDf)) {
   8430         if(soc_mem_field32_get(unit, alpm_mem, alpm_entry, DST_DISCARDf)) {
   8431             lpm_cfg->defip_flags |= BCM_L3_DST_DISCARD;
   8432         }
   8433     }
   8434 
   8435     /* Set classification group id. */
   8436     lpm_cfg->defip_lookup_class = soc_mem_field32_get(unit, alpm_mem, 
   8437                                                        alpm_entry, CLASS_IDf);
   8438 
   8439     if (alpm_mem == L3_DEFIP_ALPM_IPV6_64m ||
   8440         alpm_mem == L3_DEFIP_ALPM_IPV6_64_1m ||
   8441         alpm_mem == L3_DEFIP_ALPM_IPV6_128m) {
   8442         lpm_cfg->defip_flags |= BCM_L3_IP6;
   8443     }
   8444     return;
   8445 }
   8446 
   8447 STATIC int
   8448 _bcm_td2_alpm_ent128_key_parse(int unit, soc_mem_t mem, uint32 *alpm_entry,
   8449                                _bcm_defip_cfg_t *lpm_cfg)
   8450 {
   8451     uint32 ip6_word[4];
   8452 
   8453     uint8 *ip6;
   8454 
   8455     ip6 = lpm_cfg->defip_ip6_addr;
   8456 
   8457     soc_mem_field_get(unit, mem, alpm_entry, KEYf, ip6_word);
   8458     ip6[0] = (ip6_word[3] >> 24);
   8459     ip6[1] = (ip6_word[3] >> 16) & 0xff;
   8460     ip6[2] = (ip6_word[3] >> 8) & 0xff;
   8461     ip6[3] = ip6_word[3];
   8462 
   8463     ip6[4] = ip6_word[2] >> 24;
   8464     ip6[5] = (ip6_word[2] >> 16) & 0xff;
   8465     ip6[6] = (ip6_word[2] >> 8) & 0xff;
   8466     ip6[7] = ip6_word[2];
   8467 
   8468     ip6[8] = ip6_word[1] >> 24;
   8469     ip6[9] = (ip6_word[1] >> 16) & 0xff;
   8470     ip6[10] = (ip6_word[1] >> 8) & 0xff;
   8471     ip6[11] = ip6_word[1];
   8472 
   8473     ip6[12] = ip6_word[0] >> 24;
   8474     ip6[13] = (ip6_word[0] >> 16) & 0xff;
   8475     ip6[14] = (ip6_word[0] >> 8) & 0xff;
   8476     ip6[15] = ip6_word[0];
   8477 
   8478     lpm_cfg->defip_sub_len = 
   8479                     soc_mem_field32_get(unit, mem, alpm_entry, LENGTHf);
   8480 
   8481     return SOC_E_NONE;
   8482 }
   8483 
   8484 STATIC int
   8485 _bcm_td2_alpm_ent128_data_parse(int unit, soc_mem_t mem, uint32 *hw_entry,
   8486                                 _bcm_defip_cfg_t *lpm_cfg, int *p_nh_ecmp_idx)
   8487 {
   8488     int is_ecmp = 0;
   8489     uint32 nh_ecmp_idx = 0;
   8490 
   8491     /* Input parameters check. */
   8492     if ((lpm_cfg == NULL) || (hw_entry == NULL)) {
   8493         return (BCM_E_PARAM);
   8494     }
   8495 
   8496     /* Check if entry points to ecmp group. */
   8497     if (soc_feature(unit, soc_feature_generic_dest)) {
   8498         uint32 dest_type = SOC_MEM_FIF_DEST_INVALID;
   8499         nh_ecmp_idx = soc_mem_field32_dest_get(unit, mem, hw_entry,
   8500                                                DESTINATIONf, &dest_type);
   8501         if (dest_type == SOC_MEM_FIF_DEST_ECMP) {
   8502             is_ecmp = 1;
   8503         } else if (dest_type != SOC_MEM_FIF_DEST_NEXTHOP) {
   8504             nh_ecmp_idx = 0;
   8505         }
   8506     } else {
   8507         is_ecmp = soc_mem_field32_get(unit, mem, hw_entry, ECMPf);
   8508         if (is_ecmp) {
   8509             nh_ecmp_idx = soc_mem_field32_get(unit, mem, hw_entry, ECMP_PTRf);
   8510         } else {
   8511             nh_ecmp_idx = soc_mem_field32_get(unit, mem, hw_entry, NEXT_HOP_INDEXf);
   8512         }
   8513     }
   8514 
   8515     /* Reset entry flags first. */
   8516     lpm_cfg->defip_flags = 0;
   8517 
   8518     /* Check if entry points to ecmp group. */
   8519     if (is_ecmp) {
   8520         /* Mark entry as ecmp */
   8521         lpm_cfg->defip_ecmp = TRUE;
   8522         lpm_cfg->defip_flags |= BCM_L3_MULTIPATH;
   8523 
   8524         /* Get ecmp group id. */
   8525         if (p_nh_ecmp_idx != NULL) {
   8526             *p_nh_ecmp_idx = nh_ecmp_idx;
   8527         }
   8528     } else {
   8529         /* Mark entry as non-ecmp. */
   8530         lpm_cfg->defip_ecmp = 0;
   8531 
   8532         /* Reset ecmp group next hop count. */
   8533         lpm_cfg->defip_ecmp_count = 0;
   8534 
   8535         /* Get next hop index. */
   8536         if (p_nh_ecmp_idx != NULL) {
   8537             *p_nh_ecmp_idx = nh_ecmp_idx;
   8538         }
   8539     }
   8540 
   8541     /* Mark entry as IPv6 */
   8542     lpm_cfg->defip_flags |= BCM_L3_IP6;
   8543 
   8544     /* Get entry priority. */
   8545     lpm_cfg->defip_prio = soc_mem_field32_get(unit, mem, hw_entry, PRIf);
   8546 
   8547     /* Get classification group id. */
   8548     lpm_cfg->defip_lookup_class = 
   8549         soc_mem_field32_get(unit, mem, hw_entry, CLASS_IDf);
   8550 
   8551     /* Get hit bit. */
   8552     if (!ALPM_CTRL(unit).hit_bits_skip &&
   8553         soc_mem_field32_get(unit, mem, hw_entry, HITf)) {
   8554         lpm_cfg->defip_flags |= BCM_L3_HIT;
   8555     }
   8556 
   8557     /* Get priority override bit. */
   8558     if (soc_mem_field32_get(unit, mem, hw_entry, RPEf)) {
   8559         lpm_cfg->defip_flags |= BCM_L3_RPE;
   8560     }
   8561 
   8562     /* Get destination discard field. */
   8563     if(soc_mem_field32_get(unit, mem, hw_entry, DST_DISCARDf)) {
   8564         lpm_cfg->defip_flags |= BCM_L3_DST_DISCARD;
   8565     }
   8566 
   8567     return (BCM_E_NONE);
   8568 }
   8569 
   8570 /*
   8571  * Function:
   8572  *      _bcm_td2_alpm_warmboot_walk
   8573  * Purpose:
   8574  *      Recover LPM and ALPM entries
   8575  * Parameters:
   8576  *      unit     - (IN)SOC unit number.
   8577  *      trv_data - (IN)pattern + compare,act,notify routines.  
   8578  * Returns:
   8579  *      BCM_E_XXX
   8580  */
   8581 int
   8582 _bcm_td2_alpm_warmboot_walk(int unit, _bcm_l3_trvrs_data_t *trv_data)
   8583 {
   8584     int ipv6;                   /* IPv6 flag.                   */
   8585     int idx;                    /* Iteration index.             */
   8586     int tmp_idx;                /* IPv4 entries iterator.       */
   8587     int vrf_id;                 /*                              */
   8588     int vrf;                    /*                              */
   8589     int idx_end;                /*                              */
   8590     int bkt_addr;               /*                              */
   8591     int bkt_count;              /*                              */
   8592     int bkt_idx = 0;            /*                              */
   8593     int bkt_ptr = 0;            /* Bucket pointer               */
   8594     int bank_num = 0;           /* Number of active SRAM banks  */
   8595     int pivot_idx = 0;          /* Pivot Index                  */
   8596     int entry_num = 0;          /* ALPM entry number in bucket  */
   8597     int nh_ecmp_idx;            /* Next hop/Ecmp group index.   */
   8598     int entry_count;            /* ALPM entry count in bucket   */
   8599     int bank_count;             /* SRAM bank count              */
   8600     int step_count;             /*                              */
   8601     int cmp_result;             /* Test routine result.         */
   8602     int rv = BCM_E_FAIL;        /* Operation return status.     */
   8603     int defip_table_size = 0;   /* Defip table size.            */
   8604     char *lpm_tbl_ptr = NULL;   /* DMA table pointer.           */
   8605     void *alpm_entry = NULL;    /*                              */
   8606     soc_mem_t alpm_mem;         /*                              */
   8607     _bcm_defip_cfg_t lpm_cfg;   /* Buffer to fill route info.   */
   8608     defip_entry_t *lpm_entry;   /* Hw entry buffer.             */
   8609     defip_alpm_ipv4_1_entry_t    alpm_entry_v4;
   8610     defip_alpm_ipv6_64_1_entry_t alpm_entry_v6_64;
   8611 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   8612     int ipmc_route = 0;         /* Route is ip multicast type   */
   8613 #endif
   8614     int flex;
   8615     int bkt_ptr_tmp = 0;
   8616     uint8 bkt_occupied = 0;
   8617     
   8618     /* DMA LPM table to software copy */
   8619     BCM_IF_ERROR_RETURN
   8620         (bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, defip),
   8621                              BCM_XGS3_L3_ENT_SZ(unit, defip), "lpm_tbl",
   8622                              &lpm_tbl_ptr, &defip_table_size));
   8623 
   8624     if (SOC_URPF_STATUS_GET(unit)) {
   8625         defip_table_size >>= 1;
   8626     }
   8627 
   8628     idx_end    = defip_table_size;
   8629     bank_count = 4;
   8630     
   8631     /* Walk all lpm entries */
   8632     for (idx = 0; idx < idx_end; idx++) {
   8633         /* Calculate entry ofset */
   8634         lpm_entry =
   8635             soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip),
   8636                                          defip_entry_t *, lpm_tbl_ptr, idx);
   8637 
   8638         ipv6 = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, MODE0_f(unit));
   8639 
   8640         /* Calculate LPM table traverse step count */
   8641         if (ipv6) {
   8642             if (SOC_ALPM_V6_SCALE_CHECK(unit, ipv6)) {
   8643                 step_count = 2;
   8644             } else {
   8645                 step_count = 1;
   8646             }
   8647         } else {
   8648             step_count = 2;
   8649         }
   8650       
   8651         /* Insert LPM entry into HASH table and init LPM trackers */ 
   8652         if (BCM_FAILURE(soc_alpm_warmboot_lpm_reinit(unit, ipv6, 
   8653                                                      idx, lpm_entry))) {
   8654             goto free_lpm_table;
   8655         }
   8656 
   8657         bkt_occupied = 0;
   8658 
   8659         /*
   8660          * This loop is used for two purposes
   8661          *  1. IPv4, DEFIP entry has two IPv4 entries.
   8662          *  2. IPv6 double wide mode, walk next bucket.
   8663          */
   8664         for (tmp_idx = 0; tmp_idx < step_count; tmp_idx++) {
   8665             if (tmp_idx) {  /* If index == 1*/
   8666                 if (!ipv6) {
   8667                     /* Copy upper half of lpm entry to lower half */
   8668                     soc_alpm_lpm_ip4entry1_to_0(unit, lpm_entry, lpm_entry, TRUE);
   8669                
   8670                     /* Invalidate upper half */
   8671                     soc_L3_DEFIPm_field32_set(unit, lpm_entry, VALID1f, 0);
   8672                 }
   8673             }
   8674     
   8675             /* Make sure entry is valid. */
   8676             if (!soc_L3_DEFIPm_field32_get(unit, lpm_entry, VALID0f)) {
   8677                 continue;
   8678             }
   8679 
   8680             if (ipv6 && tmp_idx) {
   8681                 /* 
   8682                  * IPv6 double wide mode,  Walk bucket entries at next bucket.
   8683                  */
   8684                 bkt_ptr++;
   8685             } else {
   8686                 /* Extract bucket pointer from LPM entry */
   8687                 bkt_ptr = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, 
   8688                                               ALG_BKT_PTR0f);
   8689                 bkt_ptr_tmp = bkt_ptr;
   8690 
   8691 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   8692                 if (soc_feature(unit, soc_feature_ipmc_defip)) {
   8693                     /* Skip reserved ipmc entry */
   8694                     int ipmc_index = 0;
   8695                     ipmc_route = 0;
   8696                     if (soc_mem_field_valid(unit, L3_DEFIPm, MULTICAST_ROUTE0f)) {
   8697                         ipmc_route = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, MULTICAST_ROUTE0f);
   8698                     } else if (soc_mem_field_valid(unit, L3_DEFIPm, DATA_TYPE0f)) {
   8699                         if (soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, DATA_TYPE0f) == 2) {
   8700                             ipmc_route = 1;
   8701                         } else {
   8702                             ipmc_route = 0;
   8703                         }
   8704                     }
   8705 
   8706                     if (soc_feature(unit, soc_feature_generic_dest)) {
   8707                         uint32 dest_type = SOC_MEM_FIF_DEST_INVALID;
   8708                         uint32 dest_value = 0;
   8709                         dest_value = soc_mem_field32_dest_get(unit,
   8710                                 L3_DEFIPm, lpm_entry,
   8711                                 DESTINATION0f, &dest_type);
   8712                         if (dest_type == SOC_MEM_FIF_DEST_IPMC) {
   8713                             ipmc_index = dest_value;
   8714                         } else {
   8715                             ipmc_index = 0;
   8716                         }
   8717                     } else {
   8718                         ipmc_index = soc_mem_field32_get(unit, L3_DEFIPm,
   8719                                         lpm_entry, L3MC_INDEX0f);
   8720                     }
   8721 
   8722                     if (ipmc_route && ipmc_index == 0) {
   8723                         continue;
   8724                     }
   8725                 }
   8726 #endif
   8727                 /* Extract VRF from LPM entry*/
   8728                 if (BCM_FAILURE(soc_alpm_lpm_vrf_get
   8729                                 (unit, lpm_entry, &vrf_id, &vrf))) {
   8730                     goto free_lpm_table;
   8731                 }
   8732 
   8733                 /* VRF_OVERRIDE (Global High) entries, and IP multicast prefix 
   8734                  * resides in TCAM */
   8735                 if (bkt_ptr == 0) {
   8736                     VRF_TRIE_ROUTES_INC(unit, vrf_id, vrf, ipv6);
   8737 
   8738                     sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t));
   8739                     _bcm_td2_alpm_lpm_data_parse(unit, &lpm_cfg, &nh_ecmp_idx,
   8740                                            lpm_entry);
   8741                     _bcm_td2_alpm_lpm_key_parse(unit, &lpm_cfg, lpm_entry);
   8742                     lpm_cfg.defip_index = idx;
   8743 
   8744                     if (ipv6 == (lpm_cfg.defip_flags & BCM_L3_IP6)) {
   8745                         if (trv_data->op_cb) {
   8746                             (void) (*trv_data->op_cb)(unit, (void *)trv_data,
   8747                                                       (void *)&lpm_cfg,
   8748                                                       (void *)&nh_ecmp_idx, 
   8749                                                       &cmp_result);
   8750                         }
   8751                     }
   8752                     if (ipv6) {
   8753                         tmp_idx++;
   8754                     }
   8755                     continue;
   8756                 }
   8757                     
   8758                 pivot_idx = (idx << 1) + tmp_idx;
   8759 
   8760                 /* TCAM pivot recovery */
   8761                 if(BCM_FAILURE(soc_alpm_warmboot_pivot_add(unit, ipv6, lpm_entry, pivot_idx,
   8762                                                            bkt_ptr))) {
   8763                     goto free_lpm_table;
   8764                 }
   8765 
   8766                 /* Set bucket bitmap */
   8767                 if(BCM_FAILURE(soc_alpm_warmboot_bucket_bitmap_set(unit, ipv6, bkt_ptr))) {
   8768                     goto free_lpm_table;
   8769                 }
   8770             }
   8771 
   8772             flex = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, ENTRY_VIEW0f);
   8773             if (ipv6) {
   8774                 if (flex) {
   8775                     alpm_mem = L3_DEFIP_ALPM_IPV6_64_1m;
   8776                     bkt_count = ALPM_IPV6_64_BKT_COUNT_FLEX;
   8777                     entry_count = 3;
   8778                     alpm_entry = &alpm_entry_v6_64;
   8779                 } else {
   8780                     alpm_mem = L3_DEFIP_ALPM_IPV6_64m;
   8781                     bkt_count = ALPM_IPV6_64_BKT_COUNT;
   8782                     entry_count = 4;
   8783                     alpm_entry = &alpm_entry_v6_64;
   8784                 }
   8785             } else {
   8786                 if (flex) {
   8787                     alpm_mem = L3_DEFIP_ALPM_IPV4_1m;
   8788                     bkt_count = ALPM_IPV4_BKT_COUNT_FLEX;
   8789                     entry_count = 4;
   8790                     alpm_entry = &alpm_entry_v4;
   8791                 } else {
   8792                     alpm_mem = L3_DEFIP_ALPM_IPV4m;
   8793                     bkt_count = ALPM_IPV4_BKT_COUNT;
   8794                     entry_count = 6;
   8795                     alpm_entry = &alpm_entry_v4;
   8796                 }
   8797             }
   8798 
   8799             entry_num = 0;
   8800             bank_num = 0;
   8801 
   8802             /* Get the bucket pointer from lpm entry */
   8803             for (bkt_idx = 0; bkt_idx < bkt_count; bkt_idx++) {
   8804                 /* Calculate bucket memory address */
   8805                 /* Increment so next bucket address can be calculated */
   8806                 bkt_addr = (entry_num << 16) | (bkt_ptr << 2) | 
   8807                            (bank_num & 0x3);
   8808                 entry_num++; 
   8809                 if (entry_num == entry_count) {
   8810                     entry_num = 0;
   8811                     bank_num++;
   8812                     if (bank_num == bank_count) {
   8813                         bank_num = 0;
   8814                     }
   8815                 }
   8816 
   8817                 /* Read entry from bucket memory */
   8818                 if (BCM_FAILURE(soc_mem_read(unit, alpm_mem, MEM_BLOCK_ANY,
   8819                                   bkt_addr, alpm_entry))) {
   8820                     goto free_lpm_table;
   8821                 }
   8822 
   8823                 /* Check if ALPM entry is valid */
   8824                 if (!soc_mem_field32_get(unit, alpm_mem, alpm_entry, VALIDf)) {
   8825                     continue;
   8826                 }
   8827 
   8828                 bkt_occupied = 1;
   8829 
   8830                 /* Zero destination buffer first. */
   8831                 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t));
   8832 
   8833                 /* Parse the entry. */
   8834                 _bcm_td2_alpm_ent_data_parse(unit, &lpm_cfg, &nh_ecmp_idx,
   8835                                              alpm_mem, alpm_entry);
   8836                
   8837                 /* Execute operation routine if any. */
   8838                 if (trv_data->op_cb) {
   8839                     rv = (*trv_data->op_cb) (unit, (void *)trv_data,
   8840                                             (void *)&lpm_cfg,
   8841                                             (void *)&nh_ecmp_idx, &cmp_result);
   8842 #ifdef BCM_CB_ABORT_ON_ERR
   8843                     if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   8844                         continue;
   8845                     }
   8846 #endif
   8847                 }
   8848 
   8849                 if(BCM_FAILURE(soc_alpm_warmboot_prefix_insert(unit, ipv6, flex, lpm_entry,
   8850                                          alpm_entry, pivot_idx, bkt_ptr, bkt_addr))) {
   8851                     continue;
   8852                 }
   8853 
   8854             } /* End of bucket walk loop*/
   8855             if (bkt_occupied) {
   8856                 /* If ipv6 double wide,  two alpm bkt views should be set */
   8857                 if (SOC_ALPM_V6_SCALE_CHECK(unit, ipv6)) {
   8858                     _soc_trident2_alpm_bkt_view_set(unit, bkt_ptr_tmp << 2, alpm_mem);
   8859                     _soc_trident2_alpm_bkt_view_set(unit, (bkt_ptr_tmp + 1) << 2, alpm_mem);
   8860                 } else {
   8861                     _soc_trident2_alpm_bkt_view_set(unit, bkt_ptr_tmp << 2, alpm_mem);
   8862                 }
   8863             }
   8864         } /* End of lpm entry upper/lower half traversal */
   8865     } /* End of lpm table traversal */
   8866 
   8867     if(BCM_FAILURE(soc_alpm_warmboot_lpm_reinit_done(unit))) {
   8868         goto free_lpm_table;
   8869     }
   8870 
   8871 #ifdef ALPM_WARM_BOOT_DEBUG
   8872     soc_alpm_lpm_sw_dump(unit);
   8873 #endif /* ALPM_WARM_BOOT_DEBUG  */
   8874 
   8875     rv = BCM_E_NONE;
   8876 free_lpm_table:
   8877     soc_cm_sfree(unit, lpm_tbl_ptr);
   8878 
   8879     return (rv);
   8880 }
   8881 
   8882 /*
   8883  * Function:
   8884  *      _bcm_td2_alpm_128_warmboot_walk
   8885  * Purpose:
   8886  *      Recover IPv6-128Bit LPM and ALPM entries
   8887  * Parameters:
   8888  *      unit     - (IN)SOC unit number.
   8889  *      trv_data - (IN)pattern + compare,act,notify routines.  
   8890  * Returns:
   8891  *      BCM_E_XXX
   8892  */
   8893 int
   8894 _bcm_td2_alpm_128_warmboot_walk(int unit, _bcm_l3_trvrs_data_t *trv_data)
   8895 {
   8896     int ipv6 = 2;               /* IPv6 flag.                   */
   8897     int idx;                    /* Iteration index.             */
   8898     int tmp_idx;                /* IPv4 entries iterator.       */
   8899     int vrf, vrf_id;            /*                              */
   8900     int idx_end;                /*                              */
   8901     int bkt_addr;               /*                              */
   8902     int bkt_count;              /*                              */
   8903     int bkt_idx = 0;            /*                              */
   8904     int bkt_ptr = 0;            /* Bucket pointer               */
   8905     int bank_num = 0;           /* Number of active SRAM banks  */
   8906     int entry_num = 0;          /* ALPM entry number in bucket  */
   8907     int nh_ecmp_idx;            /* Next hop/Ecmp group index.   */
   8908     int entry_count;            /* ALPM entry count in bucket   */
   8909     int bank_count;             /* SRAM bank count              */
   8910     int step_count;             /*                              */
   8911     int cmp_result;             /* Test routine result.         */
   8912     int rv = BCM_E_FAIL;        /* Operation return status.     */
   8913     int defip_table_size = 0;   /* Defip table size.            */
   8914     char *lpm_tbl_ptr = NULL;   /* DMA table pointer.           */
   8915     void *alpm_entry = NULL;    /*                              */
   8916     uint32 rval;                /*                              */
   8917     soc_mem_t alpm_mem;         /*                              */
   8918     _bcm_defip_cfg_t lpm_cfg;   /* Buffer to fill route info.   */
   8919     defip_pair_128_entry_t *lpm_entry; /* Hw entry buffer.      */
   8920     defip_alpm_ipv6_128_entry_t alpm_entry_v6_128; /* ALPM 128  */
   8921 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   8922     int ipmc_route = 0;         /* Route is ip multicast type   */
   8923 #endif
   8924     int bkt_ptr_tmp = 0;
   8925     uint8 bkt_occupied = 0;
   8926 
   8927     /* DMA LPM table to software copy */
   8928     BCM_IF_ERROR_RETURN
   8929         (bcm_xgs3_l3_tbl_dma(unit, L3_DEFIP_PAIR_128m,
   8930                     WORDS2BYTES(soc_mem_entry_words(unit, L3_DEFIP_PAIR_128m)), 
   8931                     "lpm_128_warmboot_tbl",
   8932                     &lpm_tbl_ptr, &defip_table_size));
   8933 
   8934     if(BCM_FAILURE(READ_L3_DEFIP_RPF_CONTROLr(unit, &rval))) {
   8935         goto free_lpm_table;
   8936     }
   8937 
   8938     if (SOC_URPF_STATUS_GET(unit)) {
   8939         defip_table_size >>= 1;
   8940     }
   8941 
   8942     idx_end     = defip_table_size;
   8943     alpm_mem    = L3_DEFIP_ALPM_IPV6_128m;
   8944     alpm_entry  = &alpm_entry_v6_128;
   8945     bkt_count   = ALPM_IPV6_128_BKT_COUNT;
   8946     entry_count = 2;
   8947     bank_count  = 4;
   8948     
   8949     if (SOC_ALPM_V6_SCALE_CHECK(unit, ipv6)) {
   8950         step_count = 2;
   8951     } else {
   8952         step_count = 1;
   8953     }
   8954     
   8955     /* Walk all lpm entries */
   8956     for (idx = 0; idx < idx_end; idx++) {
   8957         /* Calculate entry ofset */
   8958         lpm_entry =
   8959             soc_mem_table_idx_to_pointer(unit, L3_DEFIP_PAIR_128m,
   8960                                          defip_pair_128_entry_t *, lpm_tbl_ptr, idx);
   8961 
   8962         /* Verify if read LPM entry is IPv6-128 entry */
   8963         if (0x03 != soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, lpm_entry,
   8964                                         MODE1_UPR_f(unit))) {
   8965             continue;
   8966         };
   8967      
   8968         /* Verify if LPM entry is valid */
   8969         if (!soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, lpm_entry,
   8970                                     VALID1_LWRf) ||
   8971             !soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, lpm_entry,
   8972                                     VALID0_LWRf) ||
   8973             !soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, lpm_entry, 
   8974                                     VALID1_UPRf) || 
   8975             !soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, lpm_entry,
   8976                                     VALID0_UPRf)) {
   8977                 continue;
   8978         };
   8979 
   8980         /* Insert LPM entry into HASH table and init LPM trackers */ 
   8981         if (BCM_FAILURE(soc_alpm_128_warmboot_lpm_reinit(unit, ipv6, 
   8982                                                      idx, lpm_entry))) {
   8983             goto free_lpm_table;
   8984         }
   8985 
   8986         bkt_occupied = 0;
   8987 
   8988         /*  If IPv6 double wide mode, walk next bucket.*/
   8989         for (tmp_idx = 0; tmp_idx < step_count; tmp_idx++) {
   8990     
   8991             if (tmp_idx) {
   8992                 /* IPv6 double wide mode, Walk bucket entries at next bucket.*/
   8993                 bkt_ptr++;
   8994             } else {
   8995                 /* Extract bucket pointer from LPM entry */
   8996                 bkt_ptr = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m, lpm_entry, 
   8997                                               ALG_BKT_PTRf);
   8998                 bkt_ptr_tmp = bkt_ptr;
   8999 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   9000                 if (soc_feature(unit, soc_feature_ipmc_defip)) {
   9001                     /* Skip reserved ipmc entry */
   9002                     int ipmc_index = 0;
   9003                     ipmc_route = 0;
   9004                     if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, MULTICAST_ROUTEf)) {
   9005                         ipmc_route = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m,
   9006                                                       lpm_entry, MULTICAST_ROUTEf);
   9007                     } else if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, DATA_TYPEf)) {
   9008                         if (soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m,
   9009                                                 lpm_entry, DATA_TYPEf) == 2) {
   9010                             ipmc_route = 1;
   9011                         } else {
   9012                             ipmc_route = 0;
   9013                         }
   9014                     }
   9015 
   9016                     if (soc_feature(unit, soc_feature_generic_dest)) {
   9017                         uint32 dest_type = SOC_MEM_FIF_DEST_INVALID;
   9018                         uint32 dest_value = 0;
   9019                         dest_value = soc_mem_field32_dest_get(unit,
   9020                                 L3_DEFIP_PAIR_128m, lpm_entry,
   9021                                 DESTINATIONf, &dest_type);
   9022                         if (dest_type == SOC_MEM_FIF_DEST_IPMC) {
   9023                             ipmc_index = dest_value;
   9024                         } else {
   9025                             ipmc_index = 0;
   9026                         }
   9027                     } else {
   9028                         ipmc_index = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m,
   9029                                         lpm_entry, L3MC_INDEXf);
   9030                     }
   9031 
   9032                     if ((ipmc_route) && (ipmc_index == 0)) {
   9033                         continue;
   9034                     }
   9035                 }
   9036 #endif
   9037 
   9038                 /* Extract VRF from LPM entry*/
   9039                 if (BCM_FAILURE(soc_alpm_128_lpm_vrf_get
   9040                                 (unit, lpm_entry, &vrf_id, &vrf))) {
   9041                     goto free_lpm_table;
   9042                 }
   9043 
   9044                 /* VRF_OVERRIDE (Global High) entries, and IP multicast prefix resides in TCAM */
   9045                 if (bkt_ptr == 0) {
   9046                     VRF_TRIE_ROUTES_INC(unit, vrf_id, vrf, ipv6);
   9047 
   9048                     /* TCAM Routes Processing */ 
   9049                     sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t));
   9050                     (void) _bcm_td2_alpm_lpm128_key_parse(unit, (uint32 *) lpm_entry,
   9051                                                      &lpm_cfg);
   9052                     (void) soc_alpm_128_lpm_vrf_get(unit, lpm_entry, 
   9053                                                     &lpm_cfg.defip_vrf, 
   9054                                                     &nh_ecmp_idx);
   9055                     (void) _bcm_td2_alpm_lpm128_data_parse(unit, &lpm_cfg, &nh_ecmp_idx, lpm_entry);
   9056 
   9057                     lpm_cfg.defip_index = idx;
   9058                     if (trv_data->op_cb) {
   9059                         (void) (*trv_data->op_cb)(unit, (void *)trv_data,
   9060                                                   (void *)&lpm_cfg,
   9061                                                   (void *)&nh_ecmp_idx, 
   9062                                                   &cmp_result);
   9063                     }
   9064                     tmp_idx++;
   9065                     continue;
   9066                 }
   9067 
   9068                 /* TCAM pivot recovery */
   9069                 if(BCM_FAILURE(soc_alpm_128_warmboot_pivot_add(unit, ipv6,
   9070                                lpm_entry, idx, bkt_ptr))) {
   9071                     goto free_lpm_table;
   9072                 }
   9073 
   9074                 /* Set bucket bitmap */
   9075                 if(BCM_FAILURE(soc_alpm_128_warmboot_bucket_bitmap_set(unit, ipv6,
   9076                                bkt_ptr))) {
   9077                     goto free_lpm_table;
   9078                 }
   9079             }
   9080 
   9081             /* Get the bucket pointer from lpm entry */
   9082             for (bkt_idx = 0; bkt_idx < bkt_count; bkt_idx++) {
   9083                 /* Calculate bucket memory address */
   9084                 bkt_addr = (entry_num << 16) | (bkt_ptr << 2) | 
   9085                            (bank_num & 0x3);
   9086                 entry_num++; 
   9087                 
   9088                 if (entry_num == entry_count) {
   9089                     entry_num = 0;
   9090                     bank_num++;
   9091                     if (bank_num == bank_count) {
   9092                         bank_num = 0;
   9093                     }
   9094                 }
   9095 
   9096                 /* Read entry from bucket memory */
   9097                 if (BCM_FAILURE(soc_mem_read(unit, alpm_mem, MEM_BLOCK_ANY,
   9098                                   bkt_addr, alpm_entry))) {
   9099                     goto free_lpm_table;
   9100                 }
   9101 
   9102                 /* Check if ALPM entry is valid */
   9103                 if (!soc_mem_field32_get(unit, alpm_mem, alpm_entry, VALIDf)) {
   9104                     continue;
   9105                 }
   9106 
   9107                 bkt_occupied = 1;
   9108 
   9109                 /* Zero destination buffer first. */
   9110                 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t));
   9111 
   9112                 /* Fill entry IP address and subnet mask. */
   9113                 _bcm_td2_alpm_ent128_key_parse(unit, alpm_mem, alpm_entry, &lpm_cfg);
   9114                 soc_alpm_128_lpm_vrf_get(unit, lpm_entry, &lpm_cfg.defip_vrf, &vrf);
   9115                 /* Parse the entry. */
   9116                 _bcm_td2_alpm_ent128_data_parse(unit, alpm_mem, alpm_entry,
   9117                                             &lpm_cfg, &nh_ecmp_idx);
   9118                
   9119                 /* Execute operation routine if any. */
   9120                 if (trv_data->op_cb) {
   9121                     rv = (*trv_data->op_cb) (unit, (void *)trv_data,
   9122                                             (void *)&lpm_cfg,
   9123                                             (void *)&nh_ecmp_idx, &cmp_result);
   9124 #ifdef BCM_CB_ABORT_ON_ERR
   9125                     if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   9126                         continue;
   9127                     }
   9128 #endif
   9129                 }
   9130 
   9131                 if(BCM_FAILURE(soc_alpm_128_warmboot_prefix_insert(unit, ipv6, lpm_entry,
   9132                                          alpm_entry, idx, bkt_ptr, bkt_addr))) {
   9133                     continue;
   9134                 }
   9135 
   9136             } /* End of bucket walk loop*/
   9137             if (bkt_occupied) {
   9138                 /* If IPV6 double wide,  two alpm bkt views should be set */
   9139                 if (SOC_ALPM_V6_SCALE_CHECK(unit, ipv6)) {
   9140                     _soc_trident2_alpm_bkt_view_set(unit, bkt_ptr_tmp << 2, alpm_mem);
   9141                     _soc_trident2_alpm_bkt_view_set(unit, (bkt_ptr_tmp + 1) << 2, alpm_mem);
   9142                 } else {
   9143                     _soc_trident2_alpm_bkt_view_set(unit, bkt_ptr_tmp << 2, alpm_mem);
   9144                 }
   9145             }
   9146         } /* End of lpm entry upper/lower half traversal */
   9147     } /* End of lpm table traversal */
   9148 
   9149     if(BCM_FAILURE(soc_alpm_128_warmboot_lpm_reinit_done(unit))) {
   9150         goto free_lpm_table;
   9151     }
   9152 
   9153 #ifdef ALPM_WARM_BOOT_DEBUG
   9154     soc_alpm_lpm_sw_dump(unit);
   9155 #endif /* ALPM_WARM_BOOT_DEBUG  */
   9156 
   9157     rv = BCM_E_NONE;
   9158 free_lpm_table:
   9159     soc_cm_sfree(unit, lpm_tbl_ptr);
   9160 
   9161     return (rv);
   9162 }
   9163 
   9164 STATIC int
   9165 _bcm_td2_alpm_128_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data)
   9166 {
   9167     uint32 ipv6;                /* Iterate over ipv6 only flag. */
   9168     int idx;                    /* Iteration index.             */
   9169     int phy_idx;                /* Iteration index.             */
   9170     int tmp_idx;                /* ipv4 entries iterator.       */
   9171     char *lpm_tbl_ptr = NULL;   /* Dma table pointer.           */
   9172     char *alpm_tbl_ptr = NULL;  /* Dma table pointer.           */
   9173     char *alpm_hit_tbl_ptr = NULL;  /* Dma hit only table pointer.  */
   9174     int nh_ecmp_idx;            /* Next hop/Ecmp group index.   */
   9175     int cmp_result;             /* Test routine result.         */
   9176     defip_pair_128_entry_t *lpm_entry = NULL;   /* Hw entry buffer.    */
   9177     _bcm_defip_cfg_t lpm_cfg;   /* Buffer to fill route info.   */
   9178     int defip_table_size;       /* Defip table size.            */
   9179     int rv = BCM_E_NONE;        /* Operation return status.     */
   9180     int idx_start = 0;
   9181     int idx_end = 0, bkt_idx, bkt_count, bkt_ptr = 0, bkt_addr;
   9182     int entry_num, bank_num, entry_count, bank_count;
   9183     defip_alpm_ipv6_128_entry_t alpm_entry_v6_128;
   9184     void *alpm_entry;
   9185     void *raw_entry ;
   9186     soc_mem_t alpm_mem, pivot_mem = L3_DEFIP_PAIR_128m;
   9187     void *hit_entry;
   9188     soc_mem_t alpm_hit_mem;
   9189     int step_count;
   9190     int def_arr_idx = 0;
   9191     int def_rte_arr_sz;
   9192     typedef struct _alpm_def_route_info_s {
   9193         int idx;
   9194         int bkt_addr;
   9195     } _alpm_def_route_info_t;
   9196     _alpm_def_route_info_t *def_rte_arr = NULL;
   9197 
   9198     ipv6 = (trv_data->flags & BCM_L3_IP6);
   9199     if (!ipv6) {
   9200         return SOC_E_NONE;
   9201     }
   9202 
   9203     /* Table DMA the LPM table to software copy */
   9204     alpm_mem = L3_DEFIP_ALPM_RAWm;
   9205 
   9206     rv = bcm_xgs3_l3_tbl_dma(unit, alpm_mem,
   9207                              WORDS2BYTES(soc_mem_entry_words(unit, alpm_mem)),
   9208                              "alpm_tbl", &alpm_tbl_ptr, NULL);
   9209     alpm_mem = L3_DEFIP_ALPM_IPV6_128m;
   9210     if (BCM_FAILURE(rv)) {
   9211         goto error;
   9212     }
   9213 
   9214     rv = bcm_xgs3_l3_tbl_dma(unit, L3_DEFIP_PAIR_128m,
   9215                     WORDS2BYTES(soc_mem_entry_words(unit, L3_DEFIP_PAIR_128m)), 
   9216                              "lpm_128_tbl", &lpm_tbl_ptr, &defip_table_size);
   9217     if (BCM_FAILURE(rv)) {
   9218         goto error;
   9219     }
   9220 
   9221     if (!soc_feature(unit, soc_feature_alpm_hit_bits_not_support)) {
   9222         alpm_hit_mem = L3_DEFIP_ALPM_HIT_ONLYm;
   9223         rv = bcm_xgs3_l3_tbl_dma(unit, alpm_hit_mem,
   9224                                  WORDS2BYTES(soc_mem_entry_words(unit, alpm_hit_mem)),
   9225                                  "alpm_hit_tbl", &alpm_hit_tbl_ptr, NULL);
   9226         if (BCM_FAILURE(rv)) {
   9227             goto error;
   9228         }
   9229     }
   9230 
   9231     /* Allocate memory to store default route meta data*/
   9232     def_rte_arr_sz = SOC_VRF_MAX(unit) * sizeof(_alpm_def_route_info_t);
   9233     def_rte_arr = sal_alloc(def_rte_arr_sz, "alpm_def_rte_arry"); 
   9234     if (NULL == def_rte_arr) {
   9235         rv = BCM_E_MEMORY;
   9236         goto error;
   9237     }
   9238     sal_memset(def_rte_arr, 0, def_rte_arr_sz);
   9239 
   9240     if (SOC_URPF_STATUS_GET(unit)) {
   9241         defip_table_size >>= 1;
   9242     }
   9243 
   9244     idx_end     = defip_table_size;
   9245     alpm_mem    = L3_DEFIP_ALPM_IPV6_128m;
   9246     bkt_count   = ALPM_IPV6_128_BKT_COUNT;
   9247     idx_start   = 0;
   9248     bank_num    = 0;
   9249     entry_num   = 0;
   9250     bank_count  = 4;
   9251     entry_count = 2;
   9252     alpm_entry  = &alpm_entry_v6_128;
   9253 
   9254     if (SOC_ALPM_V6_SCALE_CHECK(unit, 1)) {
   9255         step_count = 2;
   9256     } else {
   9257         step_count = 1;
   9258     }
   9259 
   9260 
   9261     /* Walk all lpm entries */
   9262     for (idx = (idx_end - 1); idx >= idx_start; idx--) {    
   9263 
   9264         /* Calculate entry ofset. */
   9265         lpm_entry =
   9266             soc_mem_table_idx_to_pointer(unit, L3_DEFIP_PAIR_128m,
   9267                                     defip_pair_128_entry_t *, lpm_tbl_ptr, idx);
   9268 
   9269         /* Make sure entry is valid. */
   9270         if (!soc_mem_field32_get(unit, pivot_mem, lpm_entry, VALID0_LWRf)) {
   9271             continue;
   9272         }
   9273 
   9274         /* Skip reserved ipmc entry */
   9275         if (soc_feature(unit, soc_feature_ipmc_defip)) {
   9276             int ipmc_route = 0;
   9277             int ipmc_index = 0;
   9278             if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, MULTICAST_ROUTEf)) {
   9279                 ipmc_route = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m,
   9280                                               lpm_entry, MULTICAST_ROUTEf);
   9281             } else if (soc_mem_field_valid(unit, L3_DEFIP_PAIR_128m, DATA_TYPEf)) {
   9282                 if (soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m,
   9283                                         lpm_entry, DATA_TYPEf) == 2) {
   9284                     ipmc_route = 1;
   9285                 } else {
   9286                     ipmc_route = 0;
   9287                 }
   9288             }
   9289 
   9290             if (soc_feature(unit, soc_feature_generic_dest)) {
   9291                 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID;
   9292                 uint32 dest_value = 0;
   9293                 dest_value = soc_mem_field32_dest_get(unit,
   9294                         L3_DEFIP_PAIR_128m, lpm_entry,
   9295                         DESTINATIONf, &dest_type);
   9296                 if (dest_type == SOC_MEM_FIF_DEST_IPMC) {
   9297                     ipmc_index = dest_value;
   9298                 } else {
   9299                     ipmc_index = 0;
   9300                 }
   9301             } else {
   9302                 ipmc_index = soc_mem_field32_get(unit, L3_DEFIP_PAIR_128m,
   9303                                 lpm_entry, L3MC_INDEXf);
   9304             }
   9305 
   9306             if (ipmc_route && (ipmc_index == 0)) {
   9307                 continue;
   9308             }
   9309         }
   9310 
   9311         for (tmp_idx = 0; tmp_idx < step_count; tmp_idx++) {
   9312             if (tmp_idx) {
   9313                 bkt_ptr++;
   9314             } else {
   9315                 bkt_ptr = soc_mem_field32_get(unit, pivot_mem, lpm_entry, 
   9316                                           ALG_BKT_PTRf);
   9317             }
   9318 
   9319             if (bkt_ptr == 0) {
   9320                 
   9321                 /* OVERRIDE VRF Processing */ 
   9322 
   9323                 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t));
   9324                 _bcm_td2_alpm_lpm128_key_parse(unit, (uint32 *) lpm_entry, &lpm_cfg);
   9325                 (void) soc_alpm_128_lpm_vrf_get(unit, lpm_entry,
   9326                                                 &lpm_cfg.defip_vrf,
   9327                                                 &nh_ecmp_idx);
   9328                 _bcm_td2_alpm_lpm128_data_parse(unit, &lpm_cfg, &nh_ecmp_idx, lpm_entry);
   9329 
   9330                 lpm_cfg.defip_index = idx;
   9331                 
   9332                 if (trv_data->op_cb) {
   9333                     rv = (*trv_data->op_cb) (unit, (void *)trv_data,
   9334                                             (void *)&lpm_cfg,
   9335                                             (void *)&nh_ecmp_idx, &cmp_result);
   9336 #ifdef BCM_CB_ABORT_ON_ERR
   9337                     if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   9338                         break;
   9339                     }
   9340 #endif
   9341                 }
   9342             
   9343                 /* Skip second iteration for VRF OVERRIDE routes */
   9344                 tmp_idx++;
   9345 
   9346                 continue;
   9347             }
   9348 
   9349             /* get the bucket pointer from lpm mem  entry */
   9350             for (bkt_idx = 0; bkt_idx < bkt_count; bkt_idx++) {
   9351                 /* calculate bucket memory address */
   9352                 /* also increment so next bucket address can be calculated */
   9353                 bkt_addr = (entry_num << 16) | (bkt_ptr << 2) | 
   9354                            (bank_num & 0x3);
   9355                 /* read entry from bucket memory */
   9356                 raw_entry = soc_mem_table_idx_to_pointer(unit, L3_DEFIP_ALPM_RAWm,
   9357                         defip_alpm_raw_entry_t *, alpm_tbl_ptr, bkt_addr & 0xFFFF);
   9358                 _soc_alpm_raw_mem_read(unit, alpm_mem, raw_entry, entry_num, alpm_entry);
   9359 
   9360                 entry_num++; 
   9361                 if (entry_num == entry_count) {
   9362                     entry_num = 0;
   9363                     bank_num++;
   9364                     if (bank_num == bank_count) {
   9365                         bank_num = 0;
   9366                     }
   9367                 }
   9368                 if (!soc_mem_field32_get(unit, alpm_mem, alpm_entry, VALIDf)) {
   9369                     continue;
   9370                 }
   9371                 /* Zero destination buffer first. */
   9372                 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t));
   9373 
   9374                 /* Parse  the entry. */
   9375                 /* Fill entry ip address &  subnet mask. */
   9376                 _bcm_td2_alpm_ent128_key_parse(unit, alpm_mem,
   9377                                            (uint32 *) alpm_entry, &lpm_cfg);
   9378                 
   9379                 soc_alpm_128_lpm_vrf_get(unit, lpm_entry, &lpm_cfg.defip_vrf,
   9380                                         &cmp_result);
   9381 
   9382                 /* get associated data */
   9383                 _bcm_td2_alpm_ent128_data_parse(unit, alpm_mem, alpm_entry,
   9384                                                 &lpm_cfg, &nh_ecmp_idx);
   9385 
   9386                 if (!soc_feature(unit, soc_feature_alpm_hit_bits_not_support)) {
   9387                     int hit_offset;
   9388                     soc_field_t hit_field[4] = {HIT_0f, HIT_1f, HIT_2f, HIT_3f};
   9389                     hit_entry = soc_mem_table_idx_to_pointer(unit, L3_DEFIP_ALPM_HIT_ONLYm,
   9390                                 defip_alpm_hit_only_entry_t *, alpm_hit_tbl_ptr, (bkt_addr / 4));
   9391                     hit_offset = bkt_addr % 4;
   9392                     if (!ALPM_CTRL(unit).hit_bits_skip &&
   9393                         soc_mem_field32_get(unit, alpm_hit_mem, hit_entry, hit_field[hit_offset])) {
   9394                         lpm_cfg.defip_flags |= BCM_L3_HIT;
   9395                     }
   9396                 }
   9397 
   9398                 /* If protocol doesn't match skip the entry. */
   9399                 if ((lpm_cfg.defip_flags & BCM_L3_IP6) != ipv6) {
   9400                     continue;
   9401                 }
   9402 
   9403                 phy_idx = soc_alpm_physical_idx(unit, L3_DEFIP_PAIR_128m, idx, 1);
   9404                 phy_idx = SOC_ALPM_128_ADDR_LWR(unit, phy_idx ) << 1;
   9405                 lpm_cfg.defip_alpm_cookie = SOC_ALPM_DELETE_ALL | phy_idx;
   9406                 lpm_cfg.defip_index = bkt_addr;
   9407 
   9408                 /* Check if this is default route */
   9409                 /* Subnet length zero will indicate default route */
   9410                 if (0 == lpm_cfg.defip_sub_len) {
   9411                     if (def_arr_idx < SOC_VRF_MAX(unit)) {
   9412                         def_rte_arr[def_arr_idx].bkt_addr = bkt_addr;
   9413                         def_rte_arr[def_arr_idx].idx = idx;
   9414                         def_arr_idx ++;
   9415                     }
   9416                 } else {
   9417                     /* Execute operation routine if any. */
   9418                     if (trv_data->op_cb) {
   9419                         rv = (*trv_data->op_cb) (unit, (void *)trv_data,
   9420                                                 (void *)&lpm_cfg,
   9421                                                 (void *)&nh_ecmp_idx, &cmp_result);
   9422 #ifdef BCM_CB_ABORT_ON_ERR
   9423                         if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   9424                             break;
   9425                         }
   9426 #endif
   9427                     }
   9428                 }
   9429             }
   9430         }
   9431     }
   9432    
   9433     /* Process Default routes */
   9434     for (idx = 0; idx < def_arr_idx; idx++) {
   9435 
   9436         /* Calculate entry ofset. */
   9437         lpm_entry = soc_mem_table_idx_to_pointer(unit, L3_DEFIP_PAIR_128m,
   9438                                     defip_pair_128_entry_t *, lpm_tbl_ptr,
   9439                                     def_rte_arr[idx].idx);
   9440 
   9441         /* Make sure entry is valid. */
   9442         if (!soc_mem_field32_get(unit, pivot_mem, lpm_entry, VALID0_LWRf)) {
   9443             continue;
   9444         }
   9445 
   9446         bkt_addr = def_rte_arr[idx].bkt_addr;
   9447         
   9448         /* read entry from bucket memory */
   9449         raw_entry = soc_mem_table_idx_to_pointer(unit, L3_DEFIP_ALPM_RAWm,
   9450                 defip_alpm_raw_entry_t *, alpm_tbl_ptr, bkt_addr & 0xFFFF);
   9451         _soc_alpm_raw_mem_read(unit, alpm_mem, raw_entry, bkt_addr >> 16, alpm_entry);
   9452 
   9453         if (!soc_mem_field32_get(unit, alpm_mem, alpm_entry, VALIDf)) {
   9454             continue;
   9455         }
   9456 
   9457         /* Zero destination buffer first. */
   9458         sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t));
   9459 
   9460         phy_idx = soc_alpm_physical_idx(unit, L3_DEFIP_PAIR_128m,
   9461                                         def_rte_arr[idx].idx, 1);
   9462         phy_idx = SOC_ALPM_128_ADDR_LWR(unit, phy_idx) << 1;
   9463         lpm_cfg.defip_alpm_cookie = SOC_ALPM_DELETE_ALL | phy_idx;
   9464         lpm_cfg.defip_index = bkt_addr;
   9465 
   9466         /* Parse  the entry. */
   9467         soc_alpm_128_lpm_vrf_get(unit, lpm_entry, &lpm_cfg.defip_vrf,
   9468                                  &cmp_result);
   9469         /* Fill entry ip address & subnet mask. */
   9470         _bcm_td2_alpm_ent128_key_parse(unit, alpm_mem, alpm_entry, &lpm_cfg);
   9471 
   9472         _bcm_td2_alpm_ent128_data_parse(unit, alpm_mem, alpm_entry, &lpm_cfg,
   9473                                     &nh_ecmp_idx);
   9474 
   9475         /* If protocol doesn't match skip the entry. */
   9476         if ((lpm_cfg.defip_flags & BCM_L3_IP6) != ipv6) {
   9477             continue;
   9478         }
   9479 
   9480         /* Execute operation routine if any. */
   9481         if (trv_data->op_cb) {
   9482             rv = (*trv_data->op_cb) (unit, (void *)trv_data,
   9483                                     (void *)&lpm_cfg,
   9484                                     (void *)&nh_ecmp_idx, &cmp_result);
   9485 #ifdef BCM_CB_ABORT_ON_ERR
   9486             if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   9487                 break;
   9488             }
   9489 #endif
   9490         }
   9491     }
   9492 
   9493 error:
   9494     if (def_rte_arr != NULL) {
   9495         sal_free(def_rte_arr);
   9496     }
   9497     if (lpm_tbl_ptr != NULL) {
   9498         soc_cm_sfree(unit, lpm_tbl_ptr);
   9499     }
   9500     if (alpm_tbl_ptr != NULL) {
   9501         soc_cm_sfree(unit, alpm_tbl_ptr);
   9502     }
   9503     if (alpm_hit_tbl_ptr != NULL) {
   9504         soc_cm_sfree(unit, alpm_hit_tbl_ptr);
   9505     }
   9506     return (rv);
   9507 }
   9508 
   9509 /*
   9510  * Function:
   9511  *      _bcm_td2_alpm_update_match
   9512  * Purpose:
   9513  *      Update/Delete all entries in defip table matching a certain rule.
   9514  * Parameters:
   9515  *      unit     - (IN)SOC unit number.
   9516  *      trv_data - (IN)Delete pattern + compare,act,notify routines.  
   9517  * Returns:
   9518  *      BCM_E_XXX
   9519  */
   9520 int
   9521 _bcm_td2_alpm_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data)
   9522 {
   9523     uint32 ipv6 = 0;            /* Iterate over ipv6 only flag. */
   9524     int idx;                    /* Iteration index.             */
   9525     int phy_idx;                /* Iteration index.             */
   9526     int tmp_idx;                /* Iteration index.             */
   9527     int tmp_start;              /* Iteration start.             */
   9528     int tmp_end;                /* Iteration end.               */
   9529     int tmp_delta;              /* Iteration delta.             */
   9530     char *lpm_tbl_ptr = NULL;   /* Dma table pointer.           */
   9531     char *alpm_tbl_ptr = NULL;  /* Dma table pointer.           */
   9532     int nh_ecmp_idx;            /* Next hop/Ecmp group index.   */
   9533     int cmp_result;             /* Test routine result.         */
   9534     defip_entry_t *lpm_entry;   /* Hw entry buffer.             */
   9535     defip_entry_t lpm_entry_data; /* Hw entry buffer.           */
   9536     _bcm_defip_cfg_t lpm_cfg;   /* Buffer to fill route info.   */
   9537     int defip_table_size;       /* Defip table size.            */
   9538     int rv = BCM_E_NONE;        /* Operation return status.     */
   9539     char *alpm_hit_tbl_ptr = NULL;  /* Dma hit only table pointer.  */
   9540     int idx_start = 0;
   9541     int idx_end = 0, bkt_idx, bkt_count, bkt_ptr = 0, bkt_addr;
   9542     int entry_num, bank_num, entry_count, bank_count;
   9543     defip_alpm_ipv4_1_entry_t alpm_entry_v4;
   9544     defip_alpm_ipv6_64_1_entry_t alpm_entry_v6_64;
   9545     void *alpm_entry;
   9546     void *raw_entry ;
   9547     soc_mem_t alpm_mem;
   9548     void *hit_entry;
   9549     soc_mem_t alpm_hit_mem;
   9550     int step_count;
   9551     int def_arr_idx = 0;
   9552     int def_rte_arr_sz;
   9553     int flex;
   9554     typedef struct _alpm_def_route_info_s {
   9555         int idx;
   9556         int tmp_idx;
   9557         int bkt_addr;
   9558         defip_entry_t lpm_entry;
   9559     } _alpm_def_route_info_t;
   9560        
   9561     _alpm_def_route_info_t *def_rte_arr = NULL;
   9562 
   9563 #ifdef BCM_WARM_BOOT_SUPPORT
   9564     if (SOC_WARM_BOOT(unit)) {
   9565         if (soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, defip)) != 0) {
   9566             rv =_bcm_td2_alpm_warmboot_walk(unit, trv_data);
   9567             if (rv < 0) {
   9568                 LOG_CLI((BSL_META_U(unit,
   9569                                     "ERROR!  ALPM Warmboot recovery failed")));
   9570                 return (rv);
   9571             }
   9572         }
   9573         if (soc_mem_index_count(unit, L3_DEFIP_PAIR_128m) != 0) {
   9574             /* v6-128 entries */
   9575             rv = _bcm_td2_alpm_128_warmboot_walk(unit, trv_data);
   9576             if (rv < 0) {
   9577                 LOG_CLI((BSL_META_U(unit,
   9578                                     "ERROR!  ALPM Warmboot V6-128 recovery failed")));
   9579             }
   9580         }
   9581         return (rv);
   9582     }
   9583 #endif
   9584 
   9585     ipv6 = trv_data->flags & BCM_L3_IP6;
   9586 
   9587     if (ipv6 && soc_mem_index_count(unit, L3_DEFIP_PAIR_128m) != 0) {
   9588         /* first get v6-128 entries */
   9589         rv = _bcm_td2_alpm_128_update_match(unit, trv_data);
   9590 #ifdef BCM_CB_ABORT_ON_ERR
   9591         if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   9592             return rv;
   9593         }
   9594 #endif
   9595     }
   9596 
   9597     if (soc_mem_index_count(unit, BCM_XGS3_L3_MEM(unit, defip)) == 0) {
   9598         return BCM_E_NONE;
   9599     }
   9600 
   9601 
   9602     /* Table DMA the LPM table to software copy */
   9603 
   9604     alpm_mem = L3_DEFIP_ALPM_RAWm;
   9605     rv = bcm_xgs3_l3_tbl_dma(unit, alpm_mem,
   9606                              WORDS2BYTES(soc_mem_entry_words(unit, alpm_mem)),
   9607                              "alpm_tbl", &alpm_tbl_ptr, NULL);
   9608     if (BCM_FAILURE(rv)) {
   9609         goto error;
   9610     }
   9611 
   9612     rv = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, defip),
   9613                              BCM_XGS3_L3_ENT_SZ(unit, defip), "lpm_tbl",
   9614                              &lpm_tbl_ptr, &defip_table_size);
   9615     if (BCM_FAILURE(rv)) {
   9616         goto error;
   9617     }
   9618 
   9619     if (!soc_feature(unit, soc_feature_alpm_hit_bits_not_support)) {
   9620         alpm_hit_mem = L3_DEFIP_ALPM_HIT_ONLYm;
   9621         rv = bcm_xgs3_l3_tbl_dma(unit, alpm_hit_mem,
   9622                                  WORDS2BYTES(soc_mem_entry_words(unit, alpm_hit_mem)),
   9623                                  "alpm_hit_tbl", &alpm_hit_tbl_ptr, NULL);
   9624         if (BCM_FAILURE(rv)) {
   9625             goto error;
   9626         }
   9627     }
   9628 
   9629     /* Allocate memory to store default route meta data*/
   9630     def_rte_arr_sz = SOC_VRF_MAX(unit) * sizeof(_alpm_def_route_info_t);
   9631     def_rte_arr = sal_alloc(def_rte_arr_sz, "alpm_def_rte_arry"); 
   9632     if (NULL == def_rte_arr) {
   9633         rv = BCM_E_MEMORY;
   9634         goto error;
   9635     }
   9636     sal_memset(def_rte_arr, 0, def_rte_arr_sz);
   9637 
   9638     if (SOC_URPF_STATUS_GET(unit)) {
   9639         defip_table_size >>= 1;
   9640     }
   9641 
   9642     idx_end    = defip_table_size;
   9643     bank_num   = 0;
   9644     entry_num  = 0;
   9645     bank_count = 4;
   9646 
   9647     if (ipv6) {
   9648         if (SOC_ALPM_V6_SCALE_CHECK(unit, 1)) {
   9649             step_count = 2;
   9650         } else {
   9651             step_count = 1;
   9652         }
   9653     } else {
   9654         step_count = 2;
   9655     }
   9656 
   9657     /* Walk all lpm entries */
   9658     for (idx = (idx_end - 1); idx >= idx_start; idx--) {
   9659             /* Calculate entry ofset. */
   9660         lpm_entry =
   9661                 soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, defip),
   9662                                              defip_entry_t *, lpm_tbl_ptr, idx);
   9663         sal_memcpy (&lpm_entry_data, lpm_entry, sizeof (lpm_entry_data));
   9664 
   9665         if (ipv6 && (soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, MODE0_f(unit)) == 0)) {
   9666            /*
   9667             * Function called for IPv6 LPM/ALPM walk and LPM entry is IPv4; Continue;
   9668             */
   9669            continue;
   9670         }
   9671         
   9672         /* Each LPM index has two IPv4 entries*/
   9673         if (ipv6) {
   9674            tmp_start = 0;
   9675            tmp_end   = step_count;
   9676            tmp_delta = 1;
   9677         } else {
   9678            tmp_start = step_count - 1;
   9679            tmp_end   = -1;
   9680            tmp_delta = -1;
   9681         }
   9682 
   9683         for (tmp_idx = tmp_start; tmp_idx != tmp_end; tmp_idx += tmp_delta) {
   9684             if (!ipv6) {
   9685                if (tmp_idx) {
   9686                    soc_alpm_lpm_ip4entry1_to_0(unit, &lpm_entry_data, lpm_entry, TRUE);
   9687                } else {
   9688                    soc_alpm_lpm_ip4entry0_to_0(unit, &lpm_entry_data, lpm_entry, TRUE);
   9689                }
   9690             }
   9691 
   9692             /* Make sure entry is valid. */
   9693             if (!soc_L3_DEFIPm_field32_get(unit, lpm_entry, VALID0f)) {
   9694                 continue;
   9695             }
   9696 
   9697             /* Skip reserved ipmc entry */
   9698             if (soc_feature(unit, soc_feature_ipmc_defip)) {
   9699                 /* Skip reserved ipmc entry */
   9700                 int ipmc_index = 0;
   9701                 int ipmc_route = 0;
   9702                 if (soc_mem_field_valid(unit, L3_DEFIPm, MULTICAST_ROUTE0f)) {
   9703                     ipmc_route = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, MULTICAST_ROUTE0f);
   9704                 } else if (soc_mem_field_valid(unit, L3_DEFIPm, DATA_TYPE0f)) {
   9705                     if (soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, DATA_TYPE0f) == 2) {
   9706                         ipmc_route = 1;
   9707                     } else {
   9708                         ipmc_route = 0;
   9709                     }
   9710                 }
   9711 
   9712                 if (soc_feature(unit, soc_feature_generic_dest)) {
   9713                     uint32 dest_type = SOC_MEM_FIF_DEST_INVALID;
   9714                     uint32 dest_value = 0;
   9715                     dest_value = soc_mem_field32_dest_get(unit,
   9716                             L3_DEFIPm, lpm_entry,
   9717                             DESTINATION0f, &dest_type);
   9718                     if (dest_type == SOC_MEM_FIF_DEST_IPMC) {
   9719                         ipmc_index = dest_value;
   9720                     } else {
   9721                         ipmc_index = 0;
   9722                     }
   9723                 } else {
   9724                     ipmc_index = soc_mem_field32_get(unit, L3_DEFIPm,
   9725                                     lpm_entry, L3MC_INDEX0f);
   9726                 }
   9727 
   9728                 if (ipmc_route && (ipmc_index == 0)) {
   9729                     continue;
   9730                 }
   9731             }
   9732 
   9733             cmp_result = ipv6 ? 1 : 0;
   9734             if (cmp_result != (soc_mem_field32_get(unit, L3_DEFIPm,
   9735                                                 lpm_entry, MODE0_f(unit)))) {
   9736                 continue;
   9737             }
   9738 
   9739             soc_alpm_lpm_vrf_get(unit, lpm_entry, &lpm_cfg.defip_vrf, NULL);
   9740 
   9741 
   9742             if (ipv6 && tmp_idx) {
   9743                 bkt_ptr++;
   9744             } else {
   9745                 bkt_ptr = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry,
   9746                                           ALG_BKT_PTR0f);
   9747                 if (bkt_ptr == 0) {
   9748                     sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t));
   9749                     _bcm_td2_alpm_lpm_data_parse(unit, &lpm_cfg, &nh_ecmp_idx, lpm_entry);
   9750                     _bcm_td2_alpm_lpm_key_parse(unit, &lpm_cfg, lpm_entry);
   9751 
   9752                     lpm_cfg.defip_index = idx;
   9753 
   9754                     if (ipv6 == (lpm_cfg.defip_flags & BCM_L3_IP6)) {
   9755                         if (trv_data->op_cb) {
   9756                             rv = (*trv_data->op_cb) (unit, (void *)trv_data,
   9757                                                 (void *)&lpm_cfg,
   9758                                                 (void *)&nh_ecmp_idx, &cmp_result);
   9759 #ifdef BCM_CB_ABORT_ON_ERR
   9760                             if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   9761                                 break;
   9762                             }
   9763 #endif
   9764                         }
   9765                     }
   9766                     if (ipv6) {
   9767                         /* Skip IPv6 second iteration for TCAM routes */
   9768                         tmp_idx = tmp_end - tmp_delta;
   9769                     }
   9770                     continue;
   9771                 }
   9772 
   9773             }
   9774 
   9775             flex = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, ENTRY_VIEW0f);
   9776             if (ipv6) {
   9777                 if (flex) {
   9778                     alpm_mem = L3_DEFIP_ALPM_IPV6_64_1m;
   9779                     bkt_count = ALPM_IPV6_64_BKT_COUNT_FLEX;
   9780                     entry_count = 3;
   9781                     alpm_entry = &alpm_entry_v6_64;
   9782                 } else {
   9783                     alpm_mem = L3_DEFIP_ALPM_IPV6_64m;
   9784                     bkt_count = ALPM_IPV6_64_BKT_COUNT;
   9785                     entry_count = 4;
   9786                     alpm_entry = &alpm_entry_v6_64;
   9787                 }
   9788 
   9789             } else {
   9790                 if (flex) {
   9791                     alpm_mem = L3_DEFIP_ALPM_IPV4_1m;
   9792                     bkt_count = ALPM_IPV4_BKT_COUNT_FLEX;
   9793                     entry_count = 4;
   9794                     alpm_entry = &alpm_entry_v4;
   9795                 } else {
   9796                     alpm_mem = L3_DEFIP_ALPM_IPV4m;
   9797                     bkt_count = ALPM_IPV4_BKT_COUNT;
   9798                     entry_count = 6;
   9799                     alpm_entry = &alpm_entry_v4;
   9800                 }
   9801             }
   9802 
   9803             /* Get the bucket pointer from lpm mem entry */
   9804             for (bkt_idx = 0; bkt_idx < bkt_count; bkt_idx++) {
   9805                 /* Calculate bucket memory address */
   9806                 /* Increment so next bucket address can be calculated */
   9807                 bkt_addr = (entry_num << 16) | (bkt_ptr << 2) | 
   9808                            (bank_num & 0x3);
   9809 
   9810                 raw_entry = soc_mem_table_idx_to_pointer(unit, L3_DEFIP_ALPM_RAWm,
   9811                         defip_alpm_raw_entry_t *, alpm_tbl_ptr, bkt_addr & 0xFFFF);
   9812                 _soc_alpm_raw_mem_read(unit, alpm_mem, raw_entry, entry_num, alpm_entry);
   9813 
   9814                 entry_num++; 
   9815                 if (entry_num == entry_count) {
   9816                     entry_num = 0;
   9817                     bank_num++;
   9818                     if (bank_num == bank_count) {
   9819                         bank_num = 0;
   9820                     }
   9821                 }
   9822                 if (!soc_mem_field32_get(unit, alpm_mem, alpm_entry, VALIDf)) {
   9823                     continue;
   9824                 }
   9825 
   9826                 /* Zero destination buffer first. */
   9827                 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t));
   9828 
   9829                 /* Parse the entry. */
   9830                 _bcm_td2_alpm_ent_data_parse(unit, &lpm_cfg, &nh_ecmp_idx,
   9831                                         alpm_mem, alpm_entry);
   9832 
   9833                 if (!soc_feature(unit, soc_feature_alpm_hit_bits_not_support)) {
   9834                     int hit_offset;
   9835                     soc_field_t hit_field[4] = {HIT_0f, HIT_1f, HIT_2f, HIT_3f};
   9836                     hit_entry = soc_mem_table_idx_to_pointer(unit, L3_DEFIP_ALPM_HIT_ONLYm,
   9837                                 defip_alpm_hit_only_entry_t *, alpm_hit_tbl_ptr, (bkt_addr / 4));
   9838                     hit_offset = bkt_addr % 4;
   9839                     if (!ALPM_CTRL(unit).hit_bits_skip &&
   9840                         soc_mem_field32_get(unit, alpm_hit_mem, hit_entry, hit_field[hit_offset])) {
   9841                         lpm_cfg.defip_flags |= BCM_L3_HIT;
   9842                     }
   9843                 }
   9844 
   9845                 /* If protocol doesn't match skip the entry. */
   9846                 if ((lpm_cfg.defip_flags & BCM_L3_IP6) !=  ipv6) {
   9847                     continue;
   9848                 }
   9849                  
   9850                 /* Fill entry IP address and subnet mask. */
   9851                 _bcm_td2_alpm_ent_key_parse(unit, &lpm_cfg, lpm_entry,
   9852                                           alpm_mem, alpm_entry);
   9853 
   9854                 phy_idx = ipv6 ? idx: ((idx << 1) + tmp_idx);
   9855                 phy_idx = soc_alpm_physical_idx(unit, L3_DEFIPm, phy_idx, ipv6);
   9856                 phy_idx = phy_idx << (ipv6 ? 1 : 0);
   9857                 lpm_cfg.defip_alpm_cookie = SOC_ALPM_DELETE_ALL | phy_idx;
   9858                 lpm_cfg.defip_index = bkt_addr;
   9859 
   9860                 /* Check if this is default route */
   9861                 /* Subnet length zero will indicate default route */
   9862                 if (0 == lpm_cfg.defip_sub_len) {
   9863                     if (def_arr_idx < SOC_VRF_MAX(unit)) {
   9864                         def_rte_arr[def_arr_idx].bkt_addr = bkt_addr;
   9865                         def_rte_arr[def_arr_idx].idx = idx;
   9866                         def_rte_arr[def_arr_idx].tmp_idx = tmp_idx;
   9867                         sal_memcpy(&def_rte_arr[def_arr_idx].lpm_entry,
   9868                                    lpm_entry, sizeof(*lpm_entry));
   9869                         def_arr_idx ++;
   9870                     }
   9871                 } else {
   9872                     /* Execute operation routine if any. */
   9873                     if (trv_data->op_cb) {
   9874                         rv = (*trv_data->op_cb) (unit, (void *)trv_data,
   9875                                                 (void *)&lpm_cfg,
   9876                                                 (void *)&nh_ecmp_idx, &cmp_result);
   9877 #ifdef BCM_CB_ABORT_ON_ERR
   9878                         if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   9879                             break;
   9880                         }
   9881 #endif
   9882                     }
   9883                 }
   9884             }
   9885         }
   9886     }
   9887 
   9888     /* Process Default routes */
   9889     for (idx = 0; idx < def_arr_idx; idx++) {
   9890 
   9891         /* Calculate entry ofset. */
   9892         lpm_entry = &def_rte_arr[idx].lpm_entry;
   9893 
   9894         cmp_result = ipv6 ? 1 : 0;
   9895         if (cmp_result != (soc_mem_field32_get(unit, L3_DEFIPm,
   9896                                             lpm_entry, MODE0_f(unit)))) {
   9897             /*
   9898              * Function called for IPv6 LPM/ALPM walk and LPM entry is IPv4; 
   9899              * Continue;
   9900              */
   9901             continue;
   9902         }
   9903         flex = soc_mem_field32_get(unit, L3_DEFIPm, lpm_entry, ENTRY_VIEW0f);
   9904         if (ipv6) {
   9905             if (flex) {
   9906                 alpm_mem = L3_DEFIP_ALPM_IPV6_64_1m;
   9907                 alpm_entry = &alpm_entry_v6_64;
   9908             } else {
   9909                 alpm_mem = L3_DEFIP_ALPM_IPV6_64m;
   9910                 alpm_entry = &alpm_entry_v6_64;
   9911             }
   9912 
   9913         } else {
   9914             if (flex) {
   9915                 alpm_mem = L3_DEFIP_ALPM_IPV4_1m;
   9916                 alpm_entry = &alpm_entry_v4;
   9917             } else {
   9918                 alpm_mem = L3_DEFIP_ALPM_IPV4m;
   9919                 alpm_entry = &alpm_entry_v4;
   9920             }
   9921         }
   9922 
   9923         bkt_addr = def_rte_arr[idx].bkt_addr;
   9924         
   9925         /* read entry from bucket memory */
   9926         raw_entry = soc_mem_table_idx_to_pointer(unit, L3_DEFIP_ALPM_RAWm,
   9927                 defip_alpm_raw_entry_t *, alpm_tbl_ptr, bkt_addr & 0xFFFF);
   9928         _soc_alpm_raw_mem_read(unit, alpm_mem, raw_entry, bkt_addr >> 16, alpm_entry);
   9929 
   9930         if (!soc_mem_field32_get(unit, alpm_mem, alpm_entry, VALIDf)) {
   9931             continue;
   9932         }
   9933 
   9934         /* Zero destination buffer first. */
   9935         sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t));
   9936 
   9937         phy_idx = ipv6 ? def_rte_arr[idx].idx:
   9938                        ((def_rte_arr[idx].idx << 1) + def_rte_arr[idx].tmp_idx);
   9939         phy_idx = soc_alpm_physical_idx(unit, L3_DEFIPm, phy_idx, ipv6);
   9940         phy_idx = phy_idx << (ipv6 ? 1 : 0);
   9941         lpm_cfg.defip_alpm_cookie = SOC_ALPM_DELETE_ALL | phy_idx;
   9942         lpm_cfg.defip_index = bkt_addr;
   9943 
   9944         soc_alpm_lpm_vrf_get(unit, lpm_entry, &lpm_cfg.defip_vrf, NULL);
   9945         /* Parse  the entry. */
   9946         _bcm_td2_alpm_ent_data_parse(unit, &lpm_cfg, &nh_ecmp_idx,
   9947                                      alpm_mem, alpm_entry);
   9948 
   9949         /* If protocol doesn't match skip the entry. */
   9950         if ((lpm_cfg.defip_flags & BCM_L3_IP6) != ipv6) {
   9951             continue;
   9952         }
   9953 
   9954         /* Fill entry ip address & subnet mask. */
   9955         _bcm_td2_alpm_ent_key_parse(unit, &lpm_cfg, lpm_entry,
   9956                                     alpm_mem, alpm_entry);
   9957 
   9958         /* Execute operation routine if any. */
   9959         if (trv_data->op_cb) {
   9960             rv = (*trv_data->op_cb) (unit, (void *)trv_data,
   9961                                     (void *)&lpm_cfg,
   9962                                     (void *)&nh_ecmp_idx, &cmp_result);
   9963 #ifdef BCM_CB_ABORT_ON_ERR
   9964             if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   9965                 break;
   9966             }
   9967 #endif
   9968         }
   9969     }
   9970 
   9971 #ifdef ALPM_WARM_BOOT_DEBUG
   9972     soc_alpm_lpm_sw_dump(unit);
   9973 #endif /* ALPM_WARM_BOOT_DEBUG  */
   9974 
   9975 error:
   9976     if (def_rte_arr != NULL) {
   9977         sal_free(def_rte_arr);
   9978     }
   9979     if (lpm_tbl_ptr != NULL) {
   9980         soc_cm_sfree(unit, lpm_tbl_ptr);
   9981     }
   9982     if (alpm_tbl_ptr != NULL) {
   9983         soc_cm_sfree(unit, alpm_tbl_ptr);
   9984     }
   9985     if (alpm_hit_tbl_ptr != NULL) {
   9986         soc_cm_sfree(unit, alpm_hit_tbl_ptr);
   9987     }
   9988     return (rv);
   9989 }
   9990 
   9991 /*
   9992  * Function:
   9993  *      _bcm_td2_alpm_find
   9994  * Purpose:
   9995  *      Get an entry from DEFIP table.
   9996  * Parameters:
   9997  *      unit        - (IN)SOC unit number.
   9998  *      lpm_cfg     - (IN)Buffer to fill defip information. 
   9999  *      nh_ecmp_idx - (IN)Next hop or ecmp group index
  10000  * Returns:
  10001  *      BCM_E_XXX
  10002  */
  10003 int
  10004 _bcm_td2_alpm_find(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx)
  10005 {
  10006     defip_entry_t lpm_key;      /* Route lookup key.        */
  10007     defip_entry_t lpm_entry;    /* Search result buffer.    */
  10008     defip_pair_128_entry_t lpm_128_key;
  10009     defip_pair_128_entry_t lpm_128_entry;
  10010     int do_urpf = 0;            /* Find uRPF region */
  10011     int rv;                     /* Operation return status. */
  10012     uint32 flags = 0;
  10013     soc_mem_t mem;
  10014     int lpm_mode, tmp;
  10015     uint32 rval;
  10016 
  10017     /* Input parameters check */
  10018     if (NULL == lpm_cfg) {
  10019         return (BCM_E_PARAM);
  10020     }
  10021 
  10022     SOC_IF_ERROR_RETURN(READ_L3_DEFIP_RPF_CONTROLr(unit, &rval));
  10023     lpm_mode  = soc_reg_field_get(unit, L3_DEFIP_RPF_CONTROLr, rval, LPM_MODEf);
  10024     /* Not supported in Legacy LPM mode */
  10025     if (lpm_mode == 0) {
  10026         return (BCM_E_UNAVAIL);
  10027     }
  10028     
  10029     /* Zero buffers. */
  10030     sal_memset(&lpm_entry, 0, sizeof(defip_entry_t));
  10031     sal_memset(&lpm_key, 0, sizeof(defip_entry_t));
  10032     sal_memset(&lpm_128_entry, 0, sizeof(defip_pair_128_entry_t));
  10033     sal_memset(&lpm_128_key, 0, sizeof(defip_pair_128_entry_t));
  10034 
  10035     /* Default value */
  10036     mem = L3_DEFIPm;
  10037     if ((lpm_cfg->defip_flags & BCM_L3_IP6)) {
  10038         if (soc_mem_index_count(unit, L3_DEFIP_PAIR_128m) > 0) {
  10039             mem = L3_DEFIP_PAIR_128m;
  10040         }
  10041     }
  10042     
  10043     switch (mem) {
  10044     case L3_DEFIP_PAIR_128m:
  10045         /* Initialize lkup key. */
  10046         BCM_IF_ERROR_RETURN(_bcm_td2_alpm_lpm128_init(unit, lpm_cfg,
  10047                                             &lpm_128_key, 0, &flags));
  10048         /* Perform hw lookup. */
  10049         rv = soc_alpm_128_find_best_match(unit, &lpm_128_key, &lpm_128_entry, 
  10050                                           &lpm_cfg->defip_index, do_urpf);
  10051         BCM_IF_ERROR_RETURN(rv);
  10052 
  10053         /* Parse hw buffer to defip entry. */
  10054         /* OVERRIDE VRF Processing */ 
  10055         _bcm_td2_alpm_lpm128_key_parse(unit, (uint32 *)&lpm_128_entry, lpm_cfg);
  10056         soc_alpm_128_lpm_vrf_get(unit, &lpm_128_entry, &lpm_cfg->defip_vrf, &tmp);
  10057         _bcm_td2_alpm_lpm128_data_parse(unit, lpm_cfg, nh_ecmp_idx, &lpm_128_entry);
  10058 
  10059         break;
  10060     default:
  10061         /* Initialize lkup key. */
  10062         BCM_IF_ERROR_RETURN(_bcm_td2_alpm_lpm_ent_init(unit, lpm_cfg, &lpm_key, 0,
  10063                                                    &flags));
  10064         /* Perform hw lookup. */
  10065         rv = soc_alpm_find_best_match(unit, &lpm_key, &lpm_entry, 
  10066                                       &lpm_cfg->defip_index, do_urpf);
  10067         BCM_IF_ERROR_RETURN(rv);
  10068     
  10069         /* Parse hw buffer to defip entry. */
  10070         _bcm_td2_alpm_lpm_data_parse(unit, lpm_cfg, nh_ecmp_idx, &lpm_entry);
  10071         _bcm_td2_alpm_lpm_key_parse(unit, lpm_cfg, &lpm_entry);
  10072         
  10073         break;
  10074     }
  10075     
  10076     return (BCM_E_NONE);
  10077 }
  10078 
  10079 #if defined(BCM_TOMAHAWK3_SUPPORT)
  10080 /*
  10081  * Function:
  10082  *      _bcm_th3_alpm_clear_hit
  10083  * Purpose:
  10084  *      Clear prefix entry hit bit.
  10085  * Parameters:
  10086  *      u       - (IN)SOC unit number.
  10087  *      lpm_cfg - (IN)Found LPM Defip config info
  10088  * Returns:
  10089  *      BCM_E_XXX
  10090  */
  10091 STATIC int _bcm_th3_alpm_clear_hit(int u,
  10092 						    _bcm_defip_cfg_t * lpm_cfg)
  10093 {
  10094 	return bcm_esw_alpm_clear_hit(u, lpm_cfg);
  10095 }
  10096 
  10097 /*
  10098  * Function:
  10099  *      _bcm_th3_alpm_get
  10100  * Purpose:
  10101  *      Get an entry from DEFIP table.
  10102  * Parameters:
  10103  *      unit        - (IN)SOC unit number.
  10104  *      lpm_cfg     - (IN)Buffer to fill defip information.
  10105  *      nh_ecmp_idx - (IN)Next hop or ecmp group index
  10106  * Returns:
  10107  *      BCM_E_XXX
  10108  */
  10109     int bcm_th3_alpm_get(
  10110     int unit,
  10111     _bcm_defip_cfg_t * lpm_cfg,
  10112     int *nh_ecmp_idx)
  10113     {
  10114         int clear_hit;          /* Clear hit indicator.  */
  10115         int alpm_global_routes = 0;
  10116 
  10117         /*
  10118          * Input parameters check 
  10119          */
  10120         if (lpm_cfg == NULL)
  10121         {
  10122             return (BCM_E_PARAM);
  10123         }
  10124 
  10125 #if 0
  10126         BCM_IF_ERROR_RETURN(
  10127             _bcm_td2_alpm_l3_defip_mem_get(unit, lpm_cfg->defip_flags,
  10128                                            lpm_cfg->defip_sub_len, NULL));
  10129 #else
  10130         if ((lpm_cfg->defip_sub_len > 64 &&
  10131              (soc_mem_index_count(unit, L3_DEFIP_PAIR_LEVEL1m) <= 0)) ||
  10132             (!(lpm_cfg->defip_flags & BCM_L3_IP6) &&
  10133              (BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) == 0))
  10134            ) {
  10135             return BCM_E_PARAM;
  10136         }
  10137 #endif
  10138         /*
  10139          * Check if clear hit bit required. 
  10140          */
  10141         clear_hit = lpm_cfg->defip_flags & BCM_L3_HIT_CLEAR;
  10142 
  10143         /*
  10144          * Perform hw lookup. 
  10145          */
  10146         BCM_IF_ERROR_RETURN(bcm_esw_alpm_lookup(unit, lpm_cfg));
  10147 
  10148         if (nh_ecmp_idx)
  10149         {
  10150             *nh_ecmp_idx = lpm_cfg->defip_ecmp_index;
  10151         }
  10152 
  10153         if (!ALPM_HIT_SKIP(unit) &&
  10154             !(lpm_cfg->defip_flags & BCM_L3_IPMC) &&
  10155             _soc_alpm_mode[unit] != 0 &&
  10156             (lpm_cfg->defip_vrf == BCM_L3_VRF_OVERRIDE ||
  10157              (lpm_cfg->defip_vrf == BCM_L3_VRF_GLOBAL &&
  10158               _soc_alpm_mode[unit] == 3))) {
  10159             alpm_global_routes = 1;
  10160         }
  10161 
  10162         if (!ALPM_HIT_SKIP(unit) &&
  10163             (lpm_cfg->defip_flags & BCM_L3_IPMC)) {
  10164             alpm_global_routes = 1;
  10165         }
  10166 
  10167         /*
  10168          * Clear the HIT bit 
  10169          */
  10170         if (clear_hit && !alpm_global_routes)
  10171         {
  10172             BCM_IF_ERROR_RETURN(_bcm_th3_alpm_clear_hit(unit, lpm_cfg));
  10173         }
  10174 
  10175         return (BCM_E_NONE);
  10176     }
  10177 
  10178 /*
  10179  * Function:
  10180  *      _bcm_th3_alpm_add
  10181  * Purpose:
  10182  *      Add an entry to DEFIP table.
  10183  * Parameters:
  10184  *      unit        - (IN)SOC unit number.
  10185  *      lpm_cfg     - (IN)Buffer to fill defip information.
  10186  *      nh_ecmp_idx - (IN)Next hop or ecmp group index.
  10187  * Returns:
  10188  *      BCM_E_XXX
  10189  */
  10190     int bcm_th3_alpm_add(
  10191     int unit,
  10192     _bcm_defip_cfg_t * lpm_cfg,
  10193     int nh_ecmp_idx)
  10194     {
  10195         int rv = 0;             /* Operation return status. */
  10196         /*
  10197          * Input parameters check 
  10198          */
  10199         if (lpm_cfg == NULL)
  10200         {
  10201             return (BCM_E_PARAM);
  10202         }
  10203 #if 0
  10204         BCM_IF_ERROR_RETURN(
  10205             _bcm_td2_alpm_l3_defip_mem_get(unit, lpm_cfg->defip_flags,
  10206                                            lpm_cfg->defip_sub_len, NULL));
  10207 #else
  10208         if ((lpm_cfg->defip_sub_len > 64 &&
  10209              (soc_mem_index_count(unit, L3_DEFIP_PAIR_LEVEL1m) <= 0)) ||
  10210             (!(lpm_cfg->defip_flags & BCM_L3_IP6) &&
  10211              (BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) == 0))
  10212            ) {
  10213             return BCM_E_PARAM;
  10214         }
  10215 #endif
  10216         /*
  10217          * Write buffer to hw. 
  10218          */
  10219         lpm_cfg->defip_ecmp_index = nh_ecmp_idx;
  10220         rv = bcm_esw_alpm_insert(unit, lpm_cfg);
  10221 
  10222         alpm_trace_log(unit, ALPM_TRACE_OP_ADD, lpm_cfg, nh_ecmp_idx, rv);
  10223         /*
  10224          * If new route added increment total number of routes.  
  10225          */
  10226         /*
  10227          * Lack of index indicates a new route. 
  10228          */
  10229         if ((rv >= 0) && !(lpm_cfg->defip_alpm_cookie & SOC_ALPM_LOOKUP_HIT))
  10230         {
  10231             BCM_XGS3_L3_DEFIP_CNT_INC(unit, (lpm_cfg->defip_flags & BCM_L3_IP6));
  10232         }
  10233 
  10234         return rv;
  10235     }
  10236 
  10237 /*
  10238  * Function:
  10239  *      _bcm_th3_alpm_del
  10240  * Purpose:
  10241  *      Delete an entry from DEFIP table.
  10242  * Parameters:
  10243  *      unit    - (IN)SOC unit number.
  10244  *      lpm_cfg - (IN)Buffer to fill defip information.
  10245  * Returns:
  10246  *      BCM_E_XXX
  10247  */
  10248     int bcm_th3_alpm_del(
  10249     int unit,
  10250     _bcm_defip_cfg_t * lpm_cfg)
  10251     {
  10252         int rv = 0;             /* Operation return status. */
  10253         /*
  10254          * Input parameters check 
  10255          */
  10256         if (lpm_cfg == NULL)
  10257         {
  10258             return (BCM_E_PARAM);
  10259         }
  10260 
  10261          /* For fast delete_all, we skip delete route and only do delete ecmp_nh_idx */
  10262         if (lpm_cfg->fast_delete_all) {
  10263             return rv;
  10264         }
  10265 #if 0
  10266         BCM_IF_ERROR_RETURN(
  10267             _bcm_td2_alpm_l3_defip_mem_get(unit, lpm_cfg->defip_flags,
  10268                                            lpm_cfg->defip_sub_len, NULL));
  10269 #else
  10270         if ((lpm_cfg->defip_sub_len > 64 &&
  10271              (soc_mem_index_count(unit, L3_DEFIP_PAIR_LEVEL1m) <= 0)) ||
  10272             (!(lpm_cfg->defip_flags & BCM_L3_IP6) &&
  10273              (BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) == 0))
  10274            ) {
  10275             return BCM_E_PARAM;
  10276         }
  10277 #endif
  10278         /*
  10279          * Write buffer to hw. 
  10280          */
  10281         rv = bcm_esw_alpm_delete(unit, lpm_cfg);
  10282 
  10283         alpm_trace_log(unit, ALPM_TRACE_OP_DELETE, lpm_cfg, -1, rv);
  10284         /*
  10285          * If route deleted, decrement total number of routes.  
  10286          */
  10287         if (rv >= 0)
  10288         {
  10289             BCM_XGS3_L3_DEFIP_CNT_DEC(unit, lpm_cfg->defip_flags & BCM_L3_IP6);
  10290         }
  10291         return rv;
  10292     }
  10293 
  10294 /*
  10295  * Function:
  10296  *      _bcm_th3_alpm_update_match
  10297  * Purpose:
  10298  *      Update/Delete all entries in defip table matching a certain rule.
  10299  * Parameters:
  10300  *      unit     - (IN)SOC unit number.
  10301  *      trv_data - (IN)Delete pattern + compare,act,notify routines.
  10302  * Returns:
  10303  *      BCM_E_XXX
  10304  */
  10305     int bcm_th3_alpm_update_match(
  10306     int unit,
  10307     _bcm_l3_trvrs_data_t * trv_data)
  10308     {
  10309         int rv = BCM_E_NONE;
  10310 
  10311         rv = bcm_esw_alpm_update_match(unit, trv_data);
  10312         return (rv);
  10313     }
  10314 #endif /* BCM_TOMAHAWK3_SUPPORT */
  10315 
  10316 #if defined(BCM_TOMAHAWK_SUPPORT)
  10317 /*
  10318  * Function:
  10319  *      _bcm_th_alpm_clear_hit
  10320  * Purpose:
  10321  *      Clear prefix entry hit bit.
  10322  * Parameters:
  10323  *      u       - (IN)SOC unit number.
  10324  *      lpm_cfg - (IN)Found LPM Defip config info
  10325  * Returns:
  10326  *      BCM_E_XXX
  10327  */
  10328 STATIC int 
  10329 _bcm_th_alpm_clear_hit(int u, _bcm_defip_cfg_t * lpm_cfg)
  10330 {
  10331     return bcm_esw_alpm_clear_hit(u, lpm_cfg);
  10332 }
  10333 
  10334 /*
  10335  * Function:
  10336  *      bcm_th_alpm_get
  10337  * Purpose:
  10338  *      Get an entry from DEFIP table.
  10339  * Parameters:
  10340  *      unit        - (IN)SOC unit number.
  10341  *      lpm_cfg     - (IN)Buffer to fill defip information.
  10342  *      nh_ecmp_idx - (IN)Next hop or ecmp group index
  10343  * Returns:
  10344  *      BCM_E_XXX
  10345  */
  10346 int
  10347 bcm_th_alpm_get(int unit, _bcm_defip_cfg_t * lpm_cfg, int *nh_ecmp_idx)
  10348 {
  10349     int clear_hit;          /* Clear hit indicator.  */
  10350     soc_mem_t mem;
  10351     int alpm_global_routes = 0;
  10352     /*
  10353      * Input parameters check
  10354      */
  10355     if (lpm_cfg == NULL) {
  10356         return (BCM_E_PARAM);
  10357     }
  10358 
  10359     BCM_IF_ERROR_RETURN(
  10360         _bcm_td2_alpm_l3_defip_mem_get(unit, lpm_cfg->defip_flags,
  10361                                        lpm_cfg->defip_sub_len, &mem));
  10362 
  10363     /*
  10364      * Check if clear hit bit required. 
  10365      */
  10366     clear_hit = lpm_cfg->defip_flags & BCM_L3_HIT_CLEAR;
  10367 
  10368     /*
  10369      * Perform hw lookup.
  10370      */
  10371     BCM_IF_ERROR_RETURN(bcm_esw_alpm_lookup(unit, lpm_cfg));
  10372 
  10373     if (nh_ecmp_idx) {
  10374         *nh_ecmp_idx = lpm_cfg->defip_ecmp_index;
  10375     }
  10376 
  10377     if (!ALPM_HIT_SKIP(unit) &&
  10378         !(lpm_cfg->defip_flags & BCM_L3_IPMC) &&
  10379         _soc_alpm_mode[unit] != 0 &&
  10380         (lpm_cfg->defip_vrf == BCM_L3_VRF_OVERRIDE ||
  10381          (lpm_cfg->defip_vrf == BCM_L3_VRF_GLOBAL &&
  10382           _soc_alpm_mode[unit] == 3))) {
  10383         alpm_global_routes = 1;
  10384     }
  10385 
  10386     if (!ALPM_HIT_SKIP(unit) &&
  10387         (lpm_cfg->defip_flags & BCM_L3_IPMC)) {
  10388         alpm_global_routes = 1;
  10389     }
  10390 
  10391     /*
  10392      * Clear the HIT bit
  10393      */
  10394     if (clear_hit && !alpm_global_routes) {
  10395         BCM_IF_ERROR_RETURN(_bcm_th_alpm_clear_hit(unit, lpm_cfg));
  10396     }
  10397 
  10398     return (BCM_E_NONE);
  10399 }
  10400 
  10401 /*
  10402  * Function:
  10403  *      bcm_th_alpm_add
  10404  * Purpose:
  10405  *      Add an entry to DEFIP table.
  10406  * Parameters:
  10407  *      unit        - (IN)SOC unit number.
  10408  *      lpm_cfg     - (IN)Buffer to fill defip information.
  10409  *      nh_ecmp_idx - (IN)Next hop or ecmp group index.
  10410  * Returns:
  10411  *      BCM_E_XXX
  10412  */
  10413 int 
  10414 bcm_th_alpm_add(int unit, _bcm_defip_cfg_t * lpm_cfg, int nh_ecmp_idx)
  10415 {
  10416     int rv = 0;             /* Operation return status. */
  10417     soc_mem_t mem;
  10418 
  10419     /*
  10420      * Input parameters check 
  10421      */
  10422     if (lpm_cfg == NULL) {
  10423         return (BCM_E_PARAM);
  10424     }
  10425 
  10426     BCM_IF_ERROR_RETURN(
  10427         _bcm_td2_alpm_l3_defip_mem_get(unit, lpm_cfg->defip_flags,
  10428                                        lpm_cfg->defip_sub_len, &mem));
  10429 
  10430     /*
  10431      * Write buffer to hw.
  10432      */
  10433     lpm_cfg->defip_ecmp_index = nh_ecmp_idx;
  10434     rv = bcm_esw_alpm_insert(unit, lpm_cfg);
  10435 
  10436     alpm_trace_log(unit, ALPM_TRACE_OP_ADD, lpm_cfg, nh_ecmp_idx, rv);
  10437 
  10438     /*
  10439      * If new route added increment total number of routes.  
  10440      */
  10441     /*
  10442      * Lack of index indicates a new route. 
  10443      */
  10444     if ((rv >= 0) && !(lpm_cfg->defip_alpm_cookie & SOC_ALPM_LOOKUP_HIT ||
  10445                        lpm_cfg->defip_alpm_cookie & SOC_ALPM_LPM_LOOKUP_HIT)) {
  10446         BCM_XGS3_L3_DEFIP_CNT_INC(unit, (lpm_cfg->defip_flags & BCM_L3_IP6));
  10447     }
  10448 
  10449     return rv;
  10450 }
  10451 
  10452 /*
  10453  * Function:
  10454  *      bcm_th_alpm_del
  10455  * Purpose:
  10456  *      Delete an entry from DEFIP table.
  10457  * Parameters:
  10458  *      unit    - (IN)SOC unit number.
  10459  *      lpm_cfg - (IN)Buffer to fill defip information.
  10460  * Returns:
  10461  *      BCM_E_XXX
  10462  */
  10463 int 
  10464 bcm_th_alpm_del(int unit, _bcm_defip_cfg_t * lpm_cfg)
  10465 {
  10466     int rv = 0;             /* Operation return status. */
  10467     soc_mem_t mem;
  10468 
  10469     /*
  10470      * Input parameters check 
  10471      */
  10472     if (lpm_cfg == NULL) {
  10473         return (BCM_E_PARAM);
  10474     }
  10475 
  10476     BCM_IF_ERROR_RETURN(
  10477         _bcm_td2_alpm_l3_defip_mem_get(unit, lpm_cfg->defip_flags,
  10478                                        lpm_cfg->defip_sub_len, &mem));
  10479 
  10480     /*
  10481      * Write buffer to hw. 
  10482      */
  10483     rv = bcm_esw_alpm_delete(unit, lpm_cfg);
  10484 
  10485     alpm_trace_log(unit, ALPM_TRACE_OP_DELETE, lpm_cfg, -1, rv);
  10486 
  10487     /*
  10488      * If route deleted, decrement total number of routes.
  10489      */
  10490     if (rv >= 0) {
  10491         BCM_XGS3_L3_DEFIP_CNT_DEC(unit, lpm_cfg->defip_flags & BCM_L3_IP6);
  10492     }
  10493     return rv;
  10494 }
  10495 
  10496 /*
  10497  * Function:
  10498  *      bcm_th_alpm_update_match
  10499  * Purpose:
  10500  *      Update/Delete all entries in defip table matching a certain rule.
  10501  * Parameters:
  10502  *      unit     - (IN)SOC unit number.
  10503  *      trv_data - (IN)Delete pattern + compare,act,notify routines.
  10504  * Returns:
  10505  *      BCM_E_XXX
  10506  */
  10507 int 
  10508 bcm_th_alpm_update_match(int unit, _bcm_l3_trvrs_data_t * trv_data)
  10509 {
  10510     int rv = BCM_E_NONE;
  10511 
  10512     rv = bcm_esw_alpm_update_match(unit, trv_data);
  10513     return (rv);
  10514 }
  10515 #endif /* BCM_TOMAHAWK_SUPPORT */
  10516 
  10517 #endif /* ALPM_ENABLE */
  10518 
  10519 /*
  10520  * Function:
  10521  *      bcm_td2_ecmp_rh_deinit
  10522  * Purpose:
  10523  *      Deallocate ECMP resilient hashing internal data structures
  10524  * Parameters:
  10525  *      unit - (IN) SOC unit number.
  10526  * Returns:
  10527  *      BCM_E_xxx
  10528  */
  10529 void
  10530 bcm_td2_ecmp_rh_deinit(int unit)
  10531 {
  10532     if (_td2_ecmp_rh_info[unit]) {
  10533         if (_td2_ecmp_rh_info[unit]->ecmp_rh_flowset_block_bitmap) {
  10534             sal_free(_td2_ecmp_rh_info[unit]->ecmp_rh_flowset_block_bitmap);
  10535             _td2_ecmp_rh_info[unit]->ecmp_rh_flowset_block_bitmap = NULL;
  10536         }
  10537         sal_free(_td2_ecmp_rh_info[unit]);
  10538         _td2_ecmp_rh_info[unit] = NULL;
  10539     }
  10540 }
  10541 
  10542 /*
  10543  * Function:
  10544  *      bcm_td2_ecmp_rh_init
  10545  * Purpose:
  10546  *      Initialize ECMP resilient hashing internal data structures
  10547  * Parameters:
  10548  *      unit - (IN) SOC unit number.
  10549  * Returns:
  10550  *      BCM_E_xxx
  10551  */
  10552 int
  10553 bcm_td2_ecmp_rh_init(int unit)
  10554 {
  10555     int num_ecmp_rh_flowset_entries;
  10556 
  10557     bcm_td2_ecmp_rh_deinit(unit);
  10558 
  10559     _td2_ecmp_rh_info[unit] = sal_alloc(sizeof(_td2_ecmp_rh_info_t),
  10560             "_td2_ecmp_rh_info");
  10561     if (_td2_ecmp_rh_info[unit] == NULL) {
  10562         return BCM_E_MEMORY;
  10563     }
  10564     sal_memset(_td2_ecmp_rh_info[unit], 0, sizeof(_td2_ecmp_rh_info_t));
  10565 
  10566     /* The LAG and ECMP resilient hash features share the same flow set table.
  10567      * The table can be configured in one of 3 modes:
  10568      * - dedicated to LAG resilient hashing,
  10569      * - dedicated to ECMP resilient hashing,
  10570      * - split evenly between LAG and ECMP resilient hashing.
  10571      * The mode was configured during Trident2 initialization.
  10572      */
  10573     num_ecmp_rh_flowset_entries = soc_mem_index_count(unit, RH_ECMP_FLOWSETm);
  10574 
  10575 #ifdef BCM_MONTEREY_SUPPORT
  10576     if (SOC_IS_MONTEREY(unit)) {
  10577         _td2_ecmp_rh_info[unit]->ecmp_block_size = 3;
  10578         _td2_ecmp_rh_info[unit]->ecmp_rand_seed_shift = 22;
  10579     } else
  10580 #endif
  10581     {
  10582         _td2_ecmp_rh_info[unit]->ecmp_block_size = 6;
  10583         _td2_ecmp_rh_info[unit]->ecmp_rand_seed_shift = 16;
  10584     }
  10585 
  10586     /* Each bit in ecmp_rh_flowset_block_bitmap corresponds to a block of 64
  10587      * resilient hashing flow set table entries.
  10588      */
  10589     _td2_ecmp_rh_info[unit]->num_ecmp_rh_flowset_blocks =
  10590         num_ecmp_rh_flowset_entries >> _td2_ecmp_rh_info[unit]->ecmp_block_size;
  10591     if (_td2_ecmp_rh_info[unit]->num_ecmp_rh_flowset_blocks > 0) {
  10592         _td2_ecmp_rh_info[unit]->ecmp_rh_flowset_block_bitmap = 
  10593             sal_alloc(SHR_BITALLOCSIZE(_td2_ecmp_rh_info[unit]->
  10594                         num_ecmp_rh_flowset_blocks),
  10595                     "ecmp_rh_flowset_block_bitmap");
  10596         if (_td2_ecmp_rh_info[unit]->ecmp_rh_flowset_block_bitmap == NULL) {
  10597             bcm_td2_ecmp_rh_deinit(unit);
  10598             return BCM_E_MEMORY;
  10599         }
  10600         sal_memset(_td2_ecmp_rh_info[unit]->ecmp_rh_flowset_block_bitmap, 0,
  10601                 SHR_BITALLOCSIZE(_td2_ecmp_rh_info[unit]->
  10602                     num_ecmp_rh_flowset_blocks));
  10603     }
  10604 
  10605     /* Set the seed for the pseudo-random number generator */
  10606     _td2_ecmp_rh_info[unit]->ecmp_rh_rand_seed = sal_time_usecs();
  10607 
  10608     /* Clear flow set table entries */
  10609     SOC_IF_ERROR_RETURN
  10610         (soc_mem_clear(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ALL, TRUE));
  10611     
  10612     return BCM_E_NONE;
  10613 }
  10614 
  10615 /*
  10616  * Function:
  10617  *      _bcm_td2_ecmp_rh_dynamic_size_encode
  10618  * Purpose:
  10619  *      Encode ECMP resilient hashing flow set size.
  10620  * Parameters:
  10621  *      dynamic_size - (IN) Number of flow sets.
  10622  *      encoded_value - (OUT) Encoded value.
  10623  * Returns:
  10624  *      BCM_E_xxx
  10625  */
  10626 STATIC int
  10627 _bcm_td2_ecmp_rh_dynamic_size_encode(int unit, int dynamic_size, int *encoded_value)
  10628 {
  10629 #ifdef BCM_MONTEREY_SUPPORT
  10630     if (SOC_IS_MONTEREY(unit)) {
  10631         return _bcm_monterey_ecmp_rh_dynamic_size_encode(dynamic_size,
  10632                                                         encoded_value);
  10633     }
  10634 #endif
  10635     switch (dynamic_size) {
  10636         case 64:
  10637             *encoded_value = 1;
  10638             break;
  10639         case 128:
  10640             *encoded_value = 2;
  10641             break;
  10642         case 256:
  10643             *encoded_value = 3;
  10644             break;
  10645         case 512:
  10646             *encoded_value = 4;
  10647             break;
  10648         case 1024:
  10649             *encoded_value = 5;
  10650             break;
  10651         case 2048:
  10652             *encoded_value = 6;
  10653             break;
  10654         case 4096:
  10655             *encoded_value = 7;
  10656             break;
  10657         case 8192:
  10658             *encoded_value = 8;
  10659             break;
  10660         case 16384:
  10661             *encoded_value = 9;
  10662             break;
  10663         case 32768:
  10664             *encoded_value = 10;
  10665             break;
  10666         case 65536:
  10667             *encoded_value = 11;
  10668             break;
  10669         default:
  10670             return BCM_E_PARAM;
  10671     }
  10672 
  10673     return BCM_E_NONE;
  10674 }
  10675 
  10676 /*
  10677  * Function:
  10678  *      _bcm_td2_ecmp_rh_dynamic_size_decode
  10679  * Purpose:
  10680  *      Decode ECMP resilient hashing flow set size.
  10681  * Parameters:
  10682  *      encoded_value - (IN) Encoded value.
  10683  *      dynamic_size - (OUT) Number of flow sets.
  10684  * Returns:
  10685  *      BCM_E_xxx
  10686  */
  10687 STATIC int
  10688 _bcm_td2_ecmp_rh_dynamic_size_decode(int unit, int encoded_value, int *dynamic_size)
  10689 {
  10690 #ifdef BCM_MONTEREY_SUPPORT
  10691     if (SOC_IS_MONTEREY(unit)) {
  10692         return _bcm_monterey_ecmp_rh_dynamic_size_decode(encoded_value,
  10693                                                         dynamic_size);
  10694     }
  10695 #endif
  10696 #ifdef BCM_HELIX5_SUPPORT
  10697     if (SOC_IS_HELIX5(unit)) {
  10698         return _bcm_hx5_ecmp_rh_dynamic_size_decode(encoded_value,
  10699                                                     dynamic_size);
  10700     }
  10701 #endif /* BCM_HELIX5_SUPPORT */
  10702     switch (encoded_value) {
  10703         case 1:
  10704             *dynamic_size = 64;
  10705             break;
  10706         case 2:
  10707             *dynamic_size = 128;
  10708             break;
  10709         case 3:
  10710             *dynamic_size = 256;
  10711             break;
  10712         case 4:
  10713             *dynamic_size = 512;
  10714             break;
  10715         case 5:
  10716             *dynamic_size = 1024;
  10717             break;
  10718         case 6:
  10719             *dynamic_size = 2048;
  10720             break;
  10721         case 7:
  10722             *dynamic_size = 4096;
  10723             break;
  10724         case 8:
  10725             *dynamic_size = 8192;
  10726             break;
  10727         case 9:
  10728             *dynamic_size = 16384;
  10729             break;
  10730         case 10:
  10731             *dynamic_size = 32768;
  10732             break;
  10733         case 11:
  10734             *dynamic_size = 65536;
  10735             break;
  10736         default:
  10737             return BCM_E_INTERNAL;
  10738     }
  10739 
  10740     return BCM_E_NONE;
  10741 }
  10742 
  10743 /*
  10744  * Function:
  10745  *      _bcm_td2_ecmp_rh_free_resource
  10746  * Purpose:
  10747  *      Free resources for an ECMP resilient hashing group.
  10748  * Parameters:
  10749  *      unit  - (IN) SOC unit number. 
  10750  *      ecmp_group - (IN) ECMP group ID.
  10751  * Returns:
  10752  *      BCM_E_xxx
  10753  */
  10754 STATIC int
  10755 _bcm_td2_ecmp_rh_free_resource(int unit, int ecmp_group)
  10756 {
  10757     int rv = BCM_E_NONE;
  10758     ecmp_count_entry_t ecmp_count_entry;
  10759     int flow_set_size;
  10760     int entry_base_ptr;
  10761     int num_entries;
  10762     int block_base_ptr;
  10763     int num_blocks;
  10764     int alloc_size;
  10765     uint32 *buf_ptr = NULL;
  10766     int index_min, index_max, enhanced_hashing = 1;
  10767     soc_field_t enhanced_hashing_fld;
  10768     uint32 rval;
  10769 
  10770     if (soc_reg_field_valid(unit, ENHANCED_HASHING_CONTROLr, RH_DLB_SELECTIONf)) {
  10771         SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROLr(unit, &rval));
  10772         if (0 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROLr, rval,
  10773                 RH_DLB_SELECTIONf)) {
  10774            /* ECMP resilient hashing is not enabled chip-wide. */
  10775             return BCM_E_NONE;
  10776         }
  10777     }
  10778 
  10779     SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY,
  10780                 ecmp_group, &ecmp_count_entry));
  10781     if (soc_feature(unit, soc_feature_td3_style_dlb_rh)){
  10782         enhanced_hashing_fld = LB_MODEf;
  10783         enhanced_hashing = 4;
  10784     } else {
  10785         enhanced_hashing_fld = ENHANCED_HASHING_ENABLEf;
  10786     }
  10787     if (soc_L3_ECMP_COUNTm_field32_get(unit,
  10788             &ecmp_count_entry, enhanced_hashing_fld)!= enhanced_hashing) {
  10789         /* Either (1) resilient hashing is not enabled on this ECMP
  10790          * group, or (2) resilient hashing is enabled with no members.
  10791          * For case (2), L3_ECMP_COUNT.FLOW_SET_SIZE needs to be cleared.
  10792          */
  10793         soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_count_entry,
  10794                 RH_FLOW_SET_SIZEf, 0);
  10795         SOC_IF_ERROR_RETURN(WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL,
  10796                     ecmp_group, &ecmp_count_entry));
  10797         return BCM_E_NONE;
  10798     }
  10799     flow_set_size = soc_L3_ECMP_COUNTm_field32_get(unit,
  10800             &ecmp_count_entry, RH_FLOW_SET_SIZEf);
  10801     entry_base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit,
  10802             &ecmp_count_entry, RH_FLOW_SET_BASEf);
  10803 
  10804     /* Clear resilient hashing fields */
  10805     soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_count_entry,
  10806            enhanced_hashing_fld, 0);
  10807     soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_count_entry,
  10808             RH_FLOW_SET_BASEf, 0);
  10809     soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_count_entry,
  10810             RH_FLOW_SET_SIZEf, 0);
  10811     SOC_IF_ERROR_RETURN(WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL,
  10812                 ecmp_group, &ecmp_count_entry));
  10813 
  10814     /* Clear flow set table entries */
  10815     BCM_IF_ERROR_RETURN
  10816         (_bcm_td2_ecmp_rh_dynamic_size_decode(unit, flow_set_size, &num_entries));
  10817     alloc_size = num_entries * sizeof(rh_ecmp_flowset_entry_t);
  10818     buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_ECMP_FLOWSET entries");
  10819     if (NULL == buf_ptr) {
  10820         return BCM_E_MEMORY;
  10821     }
  10822     sal_memset(buf_ptr, 0, alloc_size);
  10823     index_min = entry_base_ptr;
  10824     index_max = index_min + num_entries - 1;
  10825     rv = soc_mem_write_range(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ALL,
  10826             index_min, index_max, buf_ptr);
  10827     if (SOC_FAILURE(rv)) {
  10828         soc_cm_sfree(unit, buf_ptr);
  10829         return rv;
  10830     }
  10831     soc_cm_sfree(unit, buf_ptr);
  10832 
  10833     /* Free flow set table resources */
  10834     block_base_ptr = entry_base_ptr >> \
  10835                      _td2_ecmp_rh_info[unit]->ecmp_block_size ;
  10836     num_blocks = num_entries >> \
  10837                  _td2_ecmp_rh_info[unit]->ecmp_block_size;
  10838     _BCM_ECMP_RH_FLOWSET_BLOCK_USED_CLR_RANGE(unit, block_base_ptr, num_blocks);
  10839 
  10840 
  10841 #ifdef BCM_TRIDENT3_SUPPORT
  10842     if (soc_feature(unit, soc_feature_td3_dlb)) {
  10843         ecmp_grp_enhanced_hashing[unit][ecmp_group] = 0;
  10844     }
  10845 #endif
  10846     return BCM_E_NONE;
  10847 }
  10848 
  10849 /*
  10850  * Function:
  10851  *      _bcm_td2_ecmp_rh_dynamic_size_set
  10852  * Purpose:
  10853  *      Set the dynamic size for an ECMP resilient hashing group with
  10854  *      no members.
  10855  * Parameters:
  10856  *      unit - (IN) SOC unit number. 
  10857  *      ecmp_group - (IN) ECMP group ID.
  10858  *      dynamic_size - (IN) Number of flow sets.
  10859  * Returns:
  10860  *      BCM_E_xxx
  10861  */
  10862 STATIC int
  10863 _bcm_td2_ecmp_rh_dynamic_size_set(int unit, int ecmp_group, int dynamic_size)
  10864 {
  10865     ecmp_count_entry_t ecmp_count_entry;
  10866     int flow_set_size, enhanced_hashing = 1;
  10867     soc_field_t enhanced_hashing_fld;
  10868 
  10869     SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group,
  10870                 &ecmp_count_entry));
  10871     if (soc_feature(unit, soc_feature_td3_style_dlb_rh)){
  10872        enhanced_hashing_fld = LB_MODEf;
  10873       enhanced_hashing = 4;
  10874     } else {
  10875        enhanced_hashing_fld = ENHANCED_HASHING_ENABLEf;
  10876     }
  10877     if (soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry,
  10878                enhanced_hashing_fld) == enhanced_hashing) {
  10879         /* Not expecting resilient hashing to be enabled */
  10880         return BCM_E_INTERNAL;
  10881     }
  10882 
  10883     BCM_IF_ERROR_RETURN
  10884         (_bcm_td2_ecmp_rh_dynamic_size_encode(unit, dynamic_size, &flow_set_size));
  10885     soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_count_entry, RH_FLOW_SET_SIZEf,
  10886             flow_set_size);
  10887     SOC_IF_ERROR_RETURN(WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL, ecmp_group,
  10888                 &ecmp_count_entry));
  10889 
  10890     return BCM_E_NONE;
  10891 }
  10892 
  10893 /*
  10894  * Function:
  10895  *      _bcm_td2_ecmp_rh_rand_get
  10896  * Purpose:
  10897  *      Get a random number between 0 and the given max value.
  10898  * Parameters:
  10899  *      unit - (IN) SOC unit number. 
  10900  *      rand_max - (IN) Maximum random number.
  10901  *      rand_num - (OUT) Random number.
  10902  * Returns:
  10903  *      BCM_E_xxx
  10904  * Notes:
  10905  *      This procedure uses the pseudo-random number generator algorithm
  10906  *      suggested by the C standard.
  10907  */
  10908 STATIC int
  10909 _bcm_td2_ecmp_rh_rand_get(int unit, int rand_max, int *rand_num)
  10910 {
  10911     int modulus;
  10912     int rand_seed_shift;
  10913 
  10914     if (rand_max < 0) {
  10915         return BCM_E_PARAM;
  10916     }
  10917 
  10918     if (NULL == rand_num) {
  10919         return BCM_E_PARAM;
  10920     }
  10921 
  10922     /* Make sure the modulus does not exceed limit. For instance,
  10923      * if the 32-bit rand_seed is shifted to the right by 16 bits before
  10924      * the modulo operation, the modulus should not exceed 1 << 16.
  10925      */
  10926     modulus = rand_max + 1;
  10927     rand_seed_shift = _td2_ecmp_rh_info[unit]->ecmp_rand_seed_shift;
  10928     if (modulus > (1 << (32 - rand_seed_shift))) {
  10929         return BCM_E_PARAM;
  10930     }
  10931 
  10932     _td2_ecmp_rh_info[unit]->ecmp_rh_rand_seed =
  10933         _td2_ecmp_rh_info[unit]->ecmp_rh_rand_seed * 1103515245 + 12345;
  10934 
  10935     *rand_num = (_td2_ecmp_rh_info[unit]->ecmp_rh_rand_seed >> rand_seed_shift) %
  10936                 modulus;
  10937 
  10938     return BCM_E_NONE;
  10939 }
  10940 
  10941 /*
  10942  * Function:
  10943  *      _bcm_td2_ecmp_rh_member_choose
  10944  * Purpose:
  10945  *      Choose a member of the ECMP group.
  10946  * Parameters:
  10947  *      unit - (IN) SOC unit number. 
  10948  *      num_members - (IN) Number of members to choose from.
  10949  *      entry_count_arr   - (IN/OUT) An array keeping track of how many
  10950  *                                   flow set entries have been assigned
  10951  *                                   to each member.
  10952  *      max_entry_count   - (IN/OUT) The maximum number of flow set entries
  10953  *                                   that can be assigned to a member. 
  10954  *      chosen_index      - (OUT) The index of the chosen member.
  10955  * Returns:
  10956  *      BCM_E_xxx
  10957  */
  10958 STATIC int
  10959 _bcm_td2_ecmp_rh_member_choose(int unit, int num_members, int *entry_count_arr,
  10960         int *max_entry_count, int *chosen_index)
  10961 {
  10962     int member_index;
  10963     int next_index;
  10964 
  10965     *chosen_index = 0;
  10966 
  10967     /* Choose a random member index */
  10968     BCM_IF_ERROR_RETURN(_bcm_td2_ecmp_rh_rand_get(unit, num_members - 1,
  10969                 &member_index));
  10970 
  10971     if (entry_count_arr[member_index] < *max_entry_count) {
  10972         entry_count_arr[member_index]++;
  10973         *chosen_index = member_index;
  10974     } else {
  10975         /* The randomly chosen member has reached the maximum
  10976          * flow set entry count. Choose the next member that
  10977          * has not reached the maximum entry count.
  10978          */
  10979         next_index = (member_index + 1) % num_members;
  10980         while (next_index != member_index) {
  10981             if (entry_count_arr[next_index] < *max_entry_count) {
  10982                 entry_count_arr[next_index]++;
  10983                 *chosen_index = next_index;
  10984                 break;
  10985             } else {
  10986                 next_index = (next_index + 1) % num_members;
  10987             }
  10988         }
  10989         if (next_index == member_index) {
  10990             /* All members have reached the maximum flow set entry
  10991              * count. This scenario occurs when dividing the number of
  10992              * flow set entries by the number of members results
  10993              * in a non-zero remainder. The remainder flow set entries
  10994              * will be distributed among members, at most 1 remainder
  10995              * entry per member.
  10996              */
  10997             (*max_entry_count)++;
  10998             if (entry_count_arr[member_index] < *max_entry_count) {
  10999                 entry_count_arr[member_index]++;
  11000                 *chosen_index = member_index;
  11001             } else {
  11002                 /* It's possible that the member's entry count equals
  11003                  * to the incremented value of max_entry_count, when
  11004                  * this procedure is invoked by
  11005                  * _bcm_td2_ecmp_rh_populate_empty_entries.
  11006                  */
  11007                 next_index = (member_index + 1) % num_members;
  11008                 while (next_index != member_index) {
  11009                     if (entry_count_arr[next_index] < *max_entry_count) {
  11010                         entry_count_arr[next_index]++;
  11011                         *chosen_index = next_index;
  11012                         break;
  11013                     } else {
  11014                         next_index = (next_index + 1) % num_members;
  11015                     }
  11016                 }
  11017                 if (next_index == member_index) {
  11018                     return BCM_E_INTERNAL;
  11019                 }
  11020             }
  11021         }
  11022     }
  11023 
  11024     return BCM_E_NONE;
  11025 }
  11026 
  11027 /*
  11028  * Function:
  11029  *      _bcm_td2_ecmp_rh_set
  11030  * Purpose:
  11031  *      Configure an ECMP resilient hashing group.
  11032  * Parameters:
  11033  *      unit       - (IN) SOC unit number. 
  11034  *      ecmp       - (IN) ECMP group info.
  11035  *      intf_count - (IN) Number of elements in intf_array.
  11036  *      intf_array - (IN) Array of Egress forwarding objects.
  11037  * Returns:
  11038  *      BCM_E_xxx
  11039  */
  11040 STATIC int
  11041 _bcm_td2_ecmp_rh_set(int unit,
  11042         bcm_l3_egress_ecmp_t *ecmp,
  11043         int intf_count,
  11044         bcm_if_t *intf_array)
  11045 {
  11046     int rv = BCM_E_NONE;
  11047     int ecmp_group;
  11048     int num_blocks;
  11049     int total_blocks;
  11050     int max_block_base_ptr;
  11051     int block_base_ptr = 0;
  11052     int entry_base_ptr;
  11053     SHR_BITDCL occupied;
  11054     int alloc_size;
  11055     uint32 *buf_ptr = NULL;
  11056     int *entry_count_arr = NULL;
  11057     int max_entry_count;
  11058     int chosen_index;
  11059     int i;
  11060     rh_ecmp_flowset_entry_t *flowset_entry;
  11061     int offset;
  11062     int next_hop_index;
  11063     int index_min, index_max;
  11064     ecmp_count_entry_t ecmp_count_entry;
  11065     int flow_set_size, enhanced_hashing = 1;
  11066 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
  11067     _bcm_l3_bookkeeping_t *l3_bk_info = &_bcm_l3_bk_info[unit];
  11068 #endif
  11069     soc_field_t enhanced_hashing_fld;
  11070 
  11071     if (ecmp == NULL ||
  11072             ecmp->dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) {
  11073         return BCM_E_PARAM;
  11074     }
  11075 
  11076     if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp->ecmp_intf)) {
  11077         ecmp_group = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  11078     } else {
  11079         return BCM_E_PARAM;
  11080     }
  11081 
  11082     if (intf_count > 0 && intf_array == NULL) {
  11083         return BCM_E_PARAM;
  11084     }
  11085 
  11086     if (intf_count == 0) {
  11087         /* Store the dynamic_size in hardware */
  11088         BCM_IF_ERROR_RETURN(_bcm_td2_ecmp_rh_dynamic_size_set(unit,
  11089                     ecmp_group, ecmp->dynamic_size));
  11090         return BCM_E_NONE;
  11091     }
  11092 
  11093     /* Find a contiguous region of flow set table that's large
  11094      * enough to hold the requested number of flow sets.
  11095      * The flow set table is allocated in 64-entry blocks.
  11096      */
  11097     num_blocks = ecmp->dynamic_size >> _td2_ecmp_rh_info[unit]->ecmp_block_size;
  11098     total_blocks = _td2_ecmp_rh_info[unit]->num_ecmp_rh_flowset_blocks;
  11099     LOG_DEBUG(BSL_LS_SOC_L3, (BSL_META_U(unit,
  11100         "Total_blocks = %d , num_blocks = %d\n "), total_blocks, num_blocks));
  11101 
  11102     if (num_blocks > total_blocks) {
  11103         return BCM_E_RESOURCE;
  11104     }
  11105     max_block_base_ptr = total_blocks - num_blocks;
  11106 
  11107     /* 
  11108      * In case of Riot or Multi-Layer ECMP, RH_ECMP_FLOWSET table is divided into two halves.
  11109      * One half goes to overlay and other goes to underlay range.
  11110      * When ECMP is created then user tells the software that which range
  11111      * should be used. SDK will test the blocks only in that range.
  11112      */ 
  11113 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
  11114     if (
  11115 #if defined(BCM_RIOT_SUPPORT)
  11116         (l3_bk_info->riot_enable) ||
  11117 #endif
  11118         BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) {
  11119         if (ecmp->ecmp_group_flags & BCM_L3_ECMP_OVERLAY) {
  11120             block_base_ptr = 0;
  11121             max_block_base_ptr = (l3_bk_info->l3_ecmp_rh_overlay_entries >> \
  11122                                   _td2_ecmp_rh_info[unit]->ecmp_block_size)
  11123                                   - num_blocks;
  11124             LOG_DEBUG(BSL_LS_SOC_L3, (BSL_META_U(unit,
  11125                 "Total_blocks = %d , num_blocks = %d\n "),
  11126                 total_blocks, num_blocks));
  11127 
  11128         } else {
  11129             block_base_ptr = (l3_bk_info->l3_ecmp_rh_overlay_entries >> \
  11130                               _td2_ecmp_rh_info[unit]->ecmp_block_size);
  11131             max_block_base_ptr = total_blocks;
  11132         }
  11133     }
  11134 #endif
  11135     for (; block_base_ptr <= max_block_base_ptr; block_base_ptr++) {
  11136         /* Check if the contiguous region of flow set table from
  11137          * block_base_ptr to (block_base_ptr + num_blocks - 1) is free. 
  11138          */
  11139         _BCM_ECMP_RH_FLOWSET_BLOCK_TEST_RANGE(unit, block_base_ptr, num_blocks,
  11140                 occupied); 
  11141         if (!occupied) {
  11142             break;
  11143         }
  11144     }
  11145     if (block_base_ptr > max_block_base_ptr) {
  11146         /* A contiguous region of the desired size could not be found in
  11147          * flow set table.
  11148          */
  11149         return BCM_E_RESOURCE;
  11150     }
  11151 #ifdef BCM_TRIDENT3_SUPPORT
  11152     if (soc_feature(unit, soc_feature_td3_style_dlb_rh)){
  11153         if (soc_mem_index_count(unit, RH_ECMP_FLOWSETm)) {
  11154             SOC_IF_ERROR_RETURN(soc_reg_field32_modify(unit, ENHANCED_HASHING_CONTROLr,
  11155                          REG_PORT_ANY, RH_DLB_SELECTIONf, 1));
  11156 
  11157         }
  11158     }
  11159 #endif
  11160 
  11161     /* Configure flow set table */
  11162     alloc_size = ecmp->dynamic_size * sizeof(rh_ecmp_flowset_entry_t);
  11163     buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_ECMP_FLOWSET entries");
  11164     if (NULL == buf_ptr) {
  11165         return BCM_E_MEMORY;
  11166     }
  11167     sal_memset(buf_ptr, 0, alloc_size);
  11168 
  11169     entry_count_arr = sal_alloc(sizeof(int) * intf_count,
  11170             "ECMP RH entry count array");
  11171     if (NULL == entry_count_arr) {
  11172         soc_cm_sfree(unit, buf_ptr);
  11173         return BCM_E_MEMORY;
  11174     }
  11175     sal_memset(entry_count_arr, 0, sizeof(int) * intf_count);
  11176     max_entry_count = ecmp->dynamic_size / intf_count;
  11177 
  11178     for (i = 0; i < ecmp->dynamic_size; i++) {
  11179         /* Choose a member of the ECMP */
  11180         rv = _bcm_td2_ecmp_rh_member_choose(unit, intf_count,
  11181                 entry_count_arr, &max_entry_count, &chosen_index);
  11182         if (BCM_FAILURE(rv)) {
  11183             soc_cm_sfree(unit, buf_ptr);
  11184             sal_free(entry_count_arr);
  11185             return rv;
  11186         }
  11187 
  11188         /* Set flow set entry */
  11189         flowset_entry = soc_mem_table_idx_to_pointer(unit,
  11190                 RH_ECMP_FLOWSETm, rh_ecmp_flowset_entry_t *, buf_ptr, i);
  11191         soc_mem_field32_set(unit, RH_ECMP_FLOWSETm, flowset_entry, VALIDf, 1);
  11192         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit,
  11193                     intf_array[chosen_index])) {
  11194             offset = BCM_XGS3_EGRESS_IDX_MIN(unit);
  11195         } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit,
  11196                     intf_array[chosen_index])) {
  11197             offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  11198         } else {
  11199             soc_cm_sfree(unit, buf_ptr);
  11200             sal_free(entry_count_arr);
  11201             return BCM_E_PARAM;
  11202         }
  11203         next_hop_index = intf_array[chosen_index] - offset;
  11204         soc_mem_field32_set(unit, RH_ECMP_FLOWSETm, flowset_entry,
  11205                 NEXT_HOP_INDEXf, next_hop_index);
  11206     }
  11207 
  11208     entry_base_ptr = block_base_ptr << _td2_ecmp_rh_info[unit]->ecmp_block_size;
  11209     index_min = entry_base_ptr;
  11210     index_max = index_min + ecmp->dynamic_size - 1;
  11211     rv = soc_mem_write_range(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ALL,
  11212             index_min, index_max, buf_ptr);
  11213     if (SOC_FAILURE(rv)) {
  11214         soc_cm_sfree(unit, buf_ptr);
  11215         sal_free(entry_count_arr);
  11216         return rv;
  11217     }
  11218     soc_cm_sfree(unit, buf_ptr);
  11219     sal_free(entry_count_arr);
  11220 
  11221     _BCM_ECMP_RH_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr, num_blocks);
  11222 
  11223     /* Update ECMP group table */
  11224     SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group,
  11225                 &ecmp_count_entry));
  11226     if (soc_feature(unit, soc_feature_td3_style_dlb_rh)){
  11227         enhanced_hashing_fld = LB_MODEf;
  11228         enhanced_hashing = 4;
  11229     } else {
  11230         enhanced_hashing_fld = ENHANCED_HASHING_ENABLEf;
  11231     }
  11232     soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_count_entry,
  11233            enhanced_hashing_fld, enhanced_hashing);
  11234     soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_count_entry,
  11235             RH_FLOW_SET_BASEf, entry_base_ptr);
  11236     BCM_IF_ERROR_RETURN(_bcm_td2_ecmp_rh_dynamic_size_encode(
  11237                 unit, ecmp->dynamic_size, &flow_set_size));
  11238     soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_count_entry,
  11239             RH_FLOW_SET_SIZEf, flow_set_size);
  11240     SOC_IF_ERROR_RETURN(WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL, ecmp_group,
  11241                 &ecmp_count_entry));
  11242 
  11243 #ifdef BCM_TRIDENT3_SUPPORT
  11244     if (soc_feature(unit, soc_feature_td3_dlb)) {
  11245         ecmp_grp_enhanced_hashing[unit][ecmp_group] = 1;
  11246     }
  11247 #endif
  11248     return BCM_E_NONE;
  11249 }
  11250 
  11251 /*
  11252  * Function:
  11253  *      _bcm_td2_ecmp_rh_member_replica_find
  11254  * Purpose:
  11255  *      For each member in the member_array, find others members
  11256  *      who share the same next hop index.
  11257  * Parameters:
  11258  *      unit - (IN) SOC unit number.
  11259  *      num_members - (IN) Number of members.
  11260  *      member_array - (IN/OUT) Array of members.
  11261  * Returns:
  11262  *      BCM_E_XXX
  11263  */
  11264 STATIC int
  11265 _bcm_td2_ecmp_rh_member_replica_find(int unit, int num_members,
  11266         _td2_ecmp_rh_member_t *member_array)
  11267 {
  11268     int i, k;
  11269 
  11270     if (num_members < 1) {
  11271         return BCM_E_PARAM;
  11272     }
  11273     if (NULL == member_array) {
  11274         return BCM_E_PARAM;
  11275     }
  11276 
  11277     for (i = 0; i < num_members - 1; i++) {
  11278         if (member_array[i].replica_id == 0) {
  11279             /* replica_id == 0 indicates first replica.
  11280              * Search for other replicas in subsequent members.
  11281              */
  11282             for (k = i + 1; k < num_members; k++) {
  11283                 if (member_array[k].nh_index == member_array[i].nh_index) {
  11284                     /* Replica found. Assign replica id. */
  11285                     member_array[k].replica_id = member_array[i].num_replica;
  11286 
  11287                     /* For non-first replicas, set non-applicable fields to -1. */
  11288                     member_array[k].num_replica = -1;
  11289                     member_array[k].next_replica_id = -1;
  11290 
  11291                     /* Increment the num_replica field of the first replica */
  11292                     member_array[i].num_replica++;
  11293                 }
  11294             }
  11295         }
  11296     }
  11297 
  11298     return BCM_E_NONE;
  11299 }
  11300 
  11301 /*
  11302  * Function:
  11303  *      _bcm_td2_ecmp_rh_member_id_buf_assign
  11304  * Purpose:
  11305  *      For each entry in the flow set entry buffer, match its next hop
  11306  *      index against the next hop index of a member, then assign the
  11307  *      matching member's member ID to the entry.
  11308  * Parameters:
  11309  *      unit - (IN) SOC unit number.
  11310  *      num_members - (IN) Number of members.
  11311  *      member_array - (IN/OUT) Array of members.
  11312  *      num_entries - (IN) Number of flow set entries in buffer.
  11313  *      flowset_buf - (IN) Flow set entry buffer.
  11314  *      member_id_buf - (OUT) Member ID buffer.
  11315  * Returns:
  11316  *      BCM_E_XXX
  11317  */
  11318 STATIC int
  11319 _bcm_td2_ecmp_rh_member_id_buf_assign(int unit, int num_members,
  11320         _td2_ecmp_rh_member_t *member_array, int num_entries,
  11321         uint32 *flowset_buf, int *member_id_buf)
  11322 {
  11323     int i, k, m;
  11324     rh_ecmp_flowset_entry_t *flowset_entry;
  11325     int next_hop_index;
  11326 
  11327     for (i = 0; i < num_entries; i++) {
  11328         flowset_entry = soc_mem_table_idx_to_pointer(unit,
  11329                 RH_ECMP_FLOWSETm, rh_ecmp_flowset_entry_t *, flowset_buf, i);
  11330         if (!soc_mem_field32_get(unit, RH_ECMP_FLOWSETm, flowset_entry,
  11331                     VALIDf)) {
  11332             return BCM_E_INTERNAL;
  11333         }
  11334         next_hop_index = soc_mem_field32_get(unit, RH_ECMP_FLOWSETm,
  11335                 flowset_entry, NEXT_HOP_INDEXf);
  11336 
  11337         /* Search the member_array for matching next hop index */
  11338         for (k = 0; k < num_members; k++) {
  11339             if (member_array[k].nh_index == next_hop_index) {
  11340                 if (member_array[k].num_replica == 1) {
  11341                     /* The next hop index is not shared by other members. */
  11342                     member_id_buf[i] = member_array[k].member_id;
  11343                     break;
  11344                 }
  11345 
  11346                 /* Else there are more than one members sharing the next
  11347                  * hop index. Assign the member ID of the replica
  11348                  * indicated by next_replica_id.
  11349                  */
  11350                 for (m = k; m < num_members; m++) {
  11351                     if ((member_array[m].nh_index == next_hop_index) &&
  11352                         (member_array[m].replica_id == member_array[k].next_replica_id)) {
  11353                         member_id_buf[i] = member_array[m].member_id;
  11354                         break;
  11355                     }
  11356                 }
  11357                 if (m == num_members) {
  11358                     /* Cannot find a matching replica */
  11359                     return BCM_E_INTERNAL;
  11360                 }
  11361 
  11362                 /* Increment the next_replica_id field of the first replica */
  11363                 member_array[k].next_replica_id = (member_array[k].next_replica_id + 1) %
  11364                     member_array[k].num_replica;
  11365 
  11366                 break;
  11367             }
  11368         }
  11369         if (k == num_members) {
  11370             /* Cannot find a member with matching next hop index */
  11371             return BCM_E_INTERNAL;
  11372         }
  11373     }
  11374 
  11375     return BCM_E_NONE;
  11376 }
  11377 
  11378 /*
  11379  * Function:
  11380  *      _bcm_td2_ecmp_rh_add_rebalance
  11381  * Purpose:
  11382  *      Re-balance flow set entries from existing members to the new member.
  11383  *      For example, if the number of flow set entries is 64, and the number of
  11384  *      existing members is 6, then each existing member has between 10 and 11
  11385  *      entries. The entries should be re-assigned from the 6 existing members
  11386  *      to the new member such that each member will end up with between 9 and
  11387  *      10 entries.
  11388  * Parameters:
  11389  *      unit - (IN) SOC unit number.
  11390  *      num_entries - (IN) Number of flow set entries in buffer.
  11391  *      flowset_buf - (IN/OUT) Flow set entry buffer.
  11392  *      member_id_buf - (IN/OUT) Member ID buffer.
  11393  *      num_members - (IN) Number of members in member_array.
  11394  *      member_array - (IN) Array of existing members.
  11395  *      entry_count_array - (IN/OUT) Array of entry counts of existing members.
  11396  *      new_member - (IN) The member to be added.
  11397  *      entry_count - (OUT) Entry count of the new member.
  11398  * Returns:
  11399  *      BCM_E_XXX
  11400  */
  11401 STATIC int
  11402 _bcm_td2_ecmp_rh_add_rebalance(int unit,
  11403         int num_entries, uint32 *flowset_buf, int *member_id_buf,
  11404         int num_members, _td2_ecmp_rh_member_t *member_array,
  11405         int *entry_count_array,
  11406         _td2_ecmp_rh_member_t *new_member, int *entry_count)
  11407 {
  11408     int lower_bound, upper_bound;
  11409     int threshold;
  11410     int entry_index, next_entry_index;
  11411     rh_ecmp_flowset_entry_t *flowset_entry;
  11412     int member_id;
  11413     int is_new_member;
  11414     int member_index = 0;
  11415 
  11416     if (num_entries < 1) {
  11417         return BCM_E_PARAM;
  11418     }
  11419     if (NULL == flowset_buf || NULL == member_id_buf) {
  11420         return BCM_E_PARAM;
  11421     }
  11422     if (num_members < 1) {
  11423         return BCM_E_PARAM;
  11424     }
  11425     if (NULL == member_array) {
  11426         return BCM_E_PARAM;
  11427     }
  11428     if (NULL == entry_count_array) {
  11429         return BCM_E_PARAM;
  11430     }
  11431     if (NULL == new_member) {
  11432         return BCM_E_PARAM;
  11433     }
  11434     if (NULL == entry_count) {
  11435         return BCM_E_PARAM;
  11436     }
  11437 
  11438     lower_bound = num_entries / (num_members + 1);
  11439     upper_bound = (num_entries % (num_members + 1)) ?
  11440                   (lower_bound + 1) : lower_bound;
  11441     threshold = upper_bound;
  11442     *entry_count = 0;
  11443     while (*entry_count < lower_bound) {
  11444         /* Pick a random entry in the flow set entry buffer */
  11445         BCM_IF_ERROR_RETURN
  11446             (_bcm_td2_ecmp_rh_rand_get(unit, num_entries - 1, &entry_index));
  11447         flowset_entry = soc_mem_table_idx_to_pointer(unit, RH_ECMP_FLOWSETm,
  11448                 rh_ecmp_flowset_entry_t *, flowset_buf, entry_index);
  11449         member_id = member_id_buf[entry_index];
  11450 
  11451         /* Determine if the randomly picked entry contains the new member.
  11452          * If not, determine the existing member index.
  11453          */
  11454         if (member_id == new_member->member_id) {
  11455             is_new_member = TRUE;
  11456         } else {
  11457             is_new_member = FALSE;
  11458 
  11459             /* In the member_array, it's assumed that each array element's
  11460              * member_id matches the element's array index.
  11461              */
  11462             member_index = member_id;
  11463         }
  11464 
  11465         if (!is_new_member && (entry_count_array[member_index] > threshold)) {
  11466             soc_mem_field32_set(unit, RH_ECMP_FLOWSETm, flowset_entry,
  11467                     NEXT_HOP_INDEXf, new_member->nh_index);
  11468             member_id_buf[entry_index] = new_member->member_id;
  11469             entry_count_array[member_index]--;
  11470             (*entry_count)++;
  11471         } else {
  11472             /* Either the member of the randomly chosen entry is
  11473              * the same as the new member, or the member is an existing
  11474              * member and its entry count has decreased to threshold.
  11475              * In both cases, find the next entry that contains a
  11476              * member that's not the new member and whose entry count
  11477              * has not decreased to threshold.
  11478              */
  11479             next_entry_index = (entry_index + 1) % num_entries;
  11480             while (next_entry_index != entry_index) {
  11481                 flowset_entry = soc_mem_table_idx_to_pointer(unit,
  11482                         RH_ECMP_FLOWSETm, rh_ecmp_flowset_entry_t *,
  11483                         flowset_buf, next_entry_index);
  11484                 member_id = member_id_buf[next_entry_index];
  11485 
  11486                 /* Determine if the entry contains the new member.
  11487                  * If not, determine the existing member index.
  11488                  */
  11489                 if (member_id == new_member->member_id) {
  11490                     is_new_member = TRUE;
  11491                 } else {
  11492                     is_new_member = FALSE;
  11493 
  11494                     /* In the member_array, it's assumed that each array element's
  11495                      * member_id matches the array index of the element.
  11496                      */
  11497                     member_index = member_id;
  11498                 }
  11499 
  11500                 if (!is_new_member &&
  11501                         (entry_count_array[member_index] > threshold)) {
  11502                     soc_mem_field32_set(unit, RH_ECMP_FLOWSETm, flowset_entry,
  11503                             NEXT_HOP_INDEXf, new_member->nh_index);
  11504                     member_id_buf[next_entry_index] = new_member->member_id;
  11505                     entry_count_array[member_index]--;
  11506                     (*entry_count)++;
  11507                     break;
  11508                 } else {
  11509                     next_entry_index = (next_entry_index + 1) % num_entries;
  11510                 }
  11511             }
  11512             if (next_entry_index == entry_index) {
  11513                 /* The entry count of all existing members has decreased
  11514                  * to threshold. The entry count of the new member has
  11515                  * not yet increased to lower_bound. Lower the threshold.
  11516                  */
  11517                 threshold--;
  11518             }
  11519         }
  11520     }
  11521 
  11522     return BCM_E_NONE;
  11523 }
  11524 
  11525 /*
  11526  * Function:
  11527  *      _bcm_td2_ecmp_rh_clear_by_member_id_th
  11528  * Purpose:
  11529  *      In the given flow set entry buffer, clear entries whose
  11530  *      member ID is greater than or equal to the given member ID threshold.
  11531  *      Also, keep track of entry count for each member ID smaller
  11532  *      than the given member ID threshold.
  11533  * Parameters:
  11534  *      unit - (IN) SOC unit number.
  11535  *      num_entries - (IN) Number of flow set entries in buffer.
  11536  *      flowset_buf - (IN/OUT) Flow set entry buffer.
  11537  *      member_id_buf - (IN/OUT) Member ID buffer.
  11538  *      member_id_th - (IN) Member ID threshold.
  11539  *      array_size - (IN) Number of elements in entry_count_array.
  11540  *      entry_count_array - (OUT) Array of entry counts for member IDs not cleared.
  11541  * Returns:
  11542  *      BCM_E_XXX
  11543  */
  11544 STATIC int
  11545 _bcm_td2_ecmp_rh_clear_by_member_id_th(int unit,
  11546         int num_entries, uint32 *flowset_buf, int *member_id_buf,
  11547         int member_id_th, int array_size, int *entry_count_array)
  11548 {
  11549     int i;
  11550     rh_ecmp_flowset_entry_t *flowset_entry;
  11551     int member_id;
  11552 
  11553     if (num_entries < 1) {
  11554         return BCM_E_PARAM;
  11555     }
  11556     if (NULL == flowset_buf || NULL == member_id_buf) {
  11557         return BCM_E_PARAM;
  11558     }
  11559     if (member_id_th != array_size) {
  11560         return BCM_E_PARAM;
  11561     }
  11562     if (NULL == entry_count_array) {
  11563         return BCM_E_PARAM;
  11564     }
  11565 
  11566     for (i = 0; i < num_entries; i++) {
  11567         flowset_entry = soc_mem_table_idx_to_pointer(unit,
  11568                 RH_ECMP_FLOWSETm, rh_ecmp_flowset_entry_t *, flowset_buf, i);
  11569         if (!soc_mem_field32_get(unit, RH_ECMP_FLOWSETm, flowset_entry,
  11570                     VALIDf)) {
  11571             return BCM_E_INTERNAL;
  11572         }
  11573         member_id = member_id_buf[i];
  11574 
  11575         if (member_id >= member_id_th) {
  11576             /* Clear the valid bit */
  11577             soc_mem_field32_set(unit, RH_ECMP_FLOWSETm, flowset_entry,
  11578                     VALIDf, 0);
  11579 
  11580             /* Do not clear the next hop index, which is needed later by
  11581              * _bcm_td2_ecmp_rh_populate_empty_entries.
  11582              */
  11583 
  11584             /* Clear member ID */
  11585             member_id_buf[i] = -1;
  11586         } else {
  11587             entry_count_array[member_id]++;
  11588         }
  11589     }
  11590 
  11591     return BCM_E_NONE;
  11592 }
  11593 
  11594 /*
  11595  * Function:
  11596  *      _bcm_td2_ecmp_rh_populate_empty_entries
  11597  * Purpose:
  11598  *      In the given flow set entry buffer, populate entries not
  11599  *      containing a member, such that maximal balance is achieve
  11600  *      among members in member_array.
  11601  * Parameters:
  11602  *      unit - (IN) SOC unit number.
  11603  *      num_entries - (IN) Number of flow set entries in buffer.
  11604  *      flowset_buf - (IN/OUT) Flow set entry buffer.
  11605  *      member_id_buf - (IN/OUT) Member ID buffer.
  11606  *      num_members - (IN) Number of elements in member_array and
  11607  *                         entry_count_array.
  11608  *      member_array - (IN) Array of members.
  11609  *      entry_count_array - (IN/OUT) Array of entry counts.
  11610  *      num_shared_members - (IN) Number of members in member_array that
  11611  *                                are shared by the old and the new ECMP
  11612  *                                groups.
  11613  * Returns:
  11614  *      BCM_E_XXX
  11615  */
  11616 STATIC int
  11617 _bcm_td2_ecmp_rh_populate_empty_entries(int unit,
  11618         int num_entries, uint32 *flowset_buf, int *member_id_buf,
  11619         int num_members, _td2_ecmp_rh_member_t *member_array,
  11620         int *entry_count_array, int num_shared_members)
  11621 {
  11622     int max_entry_count;
  11623     int i, k;
  11624     rh_ecmp_flowset_entry_t *flowset_entry;
  11625     int next_hop_index;
  11626     int chosen_index = 0;
  11627 
  11628     if (num_entries < 1) {
  11629         return BCM_E_PARAM;
  11630     }
  11631     if (NULL == flowset_buf || NULL == member_id_buf) {
  11632         return BCM_E_PARAM;
  11633     }
  11634     if (0 == num_members) {
  11635         return BCM_E_PARAM;
  11636     }
  11637     if (NULL == member_array) {
  11638         return BCM_E_PARAM;
  11639     }
  11640     if (NULL == entry_count_array) {
  11641         return BCM_E_PARAM;
  11642     }
  11643     if (num_shared_members > num_members) {
  11644         return BCM_E_PARAM;
  11645     }
  11646 
  11647     max_entry_count = num_entries / num_members;
  11648     for (i = 0; i < num_entries; i++) {
  11649         flowset_entry = soc_mem_table_idx_to_pointer(unit,
  11650                 RH_ECMP_FLOWSETm, rh_ecmp_flowset_entry_t *, flowset_buf, i);
  11651         if (soc_mem_field32_get(unit, RH_ECMP_FLOWSETm, flowset_entry,
  11652                     VALIDf)) {
  11653             /* Skip valid entries */
  11654             continue;
  11655         }
  11656 
  11657         /* First, try to find a shared member whose next hop index
  11658          * matches the current entry and whose entry count has not reached
  11659          * max_entry_count. Doing so minimizes flow-to-member reassignments.
  11660          */
  11661         next_hop_index = soc_mem_field32_get(unit, RH_ECMP_FLOWSETm,
  11662                 flowset_entry, NEXT_HOP_INDEXf);
  11663         for (k = 0; k < num_shared_members; k++) {
  11664             if (member_array[k].nh_index == next_hop_index) {
  11665                 if (entry_count_array[k] < max_entry_count) {
  11666                     entry_count_array[k]++;
  11667                     chosen_index = k;
  11668                     break;
  11669                 }
  11670             }
  11671         }
  11672         if (k == num_shared_members) {
  11673             /* Cannot find a shared member with matching next hop index and
  11674              * with entry count < max_entry_count. Randomly choose a member.
  11675              */
  11676             BCM_IF_ERROR_RETURN(_bcm_td2_ecmp_rh_member_choose(unit, num_members,
  11677                         entry_count_array, &max_entry_count, &chosen_index));
  11678         }
  11679 
  11680         /* Set flow set entry */
  11681         soc_mem_field32_set(unit, RH_ECMP_FLOWSETm, flowset_entry, VALIDf, 1);
  11682         soc_mem_field32_set(unit, RH_ECMP_FLOWSETm, flowset_entry,
  11683                 NEXT_HOP_INDEXf, member_array[chosen_index].nh_index);
  11684         member_id_buf[i] = member_array[chosen_index].member_id;
  11685     }
  11686 
  11687     return BCM_E_NONE;
  11688 }
  11689 
  11690 /*
  11691  * Function:
  11692  *      _bcm_td2_ecmp_rh_balance_with_min_shared_mod
  11693  * Purpose:
  11694  *      Modify the given flow set entry buffer to achieve balance among
  11695  *      the shared members and members exclusive to the new ECMP group,
  11696  *      while keeping modification of entries containing the
  11697  *      shared members to a minimum.
  11698  * Parameters:
  11699  *      unit - (IN) SOC unit number.
  11700  *      num_entries - (IN) Number of flow set entries in buffer.
  11701  *      flowset_buf - (IN/OUT) Flow set entry buffer. Initially, this buffer
  11702  *                             contains the old ECMP group's flow set entries.
  11703  *      shared_intf_count - (IN) Number of members shared by old and new ECMP
  11704  *                               groups.
  11705  *      shared_intf_array - (IN) Array of members shared by old and new ECMP
  11706  *                               groups.
  11707  *      ex_old_intf_count - (IN) Number of members exclusive to old ECMP group.
  11708  *      ex_old_intf_array - (IN) Array of members exclusive to old ECMP group.
  11709  *      ex_new_intf_count - (IN) Number of members exclusive to new ECMP group.
  11710  *      ex_new_intf_array - (IN) Array of members exclusive to new ECMP group.
  11711  * Returns:
  11712  *      BCM_E_XXX
  11713  */
  11714 STATIC int
  11715 _bcm_td2_ecmp_rh_balance_with_min_shared_mod(int unit,
  11716         int num_entries, uint32 *flowset_buf,
  11717         int shared_intf_count, bcm_if_t *shared_intf_array,
  11718         int ex_old_intf_count, bcm_if_t *ex_old_intf_array,
  11719         int ex_new_intf_count, bcm_if_t *ex_new_intf_array)
  11720 {
  11721     int rv = BCM_E_NONE;
  11722     int old_intf_count;
  11723     int new_intf_count;
  11724     int num_members;
  11725     int alloc_size;
  11726     _td2_ecmp_rh_member_t *member_array = NULL;
  11727     int *entry_count_array = NULL;
  11728     int i;
  11729     int ex_old_index, ex_new_index;
  11730     int *member_id_buf = NULL;
  11731     int intf_count;
  11732 
  11733     if (num_entries < 1) {
  11734         return BCM_E_PARAM;
  11735     }
  11736     if (NULL == flowset_buf) {
  11737         return BCM_E_PARAM;
  11738     }
  11739     if (0 == shared_intf_count) {
  11740         return BCM_E_PARAM;
  11741     }
  11742     if (NULL == shared_intf_array) {
  11743         return BCM_E_PARAM;
  11744     }
  11745     if ((ex_old_intf_count > 0) && (NULL == ex_old_intf_array)) {
  11746         return BCM_E_PARAM;
  11747     }
  11748     if ((ex_new_intf_count > 0) && (NULL == ex_new_intf_array)) {
  11749         return BCM_E_PARAM;
  11750     }
  11751 
  11752     /* Allocate an array of members and an array of entry counts */
  11753     old_intf_count = shared_intf_count + ex_old_intf_count;
  11754     new_intf_count = shared_intf_count + ex_new_intf_count;
  11755     num_members = (old_intf_count > new_intf_count) ? old_intf_count : new_intf_count;
  11756     alloc_size = num_members * sizeof(_td2_ecmp_rh_member_t);
  11757     member_array = sal_alloc(alloc_size, "ECMP RH member array");
  11758     if (NULL == member_array) {
  11759         rv = BCM_E_MEMORY;
  11760         goto cleanup;
  11761     }
  11762     sal_memset(member_array, 0, alloc_size);
  11763 
  11764     alloc_size = num_members * sizeof(int);
  11765     entry_count_array = sal_alloc(alloc_size, "ECMP RH entry count array");
  11766     if (NULL == entry_count_array) {
  11767         rv = BCM_E_MEMORY;
  11768         goto cleanup;
  11769     }
  11770     sal_memset(entry_count_array, 0, alloc_size);
  11771 
  11772     /* Initialize the member_array with shared members, followed by members
  11773      * exclusive to the old ECMP group.
  11774      */
  11775     for (i = 0; i < shared_intf_count; i++) {
  11776         member_array[i].nh_index = shared_intf_array[i];
  11777         member_array[i].member_id = i;
  11778         member_array[i].num_replica = 1;
  11779         member_array[i].replica_id = 0;
  11780         member_array[i].next_replica_id = 0;
  11781     }
  11782     for (i = shared_intf_count; i < old_intf_count; i++) {
  11783         ex_old_index = i - shared_intf_count;
  11784         member_array[i].nh_index = ex_old_intf_array[ex_old_index];
  11785         member_array[i].member_id = i;
  11786         member_array[i].num_replica = 1;
  11787         member_array[i].replica_id = 0;
  11788         member_array[i].next_replica_id = 0;
  11789     }
  11790 
  11791     /* Find members that share the same next hop index, and
  11792      * update the replica information in member_array.
  11793      */
  11794     rv = _bcm_td2_ecmp_rh_member_replica_find(unit, old_intf_count,
  11795             member_array);
  11796     if (BCM_FAILURE(rv)) {
  11797         goto cleanup;
  11798     }
  11799 
  11800     /* Derive a buffer of member IDs by assigning a member ID to each
  11801      * entry of the flow set entry buffer.
  11802      */
  11803     alloc_size = num_entries * sizeof(int);
  11804     member_id_buf = sal_alloc(alloc_size, "ECMP RH member ID buffer");
  11805     if (NULL == member_id_buf) {
  11806         rv = BCM_E_MEMORY;
  11807         goto cleanup;
  11808     }
  11809     sal_memset(member_id_buf, 0, alloc_size);
  11810     rv = _bcm_td2_ecmp_rh_member_id_buf_assign(unit, old_intf_count,
  11811             member_array, num_entries, flowset_buf, member_id_buf);
  11812     if (BCM_FAILURE(rv)) {
  11813         goto cleanup;
  11814     }
  11815 
  11816     /* Traverse the flow set entry buffer to clear entries with member
  11817      * IDs greater than the member IDs of the shared members. Also keep
  11818      * track of each shared member's entry count.
  11819      */
  11820     rv = _bcm_td2_ecmp_rh_clear_by_member_id_th(unit, num_entries, flowset_buf,
  11821             member_id_buf, shared_intf_count, shared_intf_count,
  11822             entry_count_array);
  11823     if (BCM_FAILURE(rv)) {
  11824         goto cleanup;
  11825     }
  11826 
  11827     /* Clear from the member_array members exclusive to the old ECMP group.
  11828      * Also need to reset share members' replica info.
  11829      */
  11830     for (i = shared_intf_count; i < old_intf_count; i++) {
  11831         sal_memset(&member_array[i], 0, sizeof(_td2_ecmp_rh_member_t));
  11832     }
  11833     for (i = 0; i < shared_intf_count; i++) {
  11834         member_array[i].num_replica = 1;
  11835         member_array[i].replica_id = 0;
  11836         member_array[i].next_replica_id = 0;
  11837     }
  11838 
  11839     /* Add to member_array members exclusive to the new ECMP group */
  11840     for (i = shared_intf_count; i < new_intf_count; i++) {
  11841         ex_new_index = i - shared_intf_count;
  11842         member_array[i].nh_index = ex_new_intf_array[ex_new_index];
  11843         member_array[i].member_id = i;
  11844         member_array[i].num_replica = 1;
  11845         member_array[i].replica_id = 0;
  11846         member_array[i].next_replica_id = 0;
  11847     }
  11848 
  11849     /* Find members that share the same next hop index, and
  11850      * update the replica information in member_array.
  11851      */
  11852     rv = _bcm_td2_ecmp_rh_member_replica_find(unit, new_intf_count,
  11853             member_array);
  11854     if (BCM_FAILURE(rv)) {
  11855         goto cleanup;
  11856     }
  11857 
  11858     /* Populate the cleared entries in the flow set entry buffer.
  11859      * There're 2 cases:
  11860      *
  11861      * Case 1:
  11862      * If the number of members in the old ECMP group is greater than or
  11863      * equal to the number in the new ECMP group, populate the cleared
  11864      * entries with shared members and members exclusive to the new ECMP
  11865      * group, such that maximal balance is achieved among them.
  11866      *
  11867      * Case 2:
  11868      * If the old ECMP group has fewer members than the new ECMP group,
  11869      * populate the cleared entries with N members that are exclusive
  11870      * to the new ECMP group, such that N + number of shared members equals
  11871      * to the number of members in old ECMP group.
  11872      *
  11873      * In both cases, the flow set entries containing the shared members
  11874      * are unmodified.
  11875      */
  11876     if (old_intf_count >= new_intf_count) {
  11877         intf_count = new_intf_count;
  11878     } else {
  11879         intf_count = old_intf_count;
  11880     }
  11881     rv = _bcm_td2_ecmp_rh_populate_empty_entries(unit, num_entries, flowset_buf,
  11882             member_id_buf, intf_count, member_array, entry_count_array,
  11883             shared_intf_count);
  11884     if (BCM_FAILURE(rv)) {
  11885         goto cleanup;
  11886     }
  11887 
  11888     /* For any remaining unused members in member_array, move some
  11889      * flow set entries from existing members to these remaining
  11890      * members, such that maximal balance is achieved.
  11891      */
  11892     if (new_intf_count > intf_count) {
  11893         for (i = intf_count; i < new_intf_count; i++) {
  11894             rv = _bcm_td2_ecmp_rh_add_rebalance(unit, num_entries, flowset_buf,
  11895                     member_id_buf, i, member_array, entry_count_array,
  11896                     &member_array[i], &entry_count_array[i]);
  11897             if (BCM_FAILURE(rv)) {
  11898                 goto cleanup;
  11899             }
  11900         }
  11901     }
  11902 
  11903 cleanup:
  11904     if (member_array) {
  11905         sal_free(member_array);
  11906     }
  11907     if (entry_count_array) {
  11908         sal_free(entry_count_array);
  11909     }
  11910     if (member_id_buf) {
  11911         sal_free(member_id_buf);
  11912     }
  11913 
  11914     return rv;
  11915 }
  11916 
  11917 /*
  11918  * Function:
  11919  *      _bcm_td2_ecmp_rh_arrange_with_no_shared_entries
  11920  * Purpose:
  11921  *      Arrange the given flow set entry buffer to achieve Maximization of the shared members,
  11922  *      while entries containing none of shared members.
  11923  * Parameters:
  11924  *      unit - (IN) SOC unit number.
  11925  *      num_entries - (IN) Number of flow set entries in buffer.
  11926  *      flowset_buf - (IN/OUT) Flow set entry buffer. Initially, this buffer
  11927  *                             contains the old ECMP group's flow set entries.
  11928  *      old_intf_count - (IN) Number of members exclusive to old ECMP group.
  11929  *      old_intf_array - (IN) Array of members exclusive to old ECMP group.
  11930  *      new_intf_count - (IN) Number of members exclusive to new ECMP group.
  11931  *      new_intf_array - (IN) Array of members exclusive to new ECMP group.
  11932  *      shared_intf_count - (OUT) Number of members shared by old and new ECMP
  11933  *                               groups.
  11934  *      shared_intf_array - (OUT) Array of members shared by old and new ECMP
  11935  *                               groups.
  11936  *      ex_old_intf_count - (OUT) Number of members exclusive to old ECMP group.
  11937  *      ex_old_intf_array - (OUT) Array of members exclusive to old ECMP group.
  11938  *      ex_new_intf_count - (OUT) Number of members exclusive to new ECMP group.
  11939  *      ex_new_intf_array - (OUT) Array of members exclusive to new ECMP group.
  11940  * Returns:
  11941  *      BCM_E_XXX
  11942  */
  11943 STATIC int
  11944 _bcm_td2_ecmp_rh_arrange_with_no_shared_entries(int unit,
  11945         int num_entries, uint32 *flowset_buf,
  11946         int old_intf_count, bcm_if_t *old_intf_array,
  11947         int new_intf_count, bcm_if_t *new_intf_array,
  11948         int *shared_intf_count, bcm_if_t *shared_intf_array,
  11949         int *ex_old_intf_count, bcm_if_t *ex_old_intf_array,
  11950         int *ex_new_intf_count, bcm_if_t *ex_new_intf_array)
  11951 {
  11952     int rv = BCM_E_NONE;
  11953     int num_members;
  11954     int alloc_size;
  11955     _td2_ecmp_rh_member_t *member_array = NULL;
  11956     int i;
  11957     int *member_id_buf = NULL;
  11958     rh_ecmp_flowset_entry_t *flowset_entry;
  11959     int member_id;
  11960     int max_shared;
  11961 
  11962     if (num_entries < 1) {
  11963         return BCM_E_PARAM;
  11964     }
  11965     if (NULL == flowset_buf) {
  11966         return BCM_E_PARAM;
  11967     }
  11968     if (old_intf_count > 0 && old_intf_array == NULL) {
  11969         return BCM_E_PARAM;
  11970     }
  11971     if (new_intf_count > 0 && new_intf_array == NULL) {
  11972         return BCM_E_PARAM;
  11973     }
  11974     if (NULL == shared_intf_array) {
  11975         return BCM_E_PARAM;
  11976     }
  11977     if (NULL == ex_old_intf_array) {
  11978         return BCM_E_PARAM;
  11979     }
  11980     if (NULL == ex_new_intf_array) {
  11981         return BCM_E_PARAM;
  11982     }
  11983 
  11984     /* Allocate an array of members and an array of entry counts */
  11985     num_members = old_intf_count;
  11986     alloc_size = num_members * sizeof(_td2_ecmp_rh_member_t);
  11987     member_array = sal_alloc(alloc_size, "ECMP RH member array");
  11988     if (NULL == member_array) {
  11989         rv = BCM_E_MEMORY;
  11990         goto cleanup;
  11991     }
  11992     sal_memset(member_array, 0, alloc_size);
  11993 
  11994     /* Initialize the member_array with shared members, followed by members
  11995      * exclusive to the old ECMP group.
  11996      */
  11997     for (i = 0; i < num_members; i++) {
  11998         member_array[i].nh_index = old_intf_array[i];
  11999         member_array[i].member_id = i;
  12000         member_array[i].num_replica = 1;
  12001         member_array[i].replica_id = 0;
  12002         member_array[i].next_replica_id = 0;
  12003     }
  12004 
  12005     /* Find members that share the same next hop index, and
  12006      * update the replica information in member_array.
  12007      */
  12008     rv = _bcm_td2_ecmp_rh_member_replica_find(unit, old_intf_count,
  12009             member_array);
  12010     if (BCM_FAILURE(rv)) {
  12011         goto cleanup;
  12012     }
  12013 
  12014     /* Derive a buffer of member IDs by assigning a member ID to each
  12015      * entry of the flow set entry buffer.
  12016      */
  12017     alloc_size = num_entries * sizeof(int);
  12018     member_id_buf = sal_alloc(alloc_size, "ECMP RH member ID buffer");
  12019     if (NULL == member_id_buf) {
  12020         rv = BCM_E_MEMORY;
  12021         goto cleanup;
  12022     }
  12023     sal_memset(member_id_buf, 0, alloc_size);
  12024     rv = _bcm_td2_ecmp_rh_member_id_buf_assign(unit, num_members,
  12025             member_array, num_entries, flowset_buf, member_id_buf);
  12026     if (BCM_FAILURE(rv)) {
  12027         goto cleanup;
  12028     }
  12029 
  12030     /* Determine members shared by old and new ECMP groups, and
  12031      * members exclusive to the old and the new ECMP groups.
  12032      */
  12033     max_shared = (old_intf_count > new_intf_count) ? new_intf_count :
  12034         old_intf_count;
  12035 
  12036     for (i = 0; i < num_entries; i++) {
  12037         member_id = member_id_buf[i];
  12038         if (member_id >= max_shared) {
  12039             continue;
  12040         }
  12041         flowset_entry = soc_mem_table_idx_to_pointer(unit,
  12042                 RH_ECMP_FLOWSETm, rh_ecmp_flowset_entry_t *, flowset_buf, i);
  12043         if (!soc_mem_field32_get(unit, RH_ECMP_FLOWSETm, flowset_entry,
  12044                     VALIDf)) {
  12045             rv = BCM_E_INTERNAL;
  12046             goto cleanup;
  12047         }
  12048         soc_mem_field32_set(unit, RH_ECMP_FLOWSETm, flowset_entry,
  12049                 NEXT_HOP_INDEXf, new_intf_array[member_id]);
  12050     }
  12051 
  12052     *shared_intf_count = max_shared;
  12053     sal_memcpy(shared_intf_array, new_intf_array, 
  12054                                 *shared_intf_count * sizeof(bcm_if_t));
  12055 
  12056     if (old_intf_count > new_intf_count) {
  12057         *ex_new_intf_count = 0;
  12058         *ex_old_intf_count = old_intf_count - *shared_intf_count;
  12059         sal_memcpy(ex_old_intf_array, &old_intf_array[*shared_intf_count], 
  12060                                     *ex_old_intf_count * sizeof(bcm_if_t));
  12061     } else {
  12062         *ex_old_intf_count = 0;
  12063         *ex_new_intf_count = new_intf_count - *shared_intf_count;
  12064         sal_memcpy(ex_new_intf_array, &new_intf_array[*shared_intf_count], 
  12065                                     *ex_new_intf_count * sizeof(bcm_if_t));
  12066     }
  12067 
  12068 cleanup:
  12069     if (member_array) {
  12070         sal_free(member_array);
  12071     }
  12072     if (member_id_buf) {
  12073         sal_free(member_id_buf);
  12074     }
  12075 
  12076     return rv;
  12077 }
  12078 
  12079 /*
  12080  * Function:
  12081  *      _bcm_td2_ecmp_rh_add
  12082  * Purpose:
  12083  *      Add a member to an ECMP resilient hashing group.
  12084  * Parameters:
  12085  *      unit       - (IN) SOC unit number. 
  12086  *      ecmp       - (IN) ECMP group info.
  12087  *      intf_count - (IN) Number of elements in intf_array.
  12088  *      intf_array - (IN) Array of resilient hashing eligible members,
  12089  *                        including the member to be added.
  12090  *      new_intf   - (IN) New member to be added.
  12091  * Returns:
  12092  *      BCM_E_xxx
  12093  */
  12094 STATIC int 
  12095 _bcm_td2_ecmp_rh_add(int unit,
  12096         bcm_l3_egress_ecmp_t *ecmp,
  12097         int intf_count,
  12098         bcm_if_t *intf_array,
  12099         bcm_if_t new_intf)
  12100 {
  12101     int rv = BCM_E_NONE;
  12102     int ecmp_group;
  12103     int offset;
  12104     int new_next_hop_index;
  12105     int num_existing_members;
  12106     ecmp_count_entry_t ecmp_count_entry;
  12107     int entry_base_ptr;
  12108     int flow_set_size;
  12109     int num_entries;
  12110     int alloc_size;
  12111     uint32 *flowset_buf = NULL;
  12112     int index_min, index_max;
  12113     _td2_ecmp_rh_member_t *existing_member_arr = NULL;
  12114     int i;
  12115     int *member_id_buf = NULL;
  12116     int *entry_count_arr = NULL;
  12117     int member_id;
  12118     int lower_bound, upper_bound;
  12119     _td2_ecmp_rh_member_t new_member;
  12120     int new_member_entry_count;
  12121 
  12122     if (ecmp == NULL ||
  12123             ecmp->dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) {
  12124         return BCM_E_PARAM;
  12125     }
  12126 
  12127     if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp->ecmp_intf)) {
  12128         ecmp_group = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  12129     } else {
  12130         return BCM_E_PARAM;
  12131     }
  12132 
  12133     if (intf_count == 0 || intf_array == NULL) {
  12134         return BCM_E_PARAM;
  12135     }
  12136 
  12137     if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, new_intf)) {
  12138         offset = BCM_XGS3_EGRESS_IDX_MIN(unit);
  12139     } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, new_intf)) {
  12140         offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  12141     } else {
  12142         return BCM_E_PARAM;
  12143     }
  12144     new_next_hop_index = new_intf - offset;
  12145 
  12146     /* Check that the new member is the last element of the array of
  12147      * resilient hashing eligible members.
  12148      */
  12149     if (new_intf != intf_array[intf_count - 1]) {
  12150         return BCM_E_PARAM;
  12151     }
  12152     num_existing_members = intf_count - 1;
  12153 
  12154     if (intf_count == 1) {
  12155         /* Adding the first member is the same as setting one member */
  12156         return _bcm_td2_ecmp_rh_set(unit, ecmp, intf_count, intf_array);
  12157     }
  12158 
  12159     /* Read all the flow set entries of this ECMP resilient hash group */
  12160     SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group,
  12161                 &ecmp_count_entry));
  12162     entry_base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry,
  12163             RH_FLOW_SET_BASEf);
  12164     flow_set_size = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry,
  12165             RH_FLOW_SET_SIZEf);
  12166     BCM_IF_ERROR_RETURN
  12167         (_bcm_td2_ecmp_rh_dynamic_size_decode(unit, flow_set_size, &num_entries));
  12168 
  12169     alloc_size = num_entries * sizeof(rh_ecmp_flowset_entry_t);
  12170     flowset_buf = soc_cm_salloc(unit, alloc_size, "RH_ECMP_FLOWSET entries");
  12171     if (NULL == flowset_buf) {
  12172         rv = BCM_E_MEMORY;
  12173         goto cleanup;
  12174     }
  12175     sal_memset(flowset_buf, 0, alloc_size);
  12176     index_min = entry_base_ptr;
  12177     index_max = index_min + num_entries - 1;
  12178     rv = soc_mem_read_range(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ANY,
  12179             index_min, index_max, flowset_buf);
  12180     if (SOC_FAILURE(rv)) {
  12181         goto cleanup;
  12182     }
  12183 
  12184     /* Construct an array of existing members */
  12185     alloc_size = num_existing_members * sizeof(_td2_ecmp_rh_member_t);
  12186     existing_member_arr = sal_alloc(alloc_size, "ECMP RH member array");
  12187     if (NULL == existing_member_arr) {
  12188         rv = BCM_E_MEMORY;
  12189         goto cleanup;
  12190     }
  12191     sal_memset(existing_member_arr, 0, alloc_size);
  12192     for (i = 0; i < num_existing_members; i++) {
  12193         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf_array[i])) {
  12194             offset = BCM_XGS3_EGRESS_IDX_MIN(unit);
  12195         } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf_array[i])) {
  12196             offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  12197         } else {
  12198             rv = BCM_E_PARAM;
  12199             goto cleanup;
  12200         }
  12201         existing_member_arr[i].nh_index = intf_array[i] - offset;
  12202         existing_member_arr[i].member_id = i;
  12203         existing_member_arr[i].num_replica = 1;
  12204         existing_member_arr[i].replica_id = 0;
  12205         existing_member_arr[i].next_replica_id = 0;
  12206     }
  12207 
  12208     /* Find members that share the same next hop index, and
  12209      * update the replica information in existing_member_arr.
  12210      */
  12211     rv = _bcm_td2_ecmp_rh_member_replica_find(unit, num_existing_members,
  12212             existing_member_arr);
  12213     if (BCM_FAILURE(rv)) {
  12214         goto cleanup;
  12215     }
  12216 
  12217     /* Derive a buffer of member IDs by assigning a member ID to each
  12218      * entry of the flow set entry buffer.
  12219      */
  12220     alloc_size = num_entries * sizeof(int);
  12221     member_id_buf = sal_alloc(alloc_size, "ECMP RH member ID buffer");
  12222     if (NULL == member_id_buf) {
  12223         rv = BCM_E_MEMORY;
  12224         goto cleanup;
  12225     }
  12226     sal_memset(member_id_buf, 0, alloc_size);
  12227     rv = _bcm_td2_ecmp_rh_member_id_buf_assign(unit, num_existing_members,
  12228             existing_member_arr, num_entries, flowset_buf, member_id_buf);
  12229     if (BCM_FAILURE(rv)) {
  12230         goto cleanup;
  12231     }
  12232 
  12233     /* Compute the number of entries currently assigned to each
  12234      * existing member.
  12235      */
  12236     alloc_size = num_existing_members * sizeof(int);
  12237     entry_count_arr = sal_alloc(alloc_size, "ECMP RH entry count array");
  12238     if (NULL == entry_count_arr) {
  12239         rv = BCM_E_MEMORY;
  12240         goto cleanup;
  12241     }
  12242     sal_memset(entry_count_arr, 0, alloc_size);
  12243     for (i = 0; i < num_entries; i++) {
  12244         member_id = member_id_buf[i];
  12245 
  12246         /* In this procedure, the member_id happens to be the same as
  12247          * the index into the existing_member_arr.
  12248          */
  12249         entry_count_arr[member_id]++;
  12250     }
  12251 
  12252     /* Check that the distribution of flow set entries among existing members
  12253      * is balanced. For instance, if the number of flow set entries is 64, and
  12254      * the number of existing members is 6, then every member should have
  12255      * between 10 and 11 entries. 
  12256      */ 
  12257     lower_bound = num_entries / num_existing_members;
  12258     upper_bound = (num_entries % num_existing_members) ?
  12259                   (lower_bound + 1) : lower_bound;
  12260     for (i = 0; i < num_existing_members; i++) {
  12261         if (entry_count_arr[i] < lower_bound ||
  12262                 entry_count_arr[i] > upper_bound) {
  12263             rv = BCM_E_INTERNAL;
  12264             goto cleanup;
  12265         }
  12266     }
  12267 
  12268     /* Re-balance flow set entries from existing members to the new member */
  12269     sal_memset(&new_member, 0, sizeof(_td2_ecmp_rh_member_t));
  12270     new_member.nh_index = new_next_hop_index;
  12271     new_member.member_id = num_existing_members;
  12272     rv = _bcm_td2_ecmp_rh_add_rebalance(unit, num_entries, flowset_buf,
  12273             member_id_buf, num_existing_members, existing_member_arr,
  12274             entry_count_arr, &new_member, &new_member_entry_count);
  12275     if (BCM_FAILURE(rv)) {
  12276         goto cleanup;
  12277     }
  12278 
  12279     /* Write re-balanced flow set entries to hardware */
  12280     rv = soc_mem_write_range(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ALL,
  12281             index_min, index_max, flowset_buf);
  12282     if (SOC_FAILURE(rv)) {
  12283         goto cleanup;
  12284     }
  12285 
  12286 cleanup:
  12287     if (flowset_buf) {
  12288         soc_cm_sfree(unit, flowset_buf);
  12289     }
  12290     if (member_id_buf) {
  12291         sal_free(member_id_buf);
  12292     }
  12293     if (existing_member_arr) {
  12294         sal_free(existing_member_arr);
  12295     }
  12296     if (entry_count_arr) {
  12297         sal_free(entry_count_arr);
  12298     }
  12299 
  12300     return rv;
  12301 }
  12302 
  12303 /*
  12304  * Function:
  12305  *      _bcm_td2_ecmp_rh_delete
  12306  * Purpose:
  12307  *      Delete a member from an ECMP resilient hashing group.
  12308  * Parameters:
  12309  *      unit         - (IN) SOC unit number. 
  12310  *      ecmp         - (IN) ECMP group info.
  12311  *      intf_count   - (IN) Number of elements in intf_array.
  12312  *      intf_array   - (IN) Array of resilient hashing eligible members,
  12313  *                        except the member to be deleted.
  12314  *      leaving_intf - (IN) Member to delete.
  12315  * Returns:
  12316  *      BCM_E_xxx
  12317  */
  12318 STATIC int
  12319 _bcm_td2_ecmp_rh_delete(int unit,
  12320         bcm_l3_egress_ecmp_t *ecmp,
  12321         int intf_count,
  12322         bcm_if_t *intf_array,
  12323         bcm_if_t leaving_intf)
  12324 {
  12325     int rv = BCM_E_NONE;
  12326     int ecmp_group;
  12327     int offset;
  12328     int leaving_next_hop_index;
  12329     ecmp_count_entry_t ecmp_count_entry;
  12330     int entry_base_ptr;
  12331     int flow_set_size;
  12332     int num_entries;
  12333     int alloc_size;
  12334     uint32 *flowset_buf = NULL;
  12335     int index_min, index_max;
  12336     int num_existing_members;
  12337     _td2_ecmp_rh_member_t *existing_member_arr = NULL;
  12338     int i;
  12339     int *member_id_buf = NULL;
  12340     int *entry_count_arr = NULL;
  12341     int lower_bound, upper_bound;
  12342     int num_remaining_members;
  12343     int threshold;
  12344     int leaving_member_id;
  12345     rh_ecmp_flowset_entry_t *flowset_entry;
  12346     int member_id;
  12347     int chosen_index;
  12348 
  12349     if (ecmp == NULL ||
  12350             ecmp->dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) {
  12351         return BCM_E_PARAM;
  12352     }
  12353 
  12354     if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp->ecmp_intf)) {
  12355         ecmp_group = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  12356     } else {
  12357         return BCM_E_PARAM;
  12358     }
  12359 
  12360     if (intf_count > 0 && intf_array == NULL) {
  12361         return BCM_E_PARAM;
  12362     }
  12363 
  12364     if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, leaving_intf)) {
  12365         offset = BCM_XGS3_EGRESS_IDX_MIN(unit);
  12366     } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, leaving_intf)) {
  12367         offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  12368     } else {
  12369         return BCM_E_PARAM;
  12370     }
  12371     leaving_next_hop_index = leaving_intf - offset;
  12372 
  12373     if (intf_count == 0) {
  12374         /* Deleting the last member is the same as freeing all resources */
  12375         BCM_IF_ERROR_RETURN(_bcm_td2_ecmp_rh_free_resource(unit, ecmp_group));
  12376 
  12377         /* Store the dynamic_size in hardware */
  12378         BCM_IF_ERROR_RETURN(_bcm_td2_ecmp_rh_dynamic_size_set(unit, ecmp_group,
  12379                     ecmp->dynamic_size));
  12380 
  12381         return BCM_E_NONE;
  12382     }
  12383 
  12384     /* Read all the flow set entries of this ECMP resilient hash group */
  12385     SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group,
  12386                 &ecmp_count_entry));
  12387     entry_base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry,
  12388             RH_FLOW_SET_BASEf);
  12389     flow_set_size = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry,
  12390             RH_FLOW_SET_SIZEf);
  12391     BCM_IF_ERROR_RETURN
  12392         (_bcm_td2_ecmp_rh_dynamic_size_decode(unit, flow_set_size, &num_entries));
  12393 
  12394     alloc_size = num_entries * sizeof(rh_ecmp_flowset_entry_t);
  12395     flowset_buf = soc_cm_salloc(unit, alloc_size, "RH_ECMP_FLOWSET entries");
  12396     if (NULL == flowset_buf) {
  12397         return BCM_E_MEMORY;
  12398     }
  12399     sal_memset(flowset_buf, 0, alloc_size);
  12400     index_min = entry_base_ptr;
  12401     index_max = index_min + num_entries - 1;
  12402     rv = soc_mem_read_range(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ANY,
  12403             index_min, index_max, flowset_buf);
  12404     if (SOC_FAILURE(rv)) {
  12405         goto cleanup;
  12406     }
  12407 
  12408     /* Construct an array of existing members */
  12409     num_existing_members = intf_count + 1;
  12410     alloc_size = num_existing_members * sizeof(_td2_ecmp_rh_member_t);
  12411     existing_member_arr = sal_alloc(alloc_size, "ECMP RH member array");
  12412     if (NULL == existing_member_arr) {
  12413         rv = BCM_E_MEMORY;
  12414         goto cleanup;
  12415     }
  12416     sal_memset(existing_member_arr, 0, alloc_size);
  12417     for (i = 0; i < intf_count; i++) {
  12418         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf_array[i])) {
  12419             offset = BCM_XGS3_EGRESS_IDX_MIN(unit);
  12420         } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf_array[i])) {
  12421             offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  12422         } else {
  12423             rv = BCM_E_PARAM;
  12424             goto cleanup;
  12425         }
  12426         existing_member_arr[i].nh_index = intf_array[i] - offset;
  12427         existing_member_arr[i].member_id = i;
  12428         existing_member_arr[i].num_replica = 1;
  12429         existing_member_arr[i].replica_id = 0;
  12430         existing_member_arr[i].next_replica_id = 0;
  12431     }
  12432     existing_member_arr[intf_count].nh_index = leaving_next_hop_index;
  12433     existing_member_arr[intf_count].member_id = intf_count;
  12434     existing_member_arr[intf_count].num_replica = 1;
  12435     existing_member_arr[intf_count].replica_id = 0;
  12436     existing_member_arr[intf_count].next_replica_id = 0;
  12437 
  12438     /* Find members that share the same next hop index, and
  12439      * update the replica information in existing_member_arr.
  12440      */
  12441     rv = _bcm_td2_ecmp_rh_member_replica_find(unit, num_existing_members,
  12442             existing_member_arr);
  12443     if (BCM_FAILURE(rv)) {
  12444         goto cleanup;
  12445     }
  12446 
  12447     /* Derive a buffer of member IDs by assigning a member ID to each
  12448      * entry of the flow set entry buffer.
  12449      */
  12450     alloc_size = num_entries * sizeof(int);
  12451     member_id_buf = sal_alloc(alloc_size, "ECMP RH member ID buffer");
  12452     if (NULL == member_id_buf) {
  12453         rv = BCM_E_MEMORY;
  12454         goto cleanup;
  12455     }
  12456     sal_memset(member_id_buf, 0, alloc_size);
  12457     rv = _bcm_td2_ecmp_rh_member_id_buf_assign(unit, num_existing_members,
  12458             existing_member_arr, num_entries, flowset_buf, member_id_buf);
  12459     if (BCM_FAILURE(rv)) {
  12460         goto cleanup;
  12461     }
  12462 
  12463     /* Compute the number of entries currently assigned to each
  12464      * existing member.
  12465      */
  12466     alloc_size = num_existing_members * sizeof(int);
  12467     entry_count_arr = sal_alloc(alloc_size, "ECMP RH entry count array");
  12468     if (NULL == entry_count_arr) {
  12469         rv = BCM_E_MEMORY;
  12470         goto cleanup;
  12471     }
  12472     sal_memset(entry_count_arr, 0, alloc_size);
  12473     for (i = 0; i < num_entries; i++) {
  12474         member_id = member_id_buf[i];
  12475 
  12476         /* In the existing_member_arr, each element's member_id is the
  12477          * same as its array index.
  12478          */
  12479         entry_count_arr[member_id]++;
  12480     }
  12481 
  12482     /* Check that the distribution of flow set entries among all members
  12483      * is balanced. For instance, if the number of flow set entries is 64, and
  12484      * the number of members is 6, then every member should have
  12485      * between 10 and 11 entries. 
  12486      */ 
  12487     lower_bound = num_entries / num_existing_members;
  12488     upper_bound = (num_entries % num_existing_members) ?
  12489                   (lower_bound + 1) : lower_bound;
  12490     for (i = 0; i < num_existing_members; i++) {
  12491         if (entry_count_arr[i] < lower_bound ||
  12492                 entry_count_arr[i] > upper_bound) {
  12493             rv = BCM_E_INTERNAL;
  12494             goto cleanup;
  12495         }
  12496     }
  12497 
  12498     /* Re-balance flow set entries from the leaving member to the remaining
  12499      * members. For example, if the number of flow set entries is 64, and
  12500      * the number of members is 6, then each member has between 10 and 11
  12501      * entries. The entries should be re-assigned from the leaving member to
  12502      * the remaining 5 members such that each remaining member will end up
  12503      * with between 12 and 13 entries.
  12504      */
  12505     num_remaining_members = num_existing_members - 1;
  12506     lower_bound = num_entries / num_remaining_members;
  12507     upper_bound = (num_entries % num_remaining_members) ?
  12508                   (lower_bound + 1) : lower_bound;
  12509     threshold = lower_bound;
  12510     leaving_member_id = existing_member_arr[intf_count].member_id;
  12511     for (i = 0; i < num_entries; i++) {
  12512         flowset_entry = soc_mem_table_idx_to_pointer(unit,
  12513                 RH_ECMP_FLOWSETm, rh_ecmp_flowset_entry_t *, flowset_buf, i);
  12514         member_id = member_id_buf[i];
  12515         if (member_id != leaving_member_id) {
  12516             continue;
  12517         }
  12518 
  12519         /* Randomly choose a member among the remaining members */
  12520         rv = _bcm_td2_ecmp_rh_member_choose(unit, num_remaining_members,
  12521                 entry_count_arr, &threshold, &chosen_index);
  12522         if (BCM_FAILURE(rv)) {
  12523             goto cleanup;
  12524         }
  12525         soc_mem_field32_set(unit, RH_ECMP_FLOWSETm, flowset_entry,
  12526                 NEXT_HOP_INDEXf, existing_member_arr[chosen_index].nh_index);
  12527         member_id_buf[i] = existing_member_arr[chosen_index].member_id;
  12528     }
  12529 
  12530     /* Write re-balanced flow set entries to hardware */
  12531     rv = soc_mem_write_range(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ALL,
  12532             index_min, index_max, flowset_buf);
  12533     if (SOC_FAILURE(rv)) {
  12534         goto cleanup;
  12535     }
  12536 
  12537 cleanup:
  12538     if (flowset_buf) {
  12539         soc_cm_sfree(unit, flowset_buf);
  12540     }
  12541     if (member_id_buf) {
  12542         sal_free(member_id_buf);
  12543     }
  12544     if (existing_member_arr) {
  12545         sal_free(existing_member_arr);
  12546     }
  12547     if (entry_count_arr) {
  12548         sal_free(entry_count_arr);
  12549     }
  12550 
  12551     return rv;
  12552 }
  12553 
  12554 /*
  12555  * Function:
  12556  *      _bcm_td2_ecmp_rh_replace
  12557  * Purpose:
  12558  *      Replace ECMP resilient hashing group members without flowset table shuffle.
  12559  * Parameters:
  12560  *      unit       - (IN) SOC unit number. 
  12561  *      ecmp       - (IN) ECMP group info.
  12562  *      intf_count - (IN) Number of elements in intf_array.
  12563  *      intf_array - (IN) Array of Egress forwarding objects.
  12564  *      old_intf_count - (IN) Number of elements in old_intf_array.
  12565  *      old_intf_array - (IN) Array of Egress forwarding objects before replacing.
  12566  * Returns:
  12567  *      BCM_E_xxx
  12568  */
  12569 STATIC int
  12570 _bcm_td2_ecmp_rh_replace(int unit,
  12571         bcm_l3_egress_ecmp_t *ecmp,
  12572         int intf_count,
  12573         bcm_if_t *intf_array,
  12574         int old_intf_count,
  12575         bcm_if_t *old_intf_array)
  12576 {
  12577     int rv = BCM_E_NONE;
  12578     int ecmp_group;
  12579     int offset;
  12580     ecmp_count_entry_t ecmp_count_entry;
  12581     int entry_base_ptr;
  12582     int flow_set_size;
  12583     int num_entries;
  12584     int alloc_size;
  12585     uint32 *flowset_buf = NULL;
  12586     int index_min, index_max;
  12587     int max_shared;
  12588     int i, j;
  12589     int shared_intf_count;
  12590     int ex_old_intf_count;
  12591     int ex_new_intf_count;
  12592     bcm_if_t *shared_intf_array = NULL;
  12593     bcm_if_t *ex_old_intf_array = NULL;
  12594     bcm_if_t *ex_new_intf_array = NULL;
  12595     bcm_if_t *temp_old_intf_array = NULL;
  12596     bcm_if_t *temp_new_intf_array = NULL;
  12597 
  12598     if (ecmp == NULL ||
  12599             ecmp->dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) {
  12600         return BCM_E_PARAM;
  12601     }
  12602 
  12603     if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp->ecmp_intf)) {
  12604         ecmp_group = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  12605     } else {
  12606         return BCM_E_PARAM;
  12607     }
  12608 
  12609     if (intf_count > 0 && intf_array == NULL) {
  12610         return BCM_E_PARAM;
  12611     }
  12612 
  12613     if (intf_count == 0) {
  12614         /* Replacing the last member is the same as freeing all resources */
  12615         BCM_IF_ERROR_RETURN(_bcm_td2_ecmp_rh_free_resource(unit, ecmp_group));
  12616 
  12617         /* Store the dynamic_size in hardware */
  12618         BCM_IF_ERROR_RETURN(_bcm_td2_ecmp_rh_dynamic_size_set(unit, ecmp_group,
  12619                     ecmp->dynamic_size));
  12620 
  12621         return BCM_E_NONE;
  12622     }
  12623 
  12624     if (old_intf_count == 0) {
  12625         /* Replacing the first member is the same as setting one member */
  12626         return _bcm_td2_ecmp_rh_set(unit, ecmp, intf_count, intf_array);
  12627     }
  12628 
  12629     /* Determine members shared by old and new ECMP groups, and
  12630      * members exclusive to the old and the new ECMP groups.
  12631      */
  12632     max_shared = (old_intf_count > intf_count) ? intf_count :
  12633         old_intf_count;
  12634 
  12635     alloc_size = max_shared * sizeof(bcm_if_t);
  12636     shared_intf_array = sal_alloc(alloc_size, "shared ecmp member array");
  12637     if (NULL == shared_intf_array) {
  12638         rv = BCM_E_MEMORY;
  12639         goto cleanup;
  12640     }
  12641     sal_memset(shared_intf_array, 0, alloc_size);
  12642 
  12643     alloc_size = old_intf_count * sizeof(bcm_if_t);
  12644     ex_old_intf_array = sal_alloc(alloc_size, 
  12645                                 "array of members exclusive to old ecmp group");
  12646     if (NULL == ex_old_intf_array) {
  12647         rv = BCM_E_MEMORY;
  12648         goto cleanup;
  12649     }
  12650     sal_memset(ex_old_intf_array, 0, alloc_size);
  12651 
  12652     alloc_size = intf_count * sizeof(bcm_if_t);
  12653     ex_new_intf_array = sal_alloc(alloc_size,
  12654                                 "array of members exclusive to new ecmp group");
  12655     if (NULL == ex_new_intf_array) {
  12656         rv = BCM_E_MEMORY;
  12657         goto cleanup;
  12658     }
  12659     sal_memset(ex_new_intf_array, 0, alloc_size);
  12660 
  12661     alloc_size = old_intf_count * sizeof(bcm_if_t);
  12662     temp_old_intf_array = sal_alloc(alloc_size, "copy of old_intf_array");
  12663     if (NULL == temp_old_intf_array) {
  12664         rv = BCM_E_MEMORY;
  12665         goto cleanup;
  12666     }
  12667     sal_memcpy(temp_old_intf_array, old_intf_array, alloc_size);
  12668     for (i = 0; i < old_intf_count; i++) {
  12669         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, temp_old_intf_array[i])) {
  12670             offset = BCM_XGS3_EGRESS_IDX_MIN(unit);
  12671         } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, temp_old_intf_array[i])) {
  12672             offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  12673         } else {
  12674             rv = BCM_E_PARAM;
  12675             goto cleanup;
  12676         }
  12677         temp_old_intf_array[i] -= offset;
  12678     }
  12679 
  12680     alloc_size = intf_count * sizeof(bcm_if_t);
  12681     temp_new_intf_array = sal_alloc(alloc_size, "copy of intf_array");
  12682     if (NULL == temp_new_intf_array) {
  12683         rv = BCM_E_MEMORY;
  12684         goto cleanup;
  12685     }
  12686     sal_memcpy(temp_new_intf_array, intf_array, alloc_size);
  12687     for (i = 0; i < intf_count; i++) {
  12688         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, temp_new_intf_array[i])) {
  12689             offset = BCM_XGS3_EGRESS_IDX_MIN(unit);
  12690         } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, temp_new_intf_array[i])) {
  12691             offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  12692         } else {
  12693             rv = BCM_E_PARAM;
  12694             goto cleanup;
  12695         }
  12696         temp_new_intf_array[i] -= offset;
  12697     }
  12698 
  12699     /* Replace arrangement */
  12700     shared_intf_count = 0;
  12701     ex_new_intf_count = 0;
  12702     for (i = 0; i < intf_count; i++) {
  12703         for (j = 0; j < old_intf_count; j++) {
  12704             if (temp_new_intf_array[i] == temp_old_intf_array[j]) {
  12705                 shared_intf_array[shared_intf_count++] = temp_new_intf_array[i];
  12706                 /* Mark the matched element invalid */
  12707                 temp_old_intf_array[j] = BCM_XGS3_L3_INVALID_INDEX;
  12708                 break;
  12709             }
  12710         }
  12711         if (j == old_intf_count) {
  12712             ex_new_intf_array[ex_new_intf_count++] = temp_new_intf_array[i];
  12713         }
  12714     }
  12715 
  12716     ex_old_intf_count = 0;
  12717     for (i = 0; i < old_intf_count; i++) {
  12718         if (temp_old_intf_array[i] != BCM_XGS3_L3_INVALID_INDEX) {
  12719             ex_old_intf_array[ex_old_intf_count++] = temp_old_intf_array[i];
  12720         }
  12721     }
  12722 
  12723     /* Read all the flow set entries of this ECMP resilient hash group */
  12724     rv = READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group,
  12725                 &ecmp_count_entry);
  12726     if (BCM_FAILURE(rv)) {
  12727         goto cleanup;
  12728     }
  12729     entry_base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry,
  12730             RH_FLOW_SET_BASEf);
  12731     flow_set_size = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry,
  12732             RH_FLOW_SET_SIZEf);
  12733 
  12734     rv = _bcm_td2_ecmp_rh_dynamic_size_decode(unit, flow_set_size, &num_entries);
  12735     if (BCM_FAILURE(rv)) {
  12736         goto cleanup;
  12737     }
  12738 
  12739     alloc_size = num_entries * sizeof(rh_ecmp_flowset_entry_t);
  12740     flowset_buf = soc_cm_salloc(unit, alloc_size, "RH_ECMP_FLOWSET entries");
  12741     if (NULL == flowset_buf) {
  12742         rv = BCM_E_MEMORY;
  12743         goto cleanup;
  12744     }
  12745     sal_memset(flowset_buf, 0, alloc_size);
  12746     index_min = entry_base_ptr;
  12747     index_max = index_min + num_entries - 1;
  12748     rv = soc_mem_read_range(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ANY,
  12749             index_min, index_max, flowset_buf);
  12750     if (BCM_FAILURE(rv)) {
  12751         goto cleanup;
  12752     }
  12753 
  12754     if (shared_intf_count == 0) {
  12755         /* The old and the new ECMP groups don't share any members.
  12756          * Replacing flow set entries with max_shared members so as to 
  12757          * set shared_intf_count = max_shared.
  12758          */
  12759         rv = _bcm_td2_ecmp_rh_arrange_with_no_shared_entries(unit,
  12760                 num_entries, flowset_buf,
  12761                 old_intf_count, temp_old_intf_array,
  12762                 intf_count, temp_new_intf_array,
  12763                 &shared_intf_count, shared_intf_array,
  12764                 &ex_old_intf_count, ex_old_intf_array,
  12765                 &ex_new_intf_count, ex_new_intf_array);
  12766         if (BCM_FAILURE(rv)) {
  12767             goto cleanup;
  12768         }
  12769     }
  12770 
  12771     /* Modify the flow set entry buffer to achieve balance among
  12772      * shared members and members exclusive to the new ECMP group,
  12773      * while keeping modifications of entries containing the
  12774      * shared members to a minimum.
  12775      */
  12776     rv = _bcm_td2_ecmp_rh_balance_with_min_shared_mod(unit,
  12777             num_entries, flowset_buf,
  12778             shared_intf_count, shared_intf_array,
  12779             ex_old_intf_count, ex_old_intf_array,
  12780             ex_new_intf_count, ex_new_intf_array);
  12781     if (BCM_FAILURE(rv)) {
  12782         goto cleanup;
  12783     }
  12784 
  12785     rv = soc_mem_write_range(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ALL,
  12786             index_min, index_max, flowset_buf);
  12787     if (BCM_FAILURE(rv)) {
  12788         goto cleanup;
  12789     }
  12790 
  12791 cleanup:
  12792     if (flowset_buf) {
  12793         soc_cm_sfree(unit, flowset_buf);
  12794     }
  12795     if (shared_intf_array) {
  12796         sal_free(shared_intf_array);
  12797     }
  12798     if (ex_old_intf_array) {
  12799         sal_free(ex_old_intf_array);
  12800     }
  12801     if (ex_new_intf_array) {
  12802         sal_free(ex_new_intf_array);
  12803     }
  12804     if (temp_old_intf_array) {
  12805         sal_free(temp_old_intf_array);
  12806     }
  12807     if (temp_new_intf_array) {
  12808         sal_free(temp_new_intf_array);
  12809     }
  12810 
  12811     return rv;
  12812 }
  12813 
  12814 
  12815 /*
  12816  * Function:
  12817  *      bcm_td2_l3_egress_ecmp_rh_create 
  12818  * Purpose:
  12819  *      Create or modify an ECMP resilient hashing group.
  12820  * Parameters:
  12821  *      unit       - (IN) bcm device.
  12822  *      ecmp       - (IN) ECMP group info.
  12823  *      intf_count - (IN) Number of elements in intf_array.
  12824  *      intf_array - (IN) Array of Egress forwarding objects.
  12825  *      op         - (IN) Member operation: SET, ADD, DELETE, or REPLACE.
  12826  *      count      - (IN) Number of elements in intf.
  12827  *      intf       - (IN) Egress forwarding objects to add, delete, or replace.
  12828 
  12829  * Returns:
  12830  *      BCM_E_XXX
  12831  */
  12832 int 
  12833 bcm_td2_l3_egress_ecmp_rh_create(int unit, bcm_l3_egress_ecmp_t *ecmp,
  12834         int intf_count, bcm_if_t *intf_array, int op, int count, bcm_if_t *intf)
  12835 {
  12836     int dynamic_size_encode;
  12837     int rh_enable;
  12838     int ecmp_group;
  12839     initial_l3_ecmp_group_entry_t initial_l3_ecmp_group_entry;
  12840 
  12841 
  12842     if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) {
  12843         /* Verify ecmp->dynamic_size */
  12844         BCM_IF_ERROR_RETURN
  12845             (_bcm_td2_ecmp_rh_dynamic_size_encode(unit, ecmp->dynamic_size,
  12846                                                   &dynamic_size_encode));
  12847         rh_enable = 1;
  12848     } else {
  12849         rh_enable = 0;
  12850     }
  12851 
  12852     if (op == BCM_L3_ECMP_MEMBER_OP_SET) {
  12853         /* Free resilient hashing resources associated with this ecmp group */
  12854         ecmp_group = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  12855         BCM_IF_ERROR_RETURN
  12856             (_bcm_td2_ecmp_rh_free_resource(unit, ecmp_group));
  12857 
  12858         if (rh_enable) {
  12859             /* Set resilient hashing members for this ecmp group */
  12860             BCM_IF_ERROR_RETURN
  12861                 (_bcm_td2_ecmp_rh_set(unit, ecmp, intf_count, intf_array));
  12862 
  12863             if (SOC_IS_TRIDENT3X(unit)) {
  12864                 ecmp_group = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  12865 
  12866                 BCM_IF_ERROR_RETURN
  12867                     (soc_mem_read(unit, INITIAL_L3_ECMP_GROUPm, MEM_BLOCK_ANY,
  12868                                     ecmp_group,&initial_l3_ecmp_group_entry));
  12869 
  12870                 soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm,
  12871                                     &initial_l3_ecmp_group_entry, LB_MODEf, 1);
  12872                 BCM_IF_ERROR_RETURN(soc_mem_write(unit, INITIAL_L3_ECMP_GROUPm, MEM_BLOCK_ALL,
  12873                                                 ecmp_group, &initial_l3_ecmp_group_entry));
  12874             }
  12875         }
  12876     } else if (op == BCM_L3_ECMP_MEMBER_OP_ADD) {
  12877         if (rh_enable) {
  12878             /* Add new resilient hashing member to ecmp group */
  12879             BCM_IF_ERROR_RETURN
  12880                 (_bcm_td2_ecmp_rh_add(unit, ecmp, intf_count, intf_array, *intf));
  12881         }
  12882     } else if (op == BCM_L3_ECMP_MEMBER_OP_DELETE) {
  12883         if (rh_enable) {
  12884             /* Delete resilient hashing member from ecmp group */
  12885             BCM_IF_ERROR_RETURN
  12886                 (_bcm_td2_ecmp_rh_delete(unit, ecmp, intf_count, intf_array, *intf));
  12887         }
  12888     } else if (op == BCM_L3_ECMP_MEMBER_OP_REPLACE) {
  12889         if (rh_enable) {
  12890             /* Replace resilient hashing member for ecmp group */
  12891             BCM_IF_ERROR_RETURN
  12892                 (_bcm_td2_ecmp_rh_replace(unit, ecmp, intf_count, intf_array, count, intf));
  12893         }
  12894     } else {
  12895         return BCM_E_PARAM;
  12896     }
  12897 
  12898     return BCM_E_NONE;
  12899 }
  12900 
  12901 /*
  12902  * Function:
  12903  *      bcm_td2_l3_egress_ecmp_rh_destroy
  12904  * Purpose:
  12905  *      Destroy an ECMP resilient hashing group.
  12906  * Parameters:
  12907  *      unit    - (IN) bcm device.
  12908  *      mpintf  - (IN) L3 interface id pointing to Egress multipath object.
  12909  * Returns:
  12910  *      BCM_E_XXX
  12911  */
  12912 int 
  12913 bcm_td2_l3_egress_ecmp_rh_destroy(int unit, bcm_if_t mpintf) 
  12914 {
  12915     int ecmp_group;
  12916 
  12917     if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, mpintf)) {
  12918         ecmp_group = mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  12919     } else {
  12920         return BCM_E_PARAM;
  12921     }
  12922 
  12923     BCM_IF_ERROR_RETURN(_bcm_td2_ecmp_rh_free_resource(unit, ecmp_group));
  12924 
  12925     return BCM_E_NONE;
  12926 }
  12927 
  12928 /*
  12929  * Function:
  12930  *      bcm_td2_l3_egress_ecmp_rh_get
  12931  * Purpose:
  12932  *      Get info about an ECMP resilient hashing group.
  12933  * Parameters:
  12934  *      unit - (IN) bcm device.
  12935  *      ecmp - (INOUT) ECMP group info.
  12936  * Returns:
  12937  *      BCM_E_XXX
  12938  */
  12939 int 
  12940 bcm_td2_l3_egress_ecmp_rh_get(int unit, bcm_l3_egress_ecmp_t *ecmp)
  12941 {
  12942     int ecmp_group;
  12943     ecmp_count_entry_t ecmp_count_entry;
  12944     int flow_set_size;
  12945     int num_entries;
  12946 
  12947     if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp->ecmp_intf)) {
  12948         ecmp_group = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  12949     } else {
  12950         return BCM_E_PARAM;
  12951     }
  12952 
  12953     /* An ECMP group can be in one of 3 resilient hashing states:
  12954      * (1) RH not enabled: L3_ECMP_COUNT.RH_FLOW_SET_SIZE = 0.
  12955      * (2) RH enabled but without any members:
  12956      *     L3_ECMP_COUNT.RH_FLOW_SET_SIZE is non-zero,
  12957      *     L3_ECMP_COUNT.ENHANCED_HASHING_ENABLE = 0.
  12958      * (3) RH enabled with members:
  12959      *     L3_ECMP_COUNT.RH_FLOW_SET_SIZE is non-zero,
  12960      *     L3_ECMP_COUNT.ENHANCED_HASHING_ENABLE = 1.
  12961      */
  12962 
  12963     SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY,
  12964                 ecmp_group, &ecmp_count_entry));
  12965     flow_set_size = soc_L3_ECMP_COUNTm_field32_get(unit,
  12966             &ecmp_count_entry, RH_FLOW_SET_SIZEf);
  12967 
  12968     if (0 == flow_set_size) {
  12969         /* Resilient hashing is not enabled on this ECMP group. */
  12970         return BCM_E_NONE;
  12971     }
  12972 
  12973     ecmp->dynamic_mode = BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT;
  12974     BCM_IF_ERROR_RETURN(_bcm_td2_ecmp_rh_dynamic_size_decode(unit, flow_set_size,
  12975                         &num_entries));
  12976     ecmp->dynamic_size = num_entries;
  12977     
  12978     return BCM_E_NONE;
  12979 }
  12980 
  12981 /*
  12982  * Function:
  12983  *      bcm_td2_l3_egress_ecmp_rh_ethertype_set
  12984  * Purpose:
  12985  *      Set the Ethertypes that are eligible or ineligible for
  12986  *      ECMP resilient hashing.
  12987  * Parameters:
  12988  *      unit - (IN) Unit number.
  12989  *      flags - (IN) BCM_L3_ECMP_DYNAMIC_ETHERTYPE_xxx flags.
  12990  *      ethertype_count - (IN) Number of elements in ethertype_array.
  12991  *      ethertype_array - (IN) Array of Ethertypes.
  12992  * Returns:
  12993  *      BCM_E_XXX
  12994  */
  12995 int 
  12996 bcm_td2_l3_egress_ecmp_rh_ethertype_set(
  12997     int unit, 
  12998     uint32 flags, 
  12999     int ethertype_count, 
  13000     int *ethertype_array)
  13001 {
  13002     uint32 control_reg;
  13003     int i, j;
  13004     rh_ecmp_ethertype_eligibility_map_entry_t ethertype_entry;
  13005 
  13006     /* Input check */
  13007     if (ethertype_count > soc_mem_index_count(unit,
  13008                 RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm)) {
  13009         return BCM_E_RESOURCE;
  13010     }
  13011 
  13012     /* Update ethertype eligibility control register */
  13013     SOC_IF_ERROR_RETURN
  13014         (READ_RH_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, &control_reg));
  13015     soc_reg_field_set(unit, RH_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr,
  13016             &control_reg, ETHERTYPE_ELIGIBILITY_CONFIGf,
  13017             flags & BCM_L3_ECMP_DYNAMIC_ETHERTYPE_ELIGIBLE ? 1 : 0);
  13018     soc_reg_field_set(unit, RH_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr,
  13019             &control_reg, INNER_OUTER_ETHERTYPE_SELECTIONf,
  13020             flags & BCM_L3_ECMP_DYNAMIC_ETHERTYPE_INNER ? 1 : 0);
  13021     SOC_IF_ERROR_RETURN
  13022         (WRITE_RH_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, control_reg));
  13023 
  13024     /* Update Ethertype eligibility map table */
  13025     for (i = 0; i < ethertype_count; i++) {
  13026         sal_memset(&ethertype_entry, 0,
  13027                 sizeof(rh_ecmp_ethertype_eligibility_map_entry_t));
  13028         soc_RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_set(unit,
  13029                 &ethertype_entry, VALIDf, 1);
  13030         soc_RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_set(unit,
  13031                 &ethertype_entry, ETHERTYPEf, ethertype_array[i]);
  13032         SOC_IF_ERROR_RETURN(WRITE_RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm(unit,
  13033                     MEM_BLOCK_ALL, i, &ethertype_entry));
  13034     }
  13035 
  13036     /* Zero out remaining entries of Ethertype eligibility map table */
  13037     for (j = i; j < soc_mem_index_count(unit,
  13038                 RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm); j++) {
  13039         SOC_IF_ERROR_RETURN(WRITE_RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm(unit,
  13040                     MEM_BLOCK_ALL, j, soc_mem_entry_null(unit,
  13041                         RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm)));
  13042     }
  13043 
  13044     return BCM_E_NONE;
  13045 }
  13046 
  13047 /*
  13048  * Function:
  13049  *      bcm_td2_l3_egress_ecmp_rh_ethertype_get
  13050  * Purpose:
  13051  *      Get the Ethertypes that are eligible or ineligible for
  13052  *      ECMP resilient hashing.
  13053  * Parameters:
  13054  *      unit - (IN) Unit number.
  13055  *      flags - (INOUT) BCM_L3_ECMP_DYNAMIC_ETHERTYPE_xxx flags.
  13056  *      ethertype_max - (IN) Number of elements in ethertype_array.
  13057  *      ethertype_array - (OUT) Array of Ethertypes.
  13058  *      ethertype_count - (OUT) Number of elements returned in ethertype_array.
  13059  * Returns:
  13060  *      BCM_E_XXX
  13061  */
  13062 int 
  13063 bcm_td2_l3_egress_ecmp_rh_ethertype_get(
  13064     int unit, 
  13065     uint32 *flags, 
  13066     int ethertype_max, 
  13067     int *ethertype_array, 
  13068     int *ethertype_count)
  13069 {
  13070     uint32 control_reg;
  13071     int i;
  13072     int ethertype;
  13073     rh_ecmp_ethertype_eligibility_map_entry_t ethertype_entry;
  13074 
  13075     *ethertype_count = 0;
  13076 
  13077     /* Get flags */
  13078     SOC_IF_ERROR_RETURN
  13079         (READ_RH_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, &control_reg));
  13080     if (soc_reg_field_get(unit, RH_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr,
  13081                 control_reg, ETHERTYPE_ELIGIBILITY_CONFIGf)) {
  13082         *flags |= BCM_L3_ECMP_DYNAMIC_ETHERTYPE_ELIGIBLE;
  13083     }
  13084     if (soc_reg_field_get(unit, RH_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr,
  13085                 control_reg, INNER_OUTER_ETHERTYPE_SELECTIONf)) {
  13086         *flags |= BCM_L3_ECMP_DYNAMIC_ETHERTYPE_INNER;
  13087     }
  13088 
  13089     /* Get Ethertypes */
  13090     for (i = 0; i < soc_mem_index_count(unit,
  13091                 RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm); i++) {
  13092         SOC_IF_ERROR_RETURN(READ_RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm(unit,
  13093                     MEM_BLOCK_ANY, i, &ethertype_entry));
  13094         if (soc_RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_get(unit,
  13095                     &ethertype_entry, VALIDf)) {
  13096             ethertype = soc_RH_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_get(unit,
  13097                     &ethertype_entry, ETHERTYPEf);
  13098             if (NULL != ethertype_array) {
  13099                 ethertype_array[*ethertype_count] = ethertype;
  13100             }
  13101             (*ethertype_count)++;
  13102             if ((ethertype_max > 0) && (*ethertype_count == ethertype_max)) {
  13103                 break;
  13104             }
  13105         }
  13106     }
  13107 
  13108     return BCM_E_NONE;
  13109 }
  13110 
  13111 /*
  13112  * Function:
  13113  *      bcm_td2_l3_egress_ecmp_rh_shared_copy
  13114  * Purpose:
  13115  *      For members shared by the old and the new ECMP groups,
  13116  *      copy the resilient hash flow set entries containing these
  13117  *      members from the old to the new ECMP group, in order to minimize
  13118  *      flow-to-member reassignments when the old ECMP group in a route
  13119  *      entry is replaced by the new one.
  13120  * Parameters:
  13121  *      unit - (IN) SOC unit number.
  13122  *      old_ecmp_group - (IN) Old ECMP group.
  13123  *      new_ecmp_group - (IN) New ECMP group.
  13124  * Returns:
  13125  *      BCM_E_XXX
  13126  */
  13127 int
  13128 bcm_td2_l3_egress_ecmp_rh_shared_copy(int unit, int old_ecmp_group,
  13129         int new_ecmp_group)
  13130 {
  13131     int rv = BCM_E_NONE;
  13132     bcm_l3_egress_ecmp_t old_ecmp, new_ecmp;
  13133     int old_intf_count, new_intf_count;
  13134     bcm_if_t *old_intf_array = NULL;
  13135     bcm_if_t *new_intf_array = NULL;
  13136     int offset;
  13137     int count;
  13138     int max_shared;
  13139     bcm_if_t *shared_intf_array = NULL;
  13140     bcm_if_t *ex_old_intf_array = NULL;
  13141     bcm_if_t *ex_new_intf_array = NULL;
  13142     bcm_if_t *temp_old_intf_array = NULL;
  13143     int shared_intf_count, ex_new_intf_count, ex_old_intf_count;
  13144     int i, j;
  13145     ecmp_count_entry_t ecmp_count_entry;
  13146     int entry_base_ptr, flow_set_size, num_entries;
  13147     int alloc_size;
  13148     uint32 *buf_ptr = NULL;
  13149     int index_min, index_max;
  13150 
  13151     /* Check if there are any routing entries pointing to the
  13152      * new ECMP group. If so, the new ECMP group's flow set
  13153      * entries should not be modified.
  13154      */
  13155     if (BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp),
  13156                 new_ecmp_group) > 2) {
  13157         /* When the new ECMP group was created, its reference count
  13158          * was set to 1. Then, in bcm_xgs3_defip_add, its reference count
  13159          * was incremented before this procedure is invoked. Hence,
  13160          * if there are any routing entry already pointing at the new
  13161          * ECMP group, the reference count would be greater than 2.
  13162          */
  13163         return BCM_E_NONE;
  13164     }
  13165 
  13166     /* Check if the old ECMP group is resilient hash enabled. */
  13167     bcm_l3_egress_ecmp_t_init(&old_ecmp);
  13168     old_ecmp.ecmp_intf = old_ecmp_group + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  13169     BCM_IF_ERROR_RETURN(bcm_esw_l3_egress_ecmp_get(unit, &old_ecmp,
  13170                 0, NULL, &old_intf_count));
  13171     if (old_ecmp.dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) {
  13172         /* The old ECMP group was not resilient hash enabled. Copying
  13173          * flow set entries is not applicable.
  13174          */
  13175         return BCM_E_NONE;
  13176     }
  13177 
  13178     /* Check if the new ECMP group is resilient hash enabled. */
  13179     bcm_l3_egress_ecmp_t_init(&new_ecmp);
  13180     new_ecmp.ecmp_intf = new_ecmp_group + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
  13181     BCM_IF_ERROR_RETURN(bcm_esw_l3_egress_ecmp_get(unit, &new_ecmp,
  13182                 0, NULL, &new_intf_count));
  13183     if (new_ecmp.dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_RESILIENT) {
  13184         /* The new ECMP group is not resilient hash enabled. Copying
  13185          * flow set entries is not applicable.
  13186          */
  13187         return BCM_E_NONE;
  13188     }
  13189 
  13190     if (old_ecmp.dynamic_size != new_ecmp.dynamic_size) {
  13191         /* The number of flow set entries in old ECMP group is not the
  13192          * same as the number in new ECMP group. Copying
  13193          * flow set entries is not applicable.
  13194          */ 
  13195         return BCM_E_NONE;
  13196     }
  13197 
  13198     /* Get old ECMP group members */
  13199     old_intf_array = sal_alloc(old_intf_count * sizeof(bcm_if_t),
  13200             "old ecmp member array");
  13201     if (NULL == old_intf_array) {
  13202         rv = BCM_E_MEMORY;
  13203         goto cleanup;
  13204     }
  13205     sal_memset(old_intf_array, 0, old_intf_count * sizeof(bcm_if_t));
  13206     rv = bcm_esw_l3_egress_ecmp_get(unit, &old_ecmp, old_intf_count,
  13207             old_intf_array, &count);
  13208     if (BCM_FAILURE(rv)) {
  13209         goto cleanup;
  13210     }
  13211     for (i = 0; i < old_intf_count; i++) {
  13212         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, old_intf_array[i])) {
  13213             offset = BCM_XGS3_EGRESS_IDX_MIN(unit);
  13214         } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, old_intf_array[i])) {
  13215             offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  13216         } else {
  13217             rv = BCM_E_PARAM;
  13218             goto cleanup;
  13219         }
  13220         old_intf_array[i] -= offset;
  13221     }
  13222 
  13223     /* Get new ECMP group members */
  13224     new_intf_array = sal_alloc(new_intf_count * sizeof(bcm_if_t),
  13225             "new ecmp member array");
  13226     if (NULL == new_intf_array) {
  13227         rv = BCM_E_MEMORY;
  13228         goto cleanup;
  13229     }
  13230     sal_memset(new_intf_array, 0, new_intf_count * sizeof(bcm_if_t));
  13231     rv = bcm_esw_l3_egress_ecmp_get(unit, &new_ecmp, new_intf_count,
  13232             new_intf_array, &count);
  13233     if (BCM_FAILURE(rv)) {
  13234         goto cleanup;
  13235     }
  13236     for (i = 0; i < new_intf_count; i++) {
  13237         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, new_intf_array[i])) {
  13238             offset = BCM_XGS3_EGRESS_IDX_MIN(unit);
  13239         } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, new_intf_array[i])) {
  13240             offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
  13241         } else {
  13242             rv = BCM_E_PARAM;
  13243             goto cleanup;
  13244         }
  13245         new_intf_array[i] -= offset;
  13246     }
  13247 
  13248     /* Determine members shared by old and new ECMP groups, and
  13249      * members exclusive to the old and the new ECMP groups.
  13250      */
  13251     max_shared = (old_intf_count > new_intf_count) ? new_intf_count :
  13252         old_intf_count;
  13253     shared_intf_array = sal_alloc(max_shared * sizeof(bcm_if_t),
  13254             "shared ecmp member array");
  13255     if (NULL == shared_intf_array) {
  13256         rv = BCM_E_MEMORY;
  13257         goto cleanup;
  13258     }
  13259     sal_memset(shared_intf_array, 0, max_shared * sizeof(bcm_if_t));
  13260 
  13261     ex_old_intf_array = sal_alloc(old_intf_count * sizeof(bcm_if_t),
  13262             "array of members exclusive to old ecmp group");
  13263     if (NULL == ex_old_intf_array) {
  13264         rv = BCM_E_MEMORY;
  13265         goto cleanup;
  13266     }
  13267     sal_memset(ex_old_intf_array, 0, old_intf_count * sizeof(bcm_if_t));
  13268 
  13269     ex_new_intf_array = sal_alloc(new_intf_count * sizeof(bcm_if_t),
  13270             "array of members exclusive to new ecmp group");
  13271     if (NULL == ex_new_intf_array) {
  13272         rv = BCM_E_MEMORY;
  13273         goto cleanup;
  13274     }
  13275     sal_memset(ex_new_intf_array, 0, new_intf_count * sizeof(bcm_if_t));
  13276 
  13277     temp_old_intf_array = sal_alloc(old_intf_count * sizeof(bcm_if_t),
  13278             "copy of old_intf_array");
  13279     if (NULL == temp_old_intf_array) {
  13280         rv = BCM_E_MEMORY;
  13281         goto cleanup;
  13282     }
  13283     sal_memcpy(temp_old_intf_array, old_intf_array, old_intf_count * sizeof(bcm_if_t));
  13284 
  13285     shared_intf_count = 0;
  13286     ex_new_intf_count = 0;
  13287     for (i = 0; i < new_intf_count; i++) {
  13288         for (j = 0; j < old_intf_count; j++) {
  13289             if (new_intf_array[i] == temp_old_intf_array[j]) {
  13290                 shared_intf_array[shared_intf_count++] = new_intf_array[i];
  13291                 /* Mark the matched element invalid */
  13292                 temp_old_intf_array[j] = BCM_XGS3_L3_INVALID_INDEX;
  13293                 break;
  13294             }
  13295         }
  13296         if (j == old_intf_count) {
  13297             ex_new_intf_array[ex_new_intf_count++] = new_intf_array[i];
  13298         }
  13299     }
  13300 
  13301     ex_old_intf_count = 0;
  13302     for (i = 0; i < old_intf_count; i++) {
  13303         if (temp_old_intf_array[i] != BCM_XGS3_L3_INVALID_INDEX) {
  13304             ex_old_intf_array[ex_old_intf_count++] = temp_old_intf_array[i];
  13305         }
  13306     }
  13307 
  13308     if (shared_intf_count == 0) {
  13309         /* The old and the new ECMP groups don't share any members.
  13310          * Copying flow set entries is not applicable.
  13311          */
  13312         rv = BCM_E_NONE;
  13313         goto cleanup;
  13314     }
  13315 
  13316     /* Read old ECMP group's flow set entries into a buffer */
  13317     rv = READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, old_ecmp_group,
  13318             &ecmp_count_entry);
  13319     if (SOC_FAILURE(rv)) {
  13320         goto cleanup;
  13321     }
  13322     entry_base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry,
  13323             RH_FLOW_SET_BASEf);
  13324     flow_set_size = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry,
  13325             RH_FLOW_SET_SIZEf);
  13326     rv = _bcm_td2_ecmp_rh_dynamic_size_decode(unit, flow_set_size, &num_entries);
  13327     if (BCM_FAILURE(rv)) {
  13328         goto cleanup;
  13329     }
  13330     alloc_size = num_entries * sizeof(rh_ecmp_flowset_entry_t);
  13331     buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_ECMP_FLOWSET entries");
  13332     if (NULL == buf_ptr) {
  13333         rv = BCM_E_MEMORY;
  13334         goto cleanup;
  13335     }
  13336     sal_memset(buf_ptr, 0, alloc_size);
  13337     index_min = entry_base_ptr;
  13338     index_max = index_min + num_entries - 1;
  13339     rv = soc_mem_read_range(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ANY,
  13340             index_min, index_max, buf_ptr);
  13341     if (SOC_FAILURE(rv)) {
  13342         goto cleanup;
  13343     }
  13344 
  13345     /* Modify the flow set entry buffer to achieve balance among
  13346      * shared members and members exclusive to the new ECMP group,
  13347      * while keeping modifications of entries containing the
  13348      * shared members to a minimum.
  13349      */
  13350     rv = _bcm_td2_ecmp_rh_balance_with_min_shared_mod(unit,
  13351             num_entries, buf_ptr,
  13352             shared_intf_count, shared_intf_array,
  13353             ex_old_intf_count, ex_old_intf_array,
  13354             ex_new_intf_count, ex_new_intf_array);
  13355     if (BCM_FAILURE(rv)) {
  13356         goto cleanup;
  13357     }
  13358 
  13359     /* Replace the new ECMP group's flow set entries with the buffer */
  13360     rv = READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, new_ecmp_group,
  13361             &ecmp_count_entry);
  13362     if (SOC_FAILURE(rv)) {
  13363         goto cleanup;
  13364     }
  13365     entry_base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry,
  13366             RH_FLOW_SET_BASEf);
  13367     flow_set_size = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_count_entry,
  13368             RH_FLOW_SET_SIZEf);
  13369     rv = _bcm_td2_ecmp_rh_dynamic_size_decode(unit, flow_set_size, &num_entries);
  13370     if (BCM_FAILURE(rv)) {
  13371         goto cleanup;
  13372     }
  13373     index_min = entry_base_ptr;
  13374     index_max = index_min + num_entries - 1;
  13375     rv = soc_mem_write_range(unit, RH_ECMP_FLOWSETm, MEM_BLOCK_ALL,
  13376             index_min, index_max, buf_ptr);
  13377     if (SOC_FAILURE(rv)) {
  13378         goto cleanup;
  13379     }
  13380 
  13381 cleanup:
  13382     if (old_intf_array) {
  13383         sal_free(old_intf_array);
  13384     }
  13385     if (new_intf_array) {
  13386         sal_free(new_intf_array);
  13387     }
  13388     if (shared_intf_array) {
  13389         sal_free(shared_intf_array);
  13390     }
  13391     if (ex_old_intf_array) {
  13392         sal_free(ex_old_intf_array);
  13393     }
  13394     if (ex_new_intf_array) {
  13395         sal_free(ex_new_intf_array);
  13396     }
  13397     if (temp_old_intf_array) {
  13398         sal_free(temp_old_intf_array);
  13399     }
  13400     if (buf_ptr) {
  13401         soc_cm_sfree(unit, buf_ptr);
  13402     }
  13403 
  13404     return rv;
  13405 }
  13406 
  13407 #ifdef BCM_WARM_BOOT_SUPPORT
  13408 
  13409 /*
  13410  * Function:
  13411  *      bcm_td2_ecmp_rh_hw_recover
  13412  * Purpose:
  13413  *      Recover ECMP resilient hashing internal state from hardware.
  13414  * Parameters:
  13415  *      unit - (IN) SOC unit number.
  13416  * Returns:
  13417  *      BCM_E_XXX
  13418  */
  13419 int
  13420 bcm_td2_ecmp_rh_hw_recover(int unit) 
  13421 {
  13422     int rv = BCM_E_NONE;
  13423     int alloc_size;
  13424     uint32 *buf_ptr = NULL;
  13425     int i;
  13426     ecmp_count_entry_t *ecmp_count_entry;
  13427     int flow_set_size;
  13428     int entry_base_ptr;
  13429     int block_base_ptr;
  13430     int num_entries;
  13431     int num_blocks, enhanced_hashing = 1;
  13432     soc_field_t enhanced_hashing_fld;
  13433     uint32 rval;
  13434 
  13435     if (soc_reg_field_valid(unit, ENHANCED_HASHING_CONTROLr, RH_DLB_SELECTIONf)) {
  13436         SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROLr(unit, &rval));
  13437         if (0 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROLr, rval,
  13438                 RH_DLB_SELECTIONf)) {
  13439            /* ECMP resilient hashing is not enabled chip-wide. */
  13440             return BCM_E_NONE;
  13441         }
  13442     }
  13443 
  13444     /* Read entire L3_ECMP_COUNT table */
  13445     alloc_size = soc_mem_index_count(unit, L3_ECMP_COUNTm) *
  13446         sizeof(ecmp_count_entry_t);
  13447     buf_ptr = soc_cm_salloc(unit, alloc_size, "L3_ECMP_COUNT entries");
  13448     if (NULL == buf_ptr) {
  13449         return BCM_E_MEMORY;
  13450     }
  13451     rv = soc_mem_read_range(unit, L3_ECMP_COUNTm, MEM_BLOCK_ANY,
  13452             soc_mem_index_min(unit, L3_ECMP_COUNTm),
  13453             soc_mem_index_max(unit, L3_ECMP_COUNTm),
  13454             buf_ptr);
  13455     if (SOC_FAILURE(rv)) {
  13456         soc_cm_sfree(unit, buf_ptr);
  13457         return rv;
  13458     }
  13459 
  13460     /* Traverse ECMP groups to recover resilient hashing flow set
  13461      * table usage.
  13462      */
  13463     for (i = 0; i < soc_mem_index_count(unit, L3_ECMP_COUNTm); i++) {
  13464 
  13465         /* An ECMP group can be in one of 3 resilient hashing states:
  13466          * (1) RH not enabled: L3_ECMP_COUNT.RH_FLOW_SET_SIZE = 0.
  13467          * (2) RH enabled but without any members:
  13468          *     L3_ECMP_COUNT.RH_FLOW_SET_SIZE is non-zero,
  13469          *     L3_ECMP_COUNT.ENHANCED_HASHING_ENABLE = 0.
  13470          * (3) RH enabled with members:
  13471          *     L3_ECMP_COUNT.RH_FLOW_SET_SIZE is non-zero,
  13472          *     L3_ECMP_COUNT.ENHANCED_HASHING_ENABLE = 1.
  13473          */
  13474 
  13475         ecmp_count_entry = soc_mem_table_idx_to_pointer(unit, L3_ECMP_COUNTm,
  13476                 ecmp_count_entry_t *, buf_ptr, i);
  13477         flow_set_size = soc_L3_ECMP_COUNTm_field32_get(unit,
  13478                 ecmp_count_entry, RH_FLOW_SET_SIZEf);
  13479         if (0 == flow_set_size) {
  13480             /* Resilient hashing is not enabled on this ECMP group. */
  13481             continue;
  13482         }
  13483         if (soc_feature(unit, soc_feature_td3_style_dlb_rh)){
  13484             enhanced_hashing_fld = LB_MODEf;
  13485             enhanced_hashing = 4;
  13486         } else {
  13487             enhanced_hashing_fld = ENHANCED_HASHING_ENABLEf;
  13488         }
  13489         if (soc_L3_ECMP_COUNTm_field32_get(unit,
  13490                    ecmp_count_entry, enhanced_hashing_fld) == enhanced_hashing) {
  13491             /* Recover ECMP resilient hashing flow set block usage */
  13492             entry_base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit,
  13493                     ecmp_count_entry, RH_FLOW_SET_BASEf);
  13494             block_base_ptr = entry_base_ptr >> \
  13495                              _td2_ecmp_rh_info[unit]->ecmp_block_size;
  13496             rv = _bcm_td2_ecmp_rh_dynamic_size_decode(unit, flow_set_size,
  13497                     &num_entries);
  13498             if (BCM_FAILURE(rv)) {
  13499                 soc_cm_sfree(unit, buf_ptr);
  13500                 return rv;
  13501             }
  13502             num_blocks = num_entries >> \
  13503                          _td2_ecmp_rh_info[unit]->ecmp_block_size ;
  13504             _BCM_ECMP_RH_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr,
  13505                     num_blocks);
  13506 #ifdef BCM_TRIDENT3_SUPPORT
  13507             if (soc_feature(unit, soc_feature_td3_dlb)) {
  13508                 ecmp_grp_enhanced_hashing[unit][i] = 1;
  13509             }
  13510 #endif
  13511         }
  13512     }
  13513 
  13514     soc_cm_sfree(unit, buf_ptr);
  13515 
  13516     return rv;
  13517 }
  13518 
  13519 #endif /* BCM_WARM_BOOT_SUPPORT */
  13520 
  13521 #ifndef BCM_SW_STATE_DUMP_DISABLE
  13522 /*
  13523  * Function:
  13524  *     bcm_td2_ecmp_rh_sw_dump
  13525  * Purpose:
  13526  *     Displays ECMP resilient hashing state maintained by software.
  13527  * Parameters:
  13528  *     unit - Device unit number
  13529  * Returns:
  13530  *     None
  13531  */
  13532 void bcm_td2_ecmp_rh_sw_dump(int unit)
  13533 {
  13534     int i, j;
  13535 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
  13536     _bcm_l3_bookkeeping_t *l3_bk_info = &_bcm_l3_bk_info[unit];
  13537 #endif 
  13538 
  13539     LOG_CLI((BSL_META_U(unit,
  13540                         "  ECMP Resilient Hashing Info -\n")));
  13541 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
  13542     if ((
  13543 #if defined(BCM_RIOT_SUPPORT)
  13544          l3_bk_info->riot_enable ||
  13545 #endif
  13546          BCMI_L3_ECMP_IS_MULTI_LEVEL(unit)) &&
  13547         (l3_bk_info->l3_ecmp_rh_overlay_entries > 0)) {
  13548 
  13549         LOG_CLI((BSL_META_U(unit,
  13550                         "    Overlay RH Flowset Table Blocks Total: %d\n"),
  13551               l3_bk_info->l3_ecmp_rh_overlay_entries >> \
  13552               _td2_ecmp_rh_info[unit]->ecmp_block_size));
  13553 
  13554         LOG_CLI((BSL_META_U(unit,
  13555                         "    Underlay RH Flowset Table Blocks Total: %d\n"),
  13556              _td2_ecmp_rh_info[unit]->num_ecmp_rh_flowset_blocks -
  13557              (l3_bk_info->l3_ecmp_rh_overlay_entries >> \
  13558               _td2_ecmp_rh_info[unit]->ecmp_block_size)));
  13559     } else
  13560 #endif
  13561     {
  13562 
  13563         LOG_CLI((BSL_META_U(unit,
  13564                         "    RH Flowset Table Blocks Total: %d\n"),
  13565              _td2_ecmp_rh_info[unit]->num_ecmp_rh_flowset_blocks));
  13566     }
  13567 
  13568     /* Print ECMP RH flowset table usage */
  13569     LOG_CLI((BSL_META_U(unit,
  13570                         "    RH Flowset Table Blocks Used:")));
  13571     j = 0;
  13572     for (i = 0; i < _td2_ecmp_rh_info[unit]->num_ecmp_rh_flowset_blocks; i++) {
  13573         if (_BCM_ECMP_RH_FLOWSET_BLOCK_USED_GET(unit, i)) {
  13574             j++;
  13575             if (j % 15 == 1) {
  13576                 LOG_CLI((BSL_META_U(unit,
  13577                                     "\n     ")));
  13578             }
  13579             LOG_CLI((BSL_META_U(unit,
  13580                                 " %4d"), i));
  13581         }
  13582     }
  13583     LOG_CLI((BSL_META_U(unit,
  13584                         "\n")));
  13585 
  13586     return;
  13587 }
  13588 
  13589 #endif /* BCM_SW_STATE_DUMP_DISABLE */
  13590 
  13591 #endif /* INCLUDE_L3 && BCM_TRIDENT2_SUPPORT  */