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


      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 <soc/defs.h>
     12 #include <shared/bsl.h>
     13 #if defined(INCLUDE_L3) && defined(BCM_TRIUMPH3_SUPPORT) 
     14 #include <soc/drv.h>
     15 #include <bcm/error.h>
     16 
     17 #include <bcm/l3.h>
     18 #include <soc/l3x.h>
     19 #include <soc/lpm.h>
     20 #include <bcm/tunnel.h>
     21 #include <bcm/debug.h>
     22 #include <bcm/error.h>
     23 #include <bcm/stack.h>
     24 
     25 #include <bcm_int/esw/triumph3.h>
     26 #include <bcm_int/esw/firebolt.h>
     27 #include <bcm_int/esw/triumph2.h>
     28 #include <bcm_int/esw/stack.h>
     29 #include <bcm_int/esw/flex_ctr.h>
     30 #include <bcm_int/esw_dispatch.h>
     31 #include <bcm_int/esw/lpmv6.h>
     32 #include <bcm_int/esw/virtual.h>
     33 #include <bcm_int/esw/tomahawk.h>
     34 
     35 #if defined(BCM_TRX_SUPPORT) 
     36 #include <bcm_int/esw/trx.h>
     37 #endif /* BCM_TRX_SUPPORT */
     38 #if defined(BCM_TRIDENT2_SUPPORT)
     39 #include <bcm_int/esw/qos.h>
     40 #endif /* BCM_TRIDENT_SUPPORT*/
     41 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
     42 #include <bcm_int/esw/trident2plus.h>
     43 #endif /* BCM_TRIDENT2PLUS_SUPPORT */
     44 #if defined(BCM_HGPROXY_COE_SUPPORT)
     45 #include <bcm_int/esw/xgs5.h>
     46 #endif /* BCM_HGPROXY_COE_SUPPORT */
     47 #if defined(BCM_TRIDENT3_SUPPORT)
     48 #include <bcm_int/esw/trident3.h>
     49 #endif /* BCM_TRIDENT_SUPPORT*/
     50 
     51 #if defined(BCM_TRIDENT3_SUPPORT)
     52 #include <bcm_int/esw/trident3.h>
     53 #endif /* BCM_TRIDENT3_SUPPORT */
     54 
     55 #define _BCM_TR3_NUM_ESM_HOST_TABLES  (4)
     56 #define _BCM_TR3_L3_MEM_BANKS_ALL     (-1)
     57 #define _BCM_TR3_HOST_ENTRY_NOT_FOUND (-1)
     58 
     59 /* L3 ESM host table state */
     60 static int *_bcm_tr3_esm_host_tbl_freeidx_ptr
     61             [_BCM_TR3_NUM_ESM_HOST_TABLES][SOC_MAX_NUM_DEVICES];
     62 #define _TR3_ESM_HOST_TBL_STATE(_u_, _tbl_) \
     63         (_bcm_tr3_esm_host_tbl_freeidx_ptr[(_tbl_)][(_u_)])
     64 #define _TR3_ESM_HOST_TBL_FREE_ENTRY(_u_, _tbl_) \
     65         (*_bcm_tr3_esm_host_tbl_freeidx_ptr[(_tbl_)][(_u_)])
     66 
     67 extern _bcm_defip_pair128_table_t *l3_defip_pair128[BCM_MAX_NUM_UNITS];
     68 /* ECMP dynamic load balancing internal state */
     69 
     70 typedef struct _tr3_ecmp_dlb_nh_membership_s {
     71     int member_id; /* ECMP DLB member ID assigned to next hop index */
     72     int group;  /* ECMP DLB group this member belongs to */
     73     struct _tr3_ecmp_dlb_nh_membership_s *next;
     74 } _tr3_ecmp_dlb_nh_membership_t;
     75 
     76 typedef struct _tr3_ecmp_dlb_nh_info_s {
     77     int valid;
     78     int nh_index; /* next hop index */
     79     _tr3_ecmp_dlb_nh_membership_t *nh_membership_list;
     80                   /* Linked list of ECMP DLB member IDs assigned to this
     81                    * next hop index and the ECMP DLB groups the member IDs
     82                    * belong to.
     83                    */ 
     84 } _tr3_ecmp_dlb_nh_info_t;
     85 
     86 typedef struct _tr3_ecmp_dlb_bookkeeping_s {
     87     int ecmp_dlb_nh_info_size; /* Size of ecmp_dlb_nh_info array */
     88     _tr3_ecmp_dlb_nh_info_t *ecmp_dlb_nh_info;
     89     SHR_BITDCL *ecmp_dlb_id_used_bitmap;
     90     SHR_BITDCL *ecmp_dlb_flowset_block_bitmap; /* Each block corresponds to
     91                                                  512 entries */
     92     SHR_BITDCL *ecmp_dlb_member_id_used_bitmap;
     93     int ecmp_dlb_sample_rate;
     94     int ecmp_dlb_tx_load_min_th;
     95     int ecmp_dlb_tx_load_max_th;
     96     int ecmp_dlb_qsize_min_th;
     97     int ecmp_dlb_qsize_max_th;
     98     int ecmp_dlb_exp_load_min_th;
     99     int ecmp_dlb_exp_load_max_th;
    100     int ecmp_dlb_imbalance_min_th;
    101     int ecmp_dlb_imbalance_max_th;
    102     uint8 *ecmp_dlb_load_weight;
    103     soc_profile_mem_t *ecmp_dlb_quality_map_profile;
    104 #ifdef BCM_WARM_BOOT_SUPPORT
    105     uint8 recovered_from_scache; /* Indicates if the following members of this
    106                                     structure have been recovered from scache:
    107                                     ecmp_dlb_sample_rate,
    108                                     ecmp_dlb_tx_load_min_th,
    109                                     ecmp_dlb_tx_load_max_th,
    110                                     ecmp_dlb_qsize_min_th,
    111                                     ecmp_dlb_qsize_max_th,
    112                                     ecmp_dlb_exp_load_min_th,
    113                                     ecmp_dlb_exp_load_max_th,
    114                                     ecmp_dlb_imbalance_min_th,
    115                                     ecmp_dlb_imbalance_max_th,
    116                                     ecmp_dlb_load_weight */
    117 #endif /* BCM_WARM_BOOT_SUPPORT */
    118 } _tr3_ecmp_dlb_bookkeeping_t;
    119 
    120 static _tr3_ecmp_dlb_bookkeeping_t *_tr3_ecmp_dlb_bk[BCM_MAX_NUM_UNITS];
    121 
    122 #define ECMP_DLB_INFO(_unit_) (_tr3_ecmp_dlb_bk[_unit_])
    123 #define ECMP_DLB_NH_INFO(_unit_, _idx_) \
    124            (_tr3_ecmp_dlb_bk[_unit_]->ecmp_dlb_nh_info[_idx_])
    125 
    126 #define _BCM_ECMP_DLB_ID_USED_GET(_u_, _idx_) \
    127     SHR_BITGET(ECMP_DLB_INFO(_u_)->ecmp_dlb_id_used_bitmap, _idx_)
    128 #define _BCM_ECMP_DLB_ID_USED_SET(_u_, _idx_) \
    129     SHR_BITSET(ECMP_DLB_INFO(_u_)->ecmp_dlb_id_used_bitmap, _idx_)
    130 #define _BCM_ECMP_DLB_ID_USED_CLR(_u_, _idx_) \
    131     SHR_BITCLR(ECMP_DLB_INFO(_u_)->ecmp_dlb_id_used_bitmap, _idx_)
    132 
    133 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_GET(_u_, _idx_) \
    134     SHR_BITGET(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_)
    135 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_SET(_u_, _idx_) \
    136     SHR_BITSET(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_)
    137 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_CLR(_u_, _idx_) \
    138     SHR_BITCLR(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_)
    139 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_SET_RANGE(_u_, _idx_, _count_) \
    140     SHR_BITSET_RANGE(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_, _count_)
    141 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_CLR_RANGE(_u_, _idx_, _count_) \
    142     SHR_BITCLR_RANGE(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_, _count_)
    143 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_TEST_RANGE(_u_, _idx_, _count_, _result_) \
    144     SHR_BITTEST_RANGE(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_, _count_, _result_)
    145 
    146 #define _BCM_ECMP_DLB_MEMBER_ID_USED_GET(_u_, _idx_) \
    147     SHR_BITGET(ECMP_DLB_INFO(_u_)->ecmp_dlb_member_id_used_bitmap, _idx_)
    148 #define _BCM_ECMP_DLB_MEMBER_ID_USED_SET(_u_, _idx_) \
    149     SHR_BITSET(ECMP_DLB_INFO(_u_)->ecmp_dlb_member_id_used_bitmap, _idx_)
    150 #define _BCM_ECMP_DLB_MEMBER_ID_USED_CLR(_u_, _idx_) \
    151     SHR_BITCLR(ECMP_DLB_INFO(_u_)->ecmp_dlb_member_id_used_bitmap, _idx_)
    152 
    153 /*----- STATIC FUNCS ----- */
    154 /*
    155  * Function:
    156  *      _bcm_tr3_l3_ent_init
    157  * Purpose:
    158  *      Tr3 helper routine used to init l3 host entry buffer
    159  * Parameters:
    160  *      unit      - (IN) SOC unit number. 
    161  *      mem       - (IN) L3 table memory.
    162  *      l3cfg     - (IN/OUT) l3 entry  lookup key & search result.
    163  *      l3x_entry - (IN) hw buffer.
    164  * Returns:
    165  *      void
    166  */
    167 STATIC int
    168 _bcm_tr3_l3_ent_init(int unit, soc_mem_t mem, 
    169                       _bcm_l3_cfg_t *l3cfg, void *l3x_entry)
    170 {
    171     int esm;
    172     int ipv6;                     /* Entry is IPv6 flag.         */
    173     uint32 *buf_p;                /* HW buffer address.          */ 
    174 
    175     /* Get entry type. */
    176     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
    177 
    178     esm = BCM_TR3_MEM_IS_ESM(unit, mem);
    179 
    180     /* Zero destination buffer. */
    181     buf_p = (uint32 *)l3x_entry;
    182     sal_memset(buf_p, 0, BCM_L3_MEM_ENT_SIZE(unit, mem)); 
    183 
    184     if (esm) {
    185         if (ipv6) {
    186             soc_mem_ip6_addr_set(unit, mem, buf_p, IP_ADDRf, l3cfg->l3c_ip6, 0);
    187         } else {
    188             soc_mem_field32_set(unit, mem, buf_p, IP_ADDRf, l3cfg->l3c_ip_addr);
    189         }
    190         soc_mem_field32_set(unit, mem, buf_p, VRF_IDf, l3cfg->l3c_vrf);
    191         /* ESM VALID bit is set/unset in EXT_TCAM_VBIT table in
    192          * the ESM add/del function  */
    193     } else {
    194         if (ipv6) { /* ipv6 entry */
    195             soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6UC__IP_ADDR_LWR_64f,
    196                              l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_ONLY);
    197             soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6UC__IP_ADDR_UPR_64f,
    198                              l3cfg->l3c_ip6, SOC_MEM_IP6_UPPER_ONLY);
    199             soc_mem_field32_set(unit, mem, buf_p, IPV6UC__VRF_IDf,
    200                                                   l3cfg->l3c_vrf);
    201             soc_mem_field32_set(unit, mem, buf_p, VALID_0f, 1); 
    202             soc_mem_field32_set(unit, mem, buf_p, VALID_1f, 1); 
    203             if (BCM_XGS3_L3_MEM(unit, v4_2) == mem) {
    204                 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_0f, 2);
    205                 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_1f, 2);
    206             } else if (BCM_XGS3_L3_MEM(unit, v6_4) == mem) { 
    207                 /* ipv6 extended host entry */
    208                 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_0f, 3);
    209                 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_1f, 3);
    210                 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_2f, 3);
    211                 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_3f, 3);
    212                 soc_mem_field32_set(unit, mem, buf_p, VALID_0f, 1); 
    213                 soc_mem_field32_set(unit, mem, buf_p, VALID_1f, 1); 
    214                 soc_mem_field32_set(unit, mem, buf_p, VALID_2f, 1); 
    215                 soc_mem_field32_set(unit, mem, buf_p, VALID_3f, 1); 
    216             } else {
    217                 return BCM_E_NOT_FOUND;
    218             }
    219         } else { /* ipv4 entry */
    220             soc_mem_field32_set(unit, mem, buf_p, IPV4UC__IP_ADDRf,
    221                                                l3cfg->l3c_ip_addr);
    222             soc_mem_field32_set(unit, mem, buf_p, IPV4UC__VRF_IDf,
    223                                                   l3cfg->l3c_vrf);
    224             if (BCM_XGS3_L3_MEM(unit, v4) == mem) {
    225                 /* ipv4 unicast */
    226                 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPEf, 0); 
    227                 soc_mem_field32_set(unit, mem, buf_p, VALIDf, 1); 
    228             } else if (BCM_XGS3_L3_MEM(unit, v4_2) == mem) { 
    229                 /* ipv4 extended host entry */
    230                 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_0f, 1);
    231                 soc_mem_field32_set(unit, mem, buf_p, KEY_TYPE_1f, 1);
    232                 soc_mem_field32_set(unit, mem, buf_p, VALID_1f, 1); 
    233                 soc_mem_field32_set(unit, mem, buf_p, VALID_0f, 1); 
    234             } else {
    235                 return BCM_E_NOT_FOUND;
    236             }
    237         }
    238     }
    239 
    240     return BCM_E_NONE;
    241 }
    242 
    243 /*
    244  * Function:
    245  *      _bcm_tr3_l3_ipmc_ent_init
    246  * Purpose:
    247  *      Set GROUP/SOURCE/VID/IMPC flag in the entry.
    248  * Parameters:
    249  *      unit      - (IN)SOC unit number.
    250  *      l3x_entry - (IN/OUT) IPMC entry to fill. 
    251  *      l3cfg     - (IN) Api IPMC data. 
    252  * Returns:
    253  *    BCM_E_XXX
    254  */
    255 STATIC void
    256 _bcm_tr3_l3_ipmc_ent_init(int unit, uint32 *buf_p,
    257                              _bcm_l3_cfg_t *l3cfg)
    258 {
    259     soc_mem_t mem;                     /* IPMC table memory.    */
    260     int ipv6;                          /* IPv6 entry indicator. */
    261     int idx;                           /* Iteration index.      */
    262     soc_field_t v4typef[] = { KEY_TYPE_0f, KEY_TYPE_1f };
    263     soc_field_t v6typef[] = { KEY_TYPE_0f, KEY_TYPE_1f, 
    264                               KEY_TYPE_2f, KEY_TYPE_3f };
    265     soc_field_t validf[] = { VALID_0f, VALID_1f, VALID_2f, VALID_3f };
    266 
    267     /* Get entry type. */
    268     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
    269 
    270     /* Get table memory. */
    271     mem =  (ipv6) ? L3_ENTRY_4m : L3_ENTRY_2m;
    272 
    273     sal_memset(buf_p, 0, BCM_L3_MEM_ENT_SIZE(unit, mem));
    274 
    275     if (ipv6) {
    276         /* Set group address. */
    277         soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6MC__GROUP_IP_ADDR_LWR_96f,
    278                              l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_96BIT);
    279         l3cfg->l3c_ip6[0] = 0x0;    /* Don't write ff entry already mcast. */
    280         soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6MC__GROUP_IP_ADDR_UPR_24f, 
    281                              l3cfg->l3c_ip6, SOC_MEM_IP6_BITS_119_96);
    282         l3cfg->l3c_ip6[0] = 0xff;    /* Restore The entry  */
    283 
    284         /* Set source  address. */
    285         soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6MC__SOURCE_IP_ADDR_LWR_64f, 
    286                              l3cfg->l3c_sip6, SOC_MEM_IP6_LOWER_ONLY);
    287         soc_mem_ip6_addr_set(unit, mem, buf_p, IPV6MC__SOURCE_IP_ADDR_UPR_64f, 
    288                              l3cfg->l3c_sip6, SOC_MEM_IP6_UPPER_ONLY);
    289 
    290         for (idx = 0; idx < 4; idx++) {
    291             /* Set key type */
    292             soc_mem_field32_set(unit, mem, buf_p, v6typef[idx], 
    293                                 SOC_MEM_KEY_L3_ENTRY_4_IPV6MC_IPV6_MULTICAST);
    294 
    295             /* Set entry valid bit. */
    296             soc_mem_field32_set(unit, mem, buf_p, validf[idx], 1);
    297 
    298         }
    299 
    300         /* Set vlan id or L3_IIF. */
    301         if (l3cfg->l3c_vid < 4096) {
    302             soc_mem_field32_set(unit, mem, buf_p, IPV6MC__VLAN_IDf, l3cfg->l3c_vid);
    303         } else {
    304             soc_mem_field32_set(unit, mem, buf_p, IPV6MC__L3_IIFf, l3cfg->l3c_vid);
    305         }
    306 
    307         /* Set virtual router id. */
    308         soc_mem_field32_set(unit, mem, buf_p, IPV6MC__VRF_IDf, l3cfg->l3c_vrf);
    309 
    310     } else {
    311         /* Set group id. */
    312         soc_mem_field32_set(unit, mem, buf_p, IPV4MC__GROUP_IP_ADDRf,
    313                             l3cfg->l3c_ip_addr);
    314 
    315         /* Set source address. */
    316         soc_mem_field32_set(unit, mem, buf_p, IPV4MC__SOURCE_IP_ADDRf,
    317                             l3cfg->l3c_src_ip_addr);
    318 
    319         for (idx = 0; idx < 2; idx++) {
    320             /* Set key type */
    321             soc_mem_field32_set(unit, mem, buf_p, v4typef[idx], 
    322                                 SOC_MEM_KEY_L3_ENTRY_2_IPV4MC_IPV4_MULTICAST);
    323 
    324             /* Set entry valid bit. */
    325             soc_mem_field32_set(unit, mem, buf_p, validf[idx], 1);
    326         }
    327 
    328         /* Set vlan id or L3_IIF. */
    329         if (l3cfg->l3c_vid < 4096) {
    330             soc_mem_field32_set(unit, mem, buf_p, IPV4MC__VLAN_IDf, l3cfg->l3c_vid);
    331         } else {
    332             soc_mem_field32_set(unit, mem, buf_p, IPV4MC__L3_IIFf, l3cfg->l3c_vid);
    333         }
    334 
    335         /* Set virtual router id. */
    336         soc_mem_field32_set(unit, mem, buf_p, IPV4MC__VRF_IDf, l3cfg->l3c_vrf);
    337     }
    338 
    339     return;
    340 }
    341 
    342 /*
    343  * Function:
    344  *      _bcm_tr3_l3_ent_parse
    345  * Purpose:
    346  *      Tr3 helper routine used to parse hw l3 entry to api format.
    347  * Parameters:
    348  *      unit      - (IN) SOC unit number. 
    349  *      mem       - (IN) L3 table memory.
    350  *      l3cfg     - (IN/OUT) l3 entry key & parse result.
    351  *      nh_idx    - (IN/OUT) Next hop index. 
    352  *      l3x_entry - (IN) hw buffer.
    353  * Returns:
    354  *      void
    355  */
    356 STATIC int
    357 _bcm_tr3_l3_ent_parse(int unit, soc_mem_t mem, _bcm_l3_cfg_t *l3cfg,
    358                                         int *nh_idx, void *l3x_entry)
    359 {
    360     int idx;                      /* Iteration index.            */
    361     int ipv6;                     /* Entry is IPv6 flag.         */
    362     uint32 *buf_p;                /* HW buffer address.          */ 
    363     _bcm_l3_fields_t *fld;        /* L3 table common fields.     */
    364     int embedded_nh = FALSE;
    365     soc_field_t ism_hitf[] = {HIT_0f, HIT_1f, HIT_2f};
    366     soc_field_t esm_hitf[] = {SRC_HITf, DST_HITf};
    367     int esm = FALSE;
    368     uint32 glp;
    369     
    370     buf_p = (uint32 *)l3x_entry;
    371     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
    372 
    373     /* Set table fields */
    374     if (BCM_TR3_MEM_IS_ESM(unit, mem)) {
    375         BCM_TR3_ESM_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
    376         esm = TRUE;
    377     } else {
    378         BCM_TR3_ISM_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);  
    379     }
    380 
    381     /* Check if embedded NH table is being used */
    382     embedded_nh = (mem == L3_ENTRY_2m && !ipv6) || 
    383                   (mem == L3_ENTRY_4m && ipv6)  ||
    384                   (mem == EXT_IPV4_UCAST_WIDEm) ||
    385                   (mem == EXT_IPV6_128_UCAST_WIDEm);
    386 
    387     /* Reset entry flags */
    388     l3cfg->l3c_flags = (ipv6) ? BCM_L3_IP6 : 0;
    389 
    390     /* Set hit bit. */
    391     if (esm) {
    392         /* For ESM Memory */
    393         if (soc_mem_field32_get(unit, mem, buf_p, esm_hitf[0])) {
    394             l3cfg->l3c_flags |= BCM_L3_S_HIT;
    395         }
    396         if (soc_mem_field32_get(unit, mem, buf_p, esm_hitf[1])) {
    397             l3cfg->l3c_flags |= BCM_L3_D_HIT;
    398         }
    399     } else {
    400         /* For ISM Memory */
    401         for (idx = 0; idx < COUNTOF(ism_hitf); idx++) {
    402             if (soc_mem_field32_get(unit, mem, buf_p, ism_hitf[idx])) {
    403                 l3cfg->l3c_flags |= BCM_L3_HIT;
    404             }
    405         }
    406     }
    407 
    408     /* Get priority override flag. */
    409     if (soc_mem_field32_get(unit, mem, buf_p, fld->rpe)) {
    410         l3cfg->l3c_flags |= BCM_L3_RPE;
    411     }
    412 
    413     /* Get destination discard flag. */
    414     if (SOC_MEM_FIELD_VALID(unit, mem, fld->dst_discard)) {
    415         if (soc_mem_field32_get(unit, mem, buf_p, fld->dst_discard)) {
    416             l3cfg->l3c_flags |= BCM_L3_DST_DISCARD;
    417         }
    418     }
    419 
    420     /* Get local addr bit. */
    421     if (SOC_MEM_FIELD_VALID(unit, mem, fld->local_addr)) {
    422         if (soc_mem_field32_get(unit, mem, buf_p, fld->local_addr)) {
    423             l3cfg->l3c_flags |= BCM_L3_HOST_LOCAL;
    424         }
    425     }
    426 
    427     /* Get classification group id. */
    428     l3cfg->l3c_lookup_class = 
    429         soc_mem_field32_get(unit, mem, buf_p, fld->class_id);
    430 
    431     /* Get priority. */
    432     l3cfg->l3c_prio = soc_mem_field32_get(unit, mem, buf_p, fld->priority);
    433 
    434     /* Get virtual router id. */
    435     l3cfg->l3c_vrf = soc_mem_field32_get(unit, mem, buf_p, fld->vrf);
    436 
    437     if (embedded_nh) {
    438         uint8 port_mask_len = 0, modid_mask_len = 0;
    439         uint32 temp = 0;
    440         
    441         if (nh_idx) {
    442             *nh_idx = BCM_XGS3_L3_INVALID_INDEX; /* Embedded NH */
    443         }
    444         l3cfg->l3c_intf = soc_mem_field32_get(unit, mem, buf_p,
    445                                            fld->l3_intf);
    446         soc_mem_mac_addr_get(unit, mem, buf_p, fld->mac_addr,
    447  		             l3cfg->l3c_mac_addr);
    448         glp = soc_mem_field32_get(unit, mem, buf_p, fld->glp);
    449         /* Determine length of port mask */
    450         temp = SOC_PORT_ADDR_MAX(unit);
    451         while (0 != temp) {
    452             port_mask_len++;
    453             temp >>= 1;
    454         }
    455         /* Determine length of modid mask */
    456         temp = SOC_MODID_MAX(unit);
    457         while (0 != temp) {
    458             modid_mask_len++;
    459             temp >>= 1;
    460         }
    461         
    462         if (glp & (1 << (port_mask_len + modid_mask_len))) {
    463             l3cfg->l3c_flags |= BCM_L3_TGID;
    464             l3cfg->l3c_port_tgid = glp & BCM_TGID_PORT_TRUNK_MASK(unit);
    465             l3cfg->l3c_modid = 0;
    466         } else {
    467             l3cfg->l3c_port_tgid = glp & SOC_PORT_ADDR_MAX(unit);
    468             l3cfg->l3c_modid = (glp >> port_mask_len)
    469                 & SOC_MODID_MAX(unit);
    470         }
    471     } else {
    472         /* Get next hop info. */
    473         if (nh_idx) {
    474             *nh_idx = soc_mem_field32_get(unit, mem, buf_p, fld->nh_idx);
    475         }
    476     }
    477 
    478     return BCM_E_NONE;
    479 }
    480 
    481 /*
    482  * Function:
    483  *      _bcm_tr3_l3_clear_hit
    484  * Purpose:
    485  *      Clear hit bit on l3 entry
    486  * Parameters:
    487  *      unit      - (IN)SOC unit number.
    488  *      mem       - (IN)L3 table memory.
    489  *      l3cfg     - (IN)l3 entry info. 
    490  *      l3x_entry - (IN)l3 entry filled hw buffer.
    491  * Returns:
    492  *      BCM_E_XXX
    493  */
    494 STATIC int
    495 _bcm_tr3_l3_clear_hit(int unit, soc_mem_t mem, _bcm_l3_cfg_t *l3cfg,
    496                                    void *l3x_entry, int l3_entry_idx)
    497 {
    498     uint32 *buf_p;                /* HW buffer address.       */ 
    499     soc_field_t hitf[] = { HIT_0f, HIT_1f, HIT_2f};
    500     int i;
    501 
    502     /* Input parameters check */
    503     if ((NULL == l3cfg) || (NULL == l3x_entry)) {
    504         return (BCM_E_PARAM);
    505     }
    506 
    507     /* Init memory pointers. */ 
    508     buf_p = (uint32 *)l3x_entry;
    509 
    510     /* If entry was not hit  there is nothing to clear */
    511     if (!(l3cfg->l3c_flags & BCM_L3_HIT)) {
    512         return (BCM_E_NONE);
    513     }
    514 
    515     /* Clear hit bits */
    516     for (i = 0; i < COUNTOF(hitf); i++) {
    517         soc_mem_field32_set(unit, mem, buf_p, hitf[i], 0);
    518     }
    519 
    520     /* Write entry back to hw. */
    521     return BCM_XGS3_MEM_WRITE(unit, mem, l3_entry_idx, buf_p);
    522 }
    523 
    524 /*
    525  * Function:
    526  *      _bcm_tr3_l3_ism_add
    527  * Purpose:
    528  *      Add and entry to Tr3 ISM L3 host table.
    529  * Parameters:
    530  *      unit   - (IN) SOC unit number.
    531  *      l3cfg  - (IN) L3 entry info.
    532  *      nh_idx - (IN) Next hop index.
    533  * Returns:
    534  *      BCM_E_XXX
    535  */
    536 STATIC int
    537 _bcm_tr3_l3_ism_add(int unit, _bcm_l3_cfg_t *l3cfg, int nh_idx)
    538 {
    539     int idx;                  /* Iteration index.        */
    540     int ipv6;
    541     uint32 *bufp;             /* Hardware buffer ptr     */
    542     soc_mem_t mem;            /* L3 table memory.        */  
    543     int rv = BCM_E_NONE;      /* Operation status.       */
    544     _bcm_l3_fields_t *fld;    /* L3 table common fields. */
    545     int embedded_nh = FALSE;
    546     uint32 glp, port_id, modid;
    547     _bcm_l3_intf_cfg_t l3_intf;
    548     l3_entry_1_entry_t l3v4_entry;    
    549     l3_entry_2_entry_t l3v4v6_entry;
    550     l3_entry_4_entry_t l3v6_ext_entry;
    551     soc_field_t hitf[] = {HIT_0f, HIT_1f, HIT_2f};
    552 
    553     /* Get entry type. */
    554     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
    555 
    556     /* Check if embedded NH table is being used */
    557     embedded_nh = BCM_TR3_L3_USE_EMBEDDED_NEXT_HOP(unit, l3cfg->l3c_intf, nh_idx);
    558 
    559     /* Get table memory. */
    560     BCM_TR3_ISM_L3_HOST_TABLE_MEM(unit, l3cfg->l3c_intf, ipv6, mem, nh_idx);
    561     
    562     /* Set table fields */
    563     BCM_TR3_ISM_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
    564 
    565     /* Assign entry buf based on table being used */
    566     BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem, bufp,
    567                                   l3v4_entry,
    568                                   l3v4v6_entry,
    569                                   l3v6_ext_entry);
    570 
    571     /* Prepare ISM host entry for addition. */
    572     BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_init(unit, mem, l3cfg, bufp));
    573 
    574     /* Set hit bit. */
    575     for (idx = 0; idx < COUNTOF(hitf); idx++) {
    576         if (l3cfg->l3c_flags & BCM_L3_HIT) {
    577             soc_mem_field32_set(unit, mem, bufp, hitf[idx], 1);
    578         }
    579     }
    580 
    581     /* Set priority override bit. */
    582     if (l3cfg->l3c_flags & BCM_L3_RPE) {
    583         soc_mem_field32_set(unit, mem, bufp, fld->rpe, 1);
    584     }
    585 
    586     /* Set destination discard bit. */
    587     if (l3cfg->l3c_flags & BCM_L3_DST_DISCARD) {
    588         soc_mem_field32_set(unit, mem, bufp, fld->dst_discard, 1);
    589     }
    590 
    591     /* Set local addr bit. */
    592     if (l3cfg->l3c_flags & BCM_L3_HOST_LOCAL) {
    593         soc_mem_field32_set(unit, mem, bufp, fld->local_addr, 1);
    594     }
    595 
    596     /* Set classification group id. */
    597     soc_mem_field32_set(unit, mem, bufp, fld->class_id, 
    598                         l3cfg->l3c_lookup_class);
    599     /*  Set priority. */
    600     soc_mem_field32_set(unit, mem, bufp, fld->priority, l3cfg->l3c_prio);
    601 
    602     if (embedded_nh) {
    603         sal_memset(&l3_intf, 0, sizeof(_bcm_l3_intf_cfg_t));
    604         BCM_XGS3_L3_INTF_IDX_SET(l3_intf, l3cfg->l3c_intf);
    605 
    606         BCM_XGS3_L3_MODULE_LOCK(unit);
    607         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, &l3_intf);
    608         BCM_XGS3_L3_MODULE_UNLOCK(unit);
    609         if (rv >= 0) {
    610             soc_mem_field32_set(unit, mem, bufp, fld->l3_oif, l3_intf.l3i_vid);
    611         }
    612 
    613         if (l3cfg->l3c_flags & BCM_L3_TGID) {
    614             port_id = (BCM_TGID_PORT_TRUNK_MASK(unit) & l3cfg->l3c_port_tgid);
    615             glp = (1 << (SOC_TRUNK_BIT_POS(unit))) |port_id;
    616         } else {
    617             port_id = (_BCM_TR3_L3_PORT_MASK & l3cfg->l3c_port_tgid);
    618             modid   = (_BCM_TR3_L3_MODID_MASK & l3cfg->l3c_modid) <<
    619                                                   _BCM_TR3_L3_MODID_SHIFT;
    620             glp = modid | port_id;
    621         }
    622 
    623         soc_mem_mac_addr_set(unit, mem, bufp,
    624                              fld->mac_addr, l3cfg->l3c_mac_addr);
    625         soc_mem_field32_set(unit, mem, bufp, fld->l3_intf, l3cfg->l3c_intf);
    626         soc_mem_field32_set(unit, mem, bufp, fld->glp, glp);
    627     } else {
    628         /* Set next hop index. */
    629         soc_mem_field32_set(unit, mem, bufp, fld->nh_idx, nh_idx);
    630     }
    631 
    632     /* Insert in ISM table */
    633     rv = soc_mem_insert(unit, mem, MEM_BLOCK_ANY, bufp);
    634 
    635     /* Handle host entry 'replace' actions */
    636     if ((BCM_E_EXISTS == rv) && (l3cfg->l3c_flags & BCM_L3_REPLACE)) {
    637         rv = BCM_E_NONE;
    638     }
    639     
    640     /* Write status check. */
    641     if ((rv >= 0) && (BCM_XGS3_L3_INVALID_INDEX == l3cfg->l3c_hw_index)) {
    642         (ipv6) ?  BCM_XGS3_L3_IP6_CNT(unit)++ : BCM_XGS3_L3_IP4_CNT(unit)++;
    643     }
    644 
    645     return rv;
    646 }
    647 
    648 /*
    649  * Function:
    650  *      _bcm_tr3_l3_esm_add
    651  * Purpose:
    652  *      Add and entry to Tr3 ESM L3 host table.
    653  * Parameters:
    654  *      unit   - (IN) SOC unit number.
    655  *      l3cfg  - (IN) L3 entry info.
    656  *      nh_idx - (IN) Next hop index.
    657  * Returns:
    658  *      BCM_E_XXX
    659  */
    660 STATIC int
    661 _bcm_tr3_l3_esm_add(int unit, _bcm_l3_cfg_t *l3cfg, int nh_idx)
    662 {
    663     int ipv6;
    664     uint32 *bufp;             /* Hardware buffer ptr */
    665     soc_mem_t mem;            /* ESM L3 table memory. */  
    666     soc_mem_t mem_data;       /* ESM L3 table memory - data only */  
    667     int rv = BCM_E_NONE;      /* Operation status.       */
    668     _bcm_l3_fields_t *fld;    /* L3 table common fields. */
    669     int tbl, tbl_free_entry;                 
    670     int embedded_nh = FALSE;
    671     uint32 glp, port_id, modid;
    672     _bcm_l3_intf_cfg_t l3_intf;
    673     ext_ipv4_ucast_entry_t          l3v4_entry;
    674     ext_ipv4_ucast_wide_entry_t     l3v4wide_entry;
    675     ext_ipv6_128_ucast_entry_t      l3v6_entry;
    676     ext_ipv6_128_ucast_wide_entry_t l3v6wide_entry;
    677 
    678     /* Get entry type. */
    679     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
    680 
    681     /* Check if embedded NH table is being used */
    682     embedded_nh = BCM_TR3_L3_USE_EMBEDDED_NEXT_HOP(unit, l3cfg->l3c_intf, nh_idx);
    683 
    684     /* Get table memory. */
    685     BCM_TR3_ESM_L3_HOST_TABLE_MEM(unit, l3cfg->l3c_intf, ipv6, mem, nh_idx);
    686     
    687     /* Set table fields */
    688     BCM_TR3_ESM_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
    689 
    690     /* Assign entry buf based on table being used */
    691     BCM_TR3_ESM_L3_HOST_ENTRY_BUF(ipv6, mem, bufp,
    692                                   l3v4_entry,
    693                                   l3v4wide_entry,
    694                                   l3v6_entry,
    695                                   l3v6wide_entry);
    696 
    697     /* Prepare ESM host entry for addition. */
    698     BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_init(unit, mem, l3cfg, bufp));
    699 
    700     /* Set hit bit. */
    701     if (l3cfg->l3c_flags & BCM_L3_HIT) {
    702         soc_mem_field32_set(unit, mem, bufp, fld->hit, 1);
    703     }
    704 
    705     /* Set priority override bit. */
    706     if (l3cfg->l3c_flags & BCM_L3_RPE) {
    707         soc_mem_field32_set(unit, mem, bufp, fld->rpe, 1);
    708     }
    709 
    710     /* Set destination discard bit. */
    711     if (l3cfg->l3c_flags & BCM_L3_DST_DISCARD) {
    712         if (SOC_MEM_FIELD_VALID(unit, mem, fld->dst_discard)) {
    713             soc_mem_field32_set(unit, mem, bufp, fld->dst_discard, 1);
    714         }
    715     }
    716 
    717     /* Set local addr bit. */
    718     if (l3cfg->l3c_flags & BCM_L3_HOST_LOCAL) {
    719         if (SOC_MEM_FIELD_VALID(unit, mem, fld->local_addr)) {
    720             soc_mem_field32_set(unit, mem, bufp, fld->local_addr, 1);
    721         }
    722     }
    723 
    724     /* Set classification group id. */
    725     soc_mem_field32_set(unit, mem, bufp, fld->class_id, 
    726                         l3cfg->l3c_lookup_class);
    727     /*  Set priority. */
    728     soc_mem_field32_set(unit, mem, bufp, fld->priority, l3cfg->l3c_prio);
    729 
    730     if (embedded_nh) {
    731         sal_memset(&l3_intf, 0, sizeof(_bcm_l3_intf_cfg_t));
    732         BCM_XGS3_L3_INTF_IDX_SET(l3_intf, l3cfg->l3c_intf);
    733 
    734         BCM_XGS3_L3_MODULE_LOCK(unit);
    735         rv = BCM_XGS3_L3_HWCALL_EXEC(unit, if_get) (unit, &l3_intf);
    736         BCM_XGS3_L3_MODULE_UNLOCK(unit);
    737         if (rv >= 0) {
    738             soc_mem_field32_set(unit, mem, bufp, fld->l3_oif, l3_intf.l3i_vid);
    739         }
    740 
    741         if (l3cfg->l3c_flags & BCM_L3_TGID) {
    742             port_id = (BCM_TGID_PORT_TRUNK_MASK(unit) & l3cfg->l3c_port_tgid);
    743             glp = (1 << (SOC_TRUNK_BIT_POS(unit)))  | port_id;
    744         } else {
    745             port_id = (_BCM_TR3_L3_PORT_MASK & l3cfg->l3c_port_tgid);
    746             modid   = (_BCM_TR3_L3_MODID_MASK & l3cfg->l3c_modid) <<
    747                                                   _BCM_TR3_L3_MODID_SHIFT;
    748             glp = modid | port_id;
    749         }
    750 
    751         soc_mem_mac_addr_set(unit, mem, bufp,
    752                              fld->mac_addr, l3cfg->l3c_mac_addr);
    753         soc_mem_field32_set(unit, mem, bufp, fld->l3_intf, l3cfg->l3c_intf);
    754         soc_mem_field32_set(unit, mem, bufp, fld->glp, glp);
    755     } else {
    756         /* Set next hop index. */
    757         soc_mem_field32_set(unit, mem, bufp, fld->nh_idx, nh_idx);
    758     }
    759 
    760     /* Write to ESM table */
    761     BCM_TR3_ESM_TBL_ENUMERATE(mem, tbl);
    762 
    763     /* Perform lookup */
    764     rv = soc_tr3_search_ext_mem(unit, &mem, bufp, &tbl_free_entry);
    765     if (BCM_E_NONE == rv) { /* Entry exists */
    766         if (l3cfg->l3c_flags & BCM_L3_REPLACE) {
    767             l3cfg->l3c_hw_index = tbl_free_entry;
    768         } else {
    769             return rv;
    770         }
    771     } else if (BCM_E_NOT_FOUND == rv) {
    772         tbl_free_entry = _TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl);
    773         rv = BCM_E_NONE;
    774 
    775     } else {
    776         return rv;
    777     }
    778     
    779     if (tbl_free_entry <= soc_mem_index_max(unit, mem)) {
    780         BCM_IF_ERROR_RETURN(soc_mem_write( unit, mem, MEM_BLOCK_ALL,
    781                               tbl_free_entry, bufp));
    782         
    783         /* Point to next free entry in the table */
    784         _TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl) += 1;
    785         tbl_free_entry = _TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl);
    786 
    787         /* Set invalid entry marker */
    788         if (tbl_free_entry <= soc_mem_index_max(unit, mem)) {
    789             switch(mem) {
    790               case EXT_IPV4_UCASTm:
    791                 mem_data = EXT_L3_UCAST_DATA_IPV4m;
    792                 break;
    793               case EXT_IPV4_UCAST_WIDEm:
    794                 mem_data = EXT_L3_UCAST_DATA_WIDE_IPV4m;
    795                 break;
    796               case EXT_IPV6_128_UCASTm:
    797                 mem_data = EXT_L3_UCAST_DATA_IPV6_128m;
    798                 break;
    799               case EXT_IPV6_128_UCAST_WIDEm:
    800                 mem_data = EXT_L3_UCAST_DATA_WIDE_IPV6_128m;
    801                 break;
    802               default:
    803                 return BCM_E_INTERNAL; /* should never happen */
    804             }
    805             BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem_data, MEM_BLOCK_ANY,
    806                          tbl_free_entry, bufp));
    807             soc_mem_field32_set(unit, mem_data, bufp, CLASS_IDf,
    808                                       _TR3_ESM_HOST_ENTRY_INVALID_MARKER);
    809             BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem_data, MEM_BLOCK_ALL, 
    810                                  tbl_free_entry, bufp));
    811         }
    812   
    813     } else {
    814         rv = (BCM_E_FULL);
    815     }
    816     
    817     /* Write status check. */
    818     if ((rv >= 0) && (BCM_XGS3_L3_INVALID_INDEX == l3cfg->l3c_hw_index)) {
    819         (ipv6) ?  BCM_XGS3_L3_IP6_CNT(unit)++ : BCM_XGS3_L3_IP4_CNT(unit)++;
    820     }
    821 
    822     return rv;
    823 }
    824 
    825 /*
    826  * Function:
    827  *      _bcm_tr3_l3_ism_get
    828  * Purpose:
    829  *      Get an entry from Tr3 ISM L3 host table.
    830  * Parameters:
    831  *      unit     - (IN) SOC unit number.
    832  *      l3cfg    - (IN/OUT) L3 entry  lookup key & search result.
    833  *      nh_index - (IN/OUT) Next hop index.
    834  *      embd     - (OUT) If TRUE, entry was found as embedded NH.
    835  * Returns:
    836  *      BCM_E_XXX
    837  */
    838 STATIC int
    839 _bcm_tr3_l3_ism_get(int unit, _bcm_l3_cfg_t *l3cfg, int *nh_idx, int *embd)
    840 {
    841     int ipv6;                                   /* IPv6 entry indicator.    */
    842     int clear_hit;                              /* Clear hit bit.           */
    843     int rv = BCM_E_NONE;                        /* Operation return status. */
    844     soc_mem_t mem, mem_ext;                     /* L3 table memories        */
    845     uint32 *buf_key, *buf_entry;                /* Key and entry buffer ptrs*/
    846     l3_entry_1_entry_t l3v4_key, l3v4_entry;    /* Lookup key and entry     */
    847     l3_entry_2_entry_t l3v4v6_key, l3v4v6_entry;     /* Lookup key and entry*/
    848     l3_entry_4_entry_t l3v6_ext_key, l3v6_ext_entry; /* Lookup key and entry*/
    849 
    850     /* Indexed NH entry */
    851     *embd = _BCM_TR3_HOST_ENTRY_NOT_FOUND;
    852 
    853     /* Get entry type. */
    854     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
    855 
    856     /* Preserve clear_hit value. */
    857     clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR;
    858 
    859     /* Table memories */
    860     if (ipv6) {
    861         mem = BCM_XGS3_L3_MEM(unit, v6); mem_ext = BCM_XGS3_L3_MEM(unit, v6_4);
    862     } else {
    863         mem = BCM_XGS3_L3_MEM(unit, v4); mem_ext = BCM_XGS3_L3_MEM(unit, v4_2);
    864     }
    865 
    866     /* Assign entry-key buf based on table being used */
    867     BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem, buf_key,
    868                                         l3v4_key,
    869                                         l3v4v6_key,
    870                                         l3v6_ext_key);
    871 
    872     /* Assign entry buf based on table being used */
    873     BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry,
    874                                         l3v4_entry,
    875                                         l3v4v6_entry,
    876                                         l3v6_ext_entry);
    877     /* Prepare lookup key. */
    878     BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_init(unit, mem, l3cfg, buf_key));
    879 
    880     /* Perform lookup */
    881     rv = soc_mem_generic_lookup(unit, mem, MEM_BLOCK_ANY,
    882                                 _BCM_TR3_L3_MEM_BANKS_ALL,
    883                                 buf_key, buf_entry, &l3cfg->l3c_hw_index);
    884     if (BCM_SUCCESS(rv)) {
    885         /* Indexed NH entry */
    886         *embd = FALSE;
    887         /* Extract entry info. */
    888         BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_parse(unit, mem, l3cfg,
    889                                                   nh_idx, buf_entry));
    890         /* Clear the HIT bit */
    891         if (clear_hit) {
    892             BCM_IF_ERROR_RETURN(_bcm_tr3_l3_clear_hit(unit, mem,
    893                                        l3cfg, buf_entry, l3cfg->l3c_hw_index));
    894         }
    895     } else if ((BCM_E_NOT_FOUND == rv) &&
    896                (soc_feature(unit, soc_feature_l3_extended_host_entry))) {
    897         /* Search in the extended tables only if the extended host entry
    898          * feature is supported and if the entry was not found in the 
    899          * regular host entry */
    900 
    901         /* Assign entry-key buf based on table being used */
    902         BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_key,
    903                                             l3v4_key,
    904                                             l3v4v6_key,
    905                                             l3v6_ext_key);
    906 
    907         /* Assign entry buf based on table being used */
    908         BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_entry,
    909                                             l3v4_entry,
    910                                             l3v4v6_entry,
    911                                             l3v6_ext_entry);
    912 
    913         /* Prepare lookup key. */
    914         BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_init(unit, mem_ext, l3cfg, buf_key));
    915 
    916         /* Perform lookup hw. */
    917         rv = soc_mem_generic_lookup(unit, mem_ext, MEM_BLOCK_ANY,
    918                                     _BCM_TR3_L3_MEM_BANKS_ALL,
    919                                     buf_key, buf_entry, &l3cfg->l3c_hw_index);
    920 
    921         if (BCM_SUCCESS(rv)) {
    922 
    923             /* Embedded NH entry */
    924             *embd = TRUE;
    925             /* Extract entry info. */
    926             BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_parse(unit, mem_ext, l3cfg,
    927                                                           nh_idx, buf_entry));
    928             /* Clear the HIT bit */
    929             if (clear_hit) {
    930                 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_clear_hit(unit, mem_ext,
    931                                               l3cfg, buf_entry, l3cfg->l3c_hw_index));
    932             }
    933         }
    934     } 
    935      
    936     return rv;
    937 }
    938 
    939 /*
    940  * Function:
    941  *      _bcm_tr3_l3_esm_get
    942  * Purpose:
    943  *      Get an entry from Tr3 ESM L3 host table.
    944  * Parameters:
    945  *      unit     - (IN) SOC unit number.
    946  *      l3cfg    - (IN/OUT) L3 entry  lookup key & search result.
    947  *      nh_index - (IN/OUT) Next hop index.
    948  *      embd     - (OUT) If TRUE, entry was found as embedded NH.
    949  * Returns:
    950  *      BCM_E_XXX
    951  */
    952 STATIC int
    953 _bcm_tr3_l3_esm_get(int unit, _bcm_l3_cfg_t *l3cfg, int *nh_idx, int *embd)
    954 {
    955     int ipv6;                                   /* IPv6 entry indicator.    */
    956     int clear_hit;                              /* Clear hit bit.           */
    957     int rv = BCM_E_NONE;                        /* Operation return status. */
    958     soc_mem_t mem;                              /* L3 table memories        */
    959     uint32 *buf_key;                            /* Key and entry buffer ptrs*/
    960     ext_ipv4_ucast_entry_t          l3v4_key;
    961     ext_ipv4_ucast_wide_entry_t     l3v4wide_key;
    962     ext_ipv6_128_ucast_entry_t      l3v6_key;
    963     ext_ipv6_128_ucast_wide_entry_t l3v6wide_key;
    964 
    965     /* Indexed NH entry */
    966     *embd = _BCM_TR3_HOST_ENTRY_NOT_FOUND;
    967 
    968     /* Get entry type. */
    969     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
    970 
    971     /* Preserve clear_hit value. */
    972     clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR;
    973 
    974     /* Table memories */
    975     if (ipv6) {
    976         mem = BCM_XGS3_L3_MEM(unit, v6_esm);
    977     } else {
    978         mem = BCM_XGS3_L3_MEM(unit, v4_esm);
    979     }
    980 
    981     /* Assign entry-key buf based on table being used */
    982     BCM_TR3_ESM_L3_HOST_ENTRY_BUF(ipv6, mem, buf_key,
    983                                         l3v4_key,
    984                                         l3v4wide_key,
    985                                         l3v6_key,
    986                                         l3v6wide_key);
    987 
    988     /* Prepare lookup key. */
    989     BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_init(unit, mem, l3cfg, buf_key));
    990 
    991     /* Perform lookup */
    992     rv = soc_tr3_search_ext_mem(unit, &mem, buf_key, &l3cfg->l3c_hw_index);
    993 
    994     if (BCM_SUCCESS(rv)) {
    995         /* Set to true if the entry was found in a wide host entry */
    996         *embd = ((mem == BCM_XGS3_L3_MEM(unit, v6_esm_wide)) ||
    997                  (mem == BCM_XGS3_L3_MEM(unit, v4_esm_wide))) ? TRUE : FALSE;
    998 
    999         if ((*embd) &&
   1000             (!soc_feature(unit, soc_feature_l3_extended_host_entry))) {
   1001             /* Flag error if the entry was found in the extended host table
   1002              * but the extended host entries are not supported
   1003              * NOTE: This should never occur, as the 'host add' operation
   1004              * should take care of this. */  
   1005             return BCM_E_PARAM;
   1006         }        
   1007 
   1008         BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ANY,
   1009                                             l3cfg->l3c_hw_index, buf_key));
   1010         /* Extract entry info. */
   1011         BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_parse(unit, mem, l3cfg,
   1012                                                   nh_idx, buf_key));
   1013         /* Clear the HIT bit */
   1014         if (clear_hit) {
   1015             BCM_IF_ERROR_RETURN(_bcm_tr3_l3_clear_hit(unit, mem,
   1016                                        l3cfg, buf_key, l3cfg->l3c_hw_index));
   1017         }
   1018     }
   1019 
   1020     return rv;
   1021 }
   1022 
   1023 /*
   1024  * Function:
   1025  *      _bcm_tr3_l3_ism_del
   1026  * Purpose:
   1027  *      Delete an entry from Tr3 ISM L3 host table.
   1028  * Parameters:
   1029  *      unit     - (IN) SOC unit number.
   1030  *      l3cfg    - (IN/OUT) L3 entry  lookup key & search result.
   1031  *      nh_index - (IN/OUT) Next hop index.
   1032  * Returns:
   1033  *      BCM_E_XXX
   1034  */
   1035 STATIC int
   1036 _bcm_tr3_l3_ism_del(int unit, _bcm_l3_cfg_t *l3cfg)
   1037 {
   1038     int ipv6;                          /* IPv6 entry indicator.*/
   1039     soc_mem_t mem, mem_ext;            /* L3 table memory.     */  
   1040     int rv = BCM_E_NONE;               /* Operation status.    */
   1041     uint32 *buf_entry;                 /* Entry buffer ptrs    */
   1042     l3_entry_1_entry_t l3v4_entry;     /* Lookup entry */
   1043     l3_entry_2_entry_t l3v4v6_entry;   /* Lookup entry */
   1044     l3_entry_4_entry_t l3v6_ext_entry; /* Lookup entry */
   1045 
   1046     /* Get entry type. */
   1047     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
   1048 
   1049     if (ipv6) {
   1050         mem = BCM_XGS3_L3_MEM(unit, v6); mem_ext = BCM_XGS3_L3_MEM(unit, v6_4);
   1051     } else {
   1052         mem = BCM_XGS3_L3_MEM(unit, v4); mem_ext = BCM_XGS3_L3_MEM(unit, v4_2);
   1053     }
   1054 
   1055     /* Assign entry-key buf based on table being used */
   1056     BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry,
   1057                                         l3v4_entry,
   1058                                         l3v4v6_entry,
   1059                                         l3v6_ext_entry);
   1060     /* Prepare lookup key. */
   1061     BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_init(unit, mem, l3cfg, buf_entry));
   1062 
   1063     rv = soc_mem_delete(unit, mem, MEM_BLOCK_ANY, (void*) buf_entry);
   1064 
   1065     if ((BCM_E_NOT_FOUND == rv) &&
   1066         (soc_feature(unit, soc_feature_l3_extended_host_entry))) { 
   1067         /* Delete from  the extended tables only if the extended host entry
   1068          * feature is supported and if the entry was not found in the 
   1069          * regular host entry */
   1070 
   1071         /* Assign entry-key buf based on table being used */
   1072         BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_entry,
   1073                                             l3v4_entry,
   1074                                             l3v4v6_entry,
   1075                                             l3v6_ext_entry);
   1076         /* Prepare lookup key. */
   1077         BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_init(unit, mem_ext, l3cfg, buf_entry));
   1078     
   1079         rv = soc_mem_delete(unit, mem_ext, MEM_BLOCK_ANY, (void*) buf_entry);
   1080     }
   1081 
   1082     /* Write status check. */
   1083     if (BCM_SUCCESS(rv)) {
   1084         (ipv6) ?  BCM_XGS3_L3_IP6_CNT(unit)-- : BCM_XGS3_L3_IP4_CNT(unit)--;
   1085     }
   1086 
   1087     return rv;
   1088 }
   1089 
   1090 /*
   1091  * Function:
   1092  *      _bcm_tr3_l3_esm_del
   1093  * Purpose:
   1094  *      Delete an entry from Tr3 ESM L3 host table.
   1095  * Parameters:
   1096  *      unit     - (IN) SOC unit number.
   1097  *      l3cfg    - (IN/OUT) L3 entry  lookup key & search result.
   1098  *      nh_index - (IN/OUT) Next hop index.
   1099  * Returns:
   1100  *      BCM_E_XXX
   1101  */
   1102 STATIC int
   1103 _bcm_tr3_l3_esm_del(int unit, _bcm_l3_cfg_t *l3cfg)
   1104 {
   1105     int tbl;                  /* Table enumeration    */
   1106     int ipv6;                 /* IPv6 entry indicator.*/
   1107     int l3_entry_idx;         /* Index of L3 host entry  */
   1108     void *null_entry;         /* Null entry for delete opearation */
   1109     int rv = BCM_E_NONE;      /* Operation status.    */
   1110     soc_mem_t mem;            /* L3 table memory.     */  
   1111     soc_mem_t mem_data;       /* L3 table memory - associated data */  
   1112     uint32 *buf_key, *buf_entry = NULL; /* Key and entry buffer ptrs*/
   1113     ext_ipv4_ucast_entry_t          l3v4_entry;    
   1114     ext_ipv4_ucast_wide_entry_t     l3v4wide_entry;
   1115     ext_ipv6_128_ucast_entry_t      l3v6_entry; 
   1116     ext_ipv6_128_ucast_wide_entry_t l3v6wide_entry;
   1117 
   1118     /* Get entry type. */
   1119     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
   1120 
   1121     if (ipv6) {
   1122         mem = BCM_XGS3_L3_MEM(unit, v6_esm);
   1123     } else {
   1124         mem = BCM_XGS3_L3_MEM(unit, v4_esm); 
   1125     }
   1126 
   1127     /* Assign entry-key buf based on table being used */
   1128     BCM_TR3_ESM_L3_HOST_ENTRY_BUF(ipv6, mem, buf_key,
   1129                                         l3v4_entry,
   1130                                         l3v4wide_entry,
   1131                                         l3v6_entry,
   1132                                         l3v6wide_entry);
   1133 
   1134     /* Prepare lookup key. */
   1135     BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_init(unit, mem, l3cfg, buf_key));
   1136 
   1137     /* Lookup TCAM with the key provided */
   1138     rv = soc_tr3_search_ext_mem(unit, &mem, buf_key, &l3_entry_idx);
   1139     if (BCM_SUCCESS(rv)) {
   1140 
   1141         if ((!soc_feature(unit, soc_feature_l3_extended_host_entry)) &&
   1142             ((mem == EXT_IPV4_UCAST_WIDEm) || (mem == EXT_IPV6_128_UCAST_WIDEm))) {
   1143             /* Flag error if the entry was found in the extended host table
   1144              * of ESM but the extended host entries are not supported
   1145              * NOTE: This should never occur, as the 'host add' operation
   1146              * should take care of this. */  
   1147             return BCM_E_PARAM;
   1148         }
   1149 
   1150         /* Write null entry at l3_entry_idx, clear vbit */
   1151         null_entry = soc_mem_entry_null(unit, mem);
   1152         BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL,
   1153                                          l3_entry_idx, null_entry));
   1154         soc_tr3_set_vbit(unit, mem, l3_entry_idx, 0);
   1155 
   1156         /* Move the last valid entry in place of deleted entry to keep
   1157          * entries contiguous - this works because host entry hit is 
   1158          * an exact match, not LPM */
   1159         BCM_TR3_ESM_TBL_ENUMERATE(mem, tbl);
   1160         BCM_TR3_ESM_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry,
   1161                                             l3v4_entry,
   1162                                             l3v4wide_entry,
   1163                                             l3v6_entry,
   1164                                             l3v6wide_entry);
   1165         /* Read last entry */
   1166         BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ANY,
   1167                             (_TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl) - 1),
   1168                             buf_entry));
   1169         /* Write last entry to index of entry that was deleted */
   1170         /* This entry is now valid */
   1171         BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL,
   1172                             l3_entry_idx, buf_entry));
   1173 
   1174         /* The last entry is now invalid because it has been moved in place 
   1175          * of the deleted entry. Write invalid entry marker here */
   1176         soc_tr3_set_vbit(unit, mem,
   1177                          (_TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl) - 1), 0);
   1178         switch(mem) {
   1179           case EXT_IPV4_UCASTm:
   1180               mem_data = EXT_L3_UCAST_DATA_IPV4m;
   1181             break;
   1182           case EXT_IPV4_UCAST_WIDEm:
   1183               mem_data = EXT_L3_UCAST_DATA_WIDE_IPV4m;
   1184             break;
   1185           case EXT_IPV6_128_UCASTm:
   1186               mem_data = EXT_L3_UCAST_DATA_IPV6_128m;
   1187             break;
   1188           case EXT_IPV6_128_UCAST_WIDEm:
   1189               mem_data = EXT_L3_UCAST_DATA_WIDE_IPV6_128m;
   1190             break;
   1191           default:
   1192               mem_data = INVALIDm;
   1193             break;
   1194         }
   1195         BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem_data, MEM_BLOCK_ANY,
   1196                      (_TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl)-1),
   1197                      buf_entry));
   1198         soc_mem_field32_set(unit, mem_data, buf_entry, CLASS_IDf,
   1199                                             _TR3_ESM_HOST_ENTRY_INVALID_MARKER);
   1200         BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem_data, MEM_BLOCK_ALL,
   1201                                   (_TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl) - 1),
   1202                                   buf_entry));
   1203         
   1204         /* Update free entry pointer */
   1205         _TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl) -= 1;
   1206     }
   1207 
   1208     /* Write status check. */
   1209     if (BCM_SUCCESS(rv)) {
   1210         (ipv6) ?  BCM_XGS3_L3_IP6_CNT(unit)-- : BCM_XGS3_L3_IP4_CNT(unit)--;
   1211     }
   1212 
   1213     return rv;
   1214 }
   1215 
   1216 STATIC INLINE int
   1217 _bcm_tr3_ip_key_to_l3cfg(int unit, bcm_l3_key_t *ipkey, _bcm_l3_cfg_t *l3cfg)
   1218 {
   1219     int ipv6;           /* IPV6 key.                     */
   1220 
   1221     /* Input parameters check */
   1222     if ((NULL == ipkey) || (NULL == l3cfg)) {
   1223         return (BCM_E_PARAM);
   1224     }
   1225 
   1226     /* Reset destination buffer first. */
   1227     sal_memset(l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   1228 
   1229     ipv6 = (ipkey->l3k_flags & BCM_L3_IP6);
   1230 
   1231     /* Set vrf id. */
   1232     l3cfg->l3c_vrf = ipkey->l3k_vrf;
   1233     l3cfg->l3c_vid = ipkey->l3k_vid;
   1234 
   1235     if (ipv6) {
   1236         if (BCM_IP6_MULTICAST(ipkey->l3k_ip6_addr)) {
   1237             /* Copy ipv6 group, source & vid. */
   1238             sal_memcpy(l3cfg->l3c_ip6, ipkey->l3k_ip6_addr, sizeof(bcm_ip6_t));
   1239             sal_memcpy(l3cfg->l3c_sip6, ipkey->l3k_sip6_addr,
   1240                        sizeof(bcm_ip6_t));
   1241             l3cfg->l3c_vid = ipkey->l3k_vid;
   1242             l3cfg->l3c_flags = (BCM_L3_IP6 | BCM_L3_IPMC);
   1243         } else {
   1244             /* Copy ipv6 address. */
   1245             sal_memcpy(l3cfg->l3c_ip6, ipkey->l3k_ip6_addr, sizeof(bcm_ip6_t));
   1246             l3cfg->l3c_flags = BCM_L3_IP6;
   1247         }
   1248     } else {
   1249         if (BCM_IP4_MULTICAST(ipkey->l3k_ip_addr)) {
   1250             /* Copy ipv4 mcast group, source & vid. */
   1251             l3cfg->l3c_ip_addr = ipkey->l3k_ip_addr;
   1252             l3cfg->l3c_src_ip_addr = ipkey->l3k_sip_addr;
   1253             l3cfg->l3c_vid = ipkey->l3k_vid;
   1254             l3cfg->l3c_flags = BCM_L3_IPMC;
   1255         } else {
   1256             /* Copy ipv4 address . */
   1257             l3cfg->l3c_ip_addr = ipkey->l3k_ip_addr;
   1258         }
   1259     }
   1260     return (BCM_E_NONE);
   1261 }
   1262 
   1263 STATIC INLINE int
   1264 _bcm_tr3_l3cfg_to_ipkey(int unit, bcm_l3_key_t *ipkey, _bcm_l3_cfg_t *l3cfg)
   1265 {
   1266     /* Input parameters check */
   1267     if ((NULL == ipkey) || (NULL == l3cfg)) {
   1268         return (BCM_E_PARAM);
   1269     }
   1270 
   1271     /* Reset destination buffer first. */
   1272     sal_memset(ipkey, 0, sizeof(bcm_l3_key_t));
   1273 
   1274     ipkey->l3k_vrf = l3cfg->l3c_vrf;
   1275     ipkey->l3k_vid = l3cfg->l3c_vid;
   1276 
   1277     if (l3cfg->l3c_flags & BCM_L3_IP6) {
   1278         if (l3cfg->l3c_flags & BCM_L3_IPMC) {
   1279             /* Copy ipv6 group, source & vid. */
   1280             sal_memcpy(ipkey->l3k_ip6_addr, l3cfg->l3c_ip6, sizeof(bcm_ip6_t));
   1281             sal_memcpy(ipkey->l3k_sip6_addr, l3cfg->l3c_sip6,
   1282                        sizeof(bcm_ip6_t));
   1283             ipkey->l3k_vid = l3cfg->l3c_vid;
   1284         } else {
   1285             /* Copy ipv6 address. */
   1286             sal_memcpy(ipkey->l3k_ip6_addr, l3cfg->l3c_ip6, sizeof(bcm_ip6_t));
   1287         }
   1288     } else {
   1289         if (l3cfg->l3c_flags & BCM_L3_IPMC) {
   1290             /* Copy ipv4 mcast group, source & vid. */
   1291             ipkey->l3k_ip_addr = l3cfg->l3c_ip_addr;
   1292             ipkey->l3k_sip_addr = l3cfg->l3c_src_ip_addr;
   1293             ipkey->l3k_vid = l3cfg->l3c_vid;
   1294         } else {
   1295             /* Copy ipv4 address . */
   1296             ipkey->l3k_ip_addr = l3cfg->l3c_ip_addr;
   1297         }
   1298     }
   1299     /* Store entry flags. */
   1300     ipkey->l3k_flags = l3cfg->l3c_flags;
   1301     return (BCM_E_NONE);
   1302 }
   1303 
   1304 int
   1305 bcm_tr3_l3_conflict_get(int unit, bcm_l3_key_t *ipkey, bcm_l3_key_t *cf_array,
   1306                         int cf_max, int *cf_count)
   1307 {
   1308     _bcm_l3_cfg_t l3cfg;
   1309     uint32 *bufk, *bufp;
   1310     soc_mem_t mem;
   1311     int nh_idx, index, rv = BCM_E_NONE;
   1312     _bcm_l3_fields_t *fld;
   1313     l3_entry_1_entry_t l3v4_key, l3v4_entry;    
   1314     l3_entry_2_entry_t l3v4v6_key, l3v4v6_entry;
   1315     l3_entry_4_entry_t l3v6_ext_key, l3v6_ext_entry;
   1316     _soc_ism_mem_banks_t mem_banks;
   1317     uint8 i, bidx, num_ent;
   1318     uint32 result, bucket_index, *keyt;
   1319     uint32 l3_entry[SOC_MAX_MEM_WORDS];
   1320     int ipmc, ipv6, embedded_nh;
   1321     uint32 key_type_1[] = {SOC_MEM_KEY_L3_ENTRY_1_IPV4UC_IPV4_UNICAST, -1, -1};
   1322     uint32 key_type_2[] = {SOC_MEM_KEY_L3_ENTRY_2_IPV4UC_IPV4_UNICAST, 
   1323                            SOC_MEM_KEY_L3_ENTRY_2_IPV4MC_IPV4_MULTICAST,
   1324                            SOC_MEM_KEY_L3_ENTRY_2_IPV6UC_IPV6_UNICAST};
   1325     uint32 key_type_4[] = {SOC_MEM_KEY_L3_ENTRY_4_IPV6UC_IPV6_UNICAST,
   1326                            SOC_MEM_KEY_L3_ENTRY_4_IPV6MC_IPV6_MULTICAST, -1};
   1327 
   1328     /*  Make sure module was initialized. */
   1329     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   1330         return (BCM_E_INIT);
   1331     }
   1332 
   1333     /* Input parameters check. */
   1334     if ((NULL == ipkey) || (NULL == cf_count) || 
   1335         (NULL == cf_array) || (cf_max <= 0)) {
   1336         return (BCM_E_PARAM);
   1337     }
   1338 
   1339     /* The wider entry may be specified or not */
   1340     embedded_nh = ipkey->l3k_flags & BCM_L3_DEREFERENCED_NEXTHOP;
   1341     nh_idx = (embedded_nh) ? BCM_XGS3_L3_INVALID_INDEX : 0;
   1342 
   1343     /* Translate lookup key to l3cfg format. */
   1344     BCM_IF_ERROR_RETURN(_bcm_tr3_ip_key_to_l3cfg(unit, ipkey, &l3cfg));
   1345     
   1346     /* Get entry type. */
   1347     ipv6 = (l3cfg.l3c_flags & BCM_L3_IP6);
   1348     ipmc = (l3cfg.l3c_flags & BCM_L3_IPMC);
   1349 
   1350     /* Get table memory. */
   1351     BCM_TR3_ISM_L3_HOST_TABLE_MEM(unit, l3cfg.l3c_intf, ipv6, mem, nh_idx);
   1352     
   1353     if (!embedded_nh) {
   1354         /* Look for the entry in wider tables */
   1355         if (ipv6) {
   1356             mem = BCM_XGS3_L3_MEM(unit, v6_4);
   1357         } else {
   1358             mem = BCM_XGS3_L3_MEM(unit, v4_2);
   1359         }
   1360         /* Assign entry-key buf based on table being used */
   1361         BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem, bufk, l3v4_key,
   1362                                       l3v4v6_key, l3v6_ext_key);
   1363         
   1364         /* Assign entry buf based on table being used */
   1365         BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem, bufp, l3v4_entry,
   1366                                       l3v4v6_entry, l3v6_ext_entry);
   1367         /* Prepare lookup key. */
   1368         if (ipmc) {
   1369             _bcm_tr3_l3_ipmc_ent_init(unit, bufk, &l3cfg);
   1370         } else {
   1371             BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_init(unit, mem, &l3cfg, bufk));
   1372         }
   1373         
   1374         /* Perform lookup */
   1375         rv = soc_mem_generic_lookup(unit, mem, MEM_BLOCK_ANY,
   1376                                     _BCM_TR3_L3_MEM_BANKS_ALL,
   1377                                     bufk, bufp, &l3cfg.l3c_hw_index);
   1378         if (BCM_SUCCESS(rv)) {
   1379             embedded_nh = BCM_L3_DEREFERENCED_NEXTHOP;
   1380         }
   1381     }
   1382     
   1383     /* Bump up the size conditionally */
   1384     mem = (embedded_nh || ipmc) ? (ipv6 ? L3_ENTRY_4m : L3_ENTRY_2m) :
   1385                                   (ipv6 ? L3_ENTRY_2m : L3_ENTRY_1m);
   1386 
   1387     /* Set the key type field array */
   1388     keyt = (embedded_nh || ipmc) ? (ipv6 ? key_type_4 : key_type_2) : 
   1389                                    (ipv6 ? key_type_2 : key_type_1);
   1390     
   1391     /* Set table fields */
   1392     BCM_TR3_ISM_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
   1393 
   1394     /* Assign entry buf based on table being used */
   1395     BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem, bufp, l3v4_entry,
   1396                                   l3v4v6_entry, l3v6_ext_entry);
   1397 
   1398     /* Prepare ISM host entry */
   1399     if (ipmc) {
   1400         _bcm_tr3_l3_ipmc_ent_init(unit, bufp, &l3cfg);
   1401     } else {
   1402         BCM_IF_ERROR_RETURN(_bcm_tr3_l3_ent_init(unit, mem, &l3cfg, bufp));
   1403     }
   1404         
   1405     *cf_count = 0;
   1406 
   1407     rv = soc_ism_get_banks_for_mem(unit, mem, mem_banks.banks, 
   1408                                    mem_banks.bank_size, &mem_banks.count);
   1409     if (SOC_FAILURE(rv)) {
   1410         return BCM_E_INTERNAL;
   1411     }
   1412     if (mem_banks.count == 0) {
   1413         return BCM_E_NOT_FOUND;
   1414     }
   1415     for (bidx = 0; bidx < mem_banks.count; bidx++) {
   1416         rv = soc_generic_hash(unit, mem, bufp, (uint32)1 << mem_banks.banks[bidx],
   1417                               0, &index, &result, &bucket_index, &num_ent);
   1418         if (SOC_FAILURE(rv)) {
   1419             return BCM_E_INTERNAL;
   1420         }
   1421         for (i = 0; (i < num_ent) && (*cf_count < cf_max); i++) {
   1422             rv = soc_mem_read(unit, mem, COPYNO_ALL, index + i, l3_entry);
   1423             if (SOC_FAILURE(rv)) {
   1424                 return BCM_E_MEMORY;
   1425             }
   1426             if (soc_mem_field32_get(unit, mem, &l3_entry, fld->valid) &&
   1427                 ((soc_mem_field32_get(unit, mem, &l3_entry, fld->key_type) == keyt[0]) ||
   1428                  (soc_mem_field32_get(unit, mem, &l3_entry, fld->key_type) == keyt[1]) ||
   1429                  (soc_mem_field32_get(unit, mem, &l3_entry, fld->key_type) == keyt[2]))) {
   1430                 switch(soc_mem_field32_get(unit, mem, &l3_entry, fld->key_type)) {
   1431                 case SOC_MEM_KEY_L3_ENTRY_1_IPV4UC_IPV4_UNICAST:
   1432                       l3cfg.l3c_flags = 0;
   1433                       break;
   1434                 case SOC_MEM_KEY_L3_ENTRY_2_IPV4UC_IPV4_UNICAST:
   1435                       l3cfg.l3c_flags = BCM_L3_DEREFERENCED_NEXTHOP;
   1436                       break;
   1437                 case SOC_MEM_KEY_L3_ENTRY_2_IPV4MC_IPV4_MULTICAST:
   1438                       l3cfg.l3c_flags = BCM_L3_IPMC;
   1439                       break;
   1440                 case SOC_MEM_KEY_L3_ENTRY_2_IPV6UC_IPV6_UNICAST:
   1441                       l3cfg.l3c_flags = BCM_L3_IP6;
   1442                       break;
   1443                 case SOC_MEM_KEY_L3_ENTRY_4_IPV6UC_IPV6_UNICAST:
   1444                       l3cfg.l3c_flags = BCM_L3_IP6 | BCM_L3_DEREFERENCED_NEXTHOP;
   1445                       break;
   1446                 case SOC_MEM_KEY_L3_ENTRY_4_IPV6MC_IPV6_MULTICAST:
   1447                       l3cfg.l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC;
   1448                       break;
   1449                 default:
   1450                       break;
   1451                 }
   1452 
   1453                 rv = _bcm_tr3_l3_get_by_idx(unit, NULL, index + i,
   1454                                                                 &l3cfg, &nh_idx);
   1455                 if (BCM_FAILURE(rv)) {
   1456                     continue;
   1457                 }
   1458 
   1459                 BCM_IF_ERROR_RETURN
   1460                     (_bcm_tr3_l3cfg_to_ipkey(unit, cf_array + (*cf_count), &l3cfg));
   1461                 if ((++(*cf_count)) >= cf_max) {
   1462                     break;
   1463                 }
   1464             }
   1465         }
   1466     } 
   1467     return BCM_E_NONE;
   1468 }
   1469 
   1470 /*
   1471  * Function:
   1472  *      _bcm_tr3_l3_get_host_ent_by_idx
   1473  * Purpose:
   1474  * Parameters:
   1475  *      unit     - (IN)SOC unit number.
   1476  *      dma_ptr  - (IN)Table pointer in dma. 
   1477  *      soc_mem_ - (IN)Table memory.
   1478  *      idx      - (IN)Index to read.
   1479  *      l3cfg    - (OUT)l3 entry search result.
   1480  *      nh_index - (OUT)Next hop index.
   1481  * Returns:
   1482  *      BCM_E_XXX
   1483  */
   1484 STATIC int
   1485 _bcm_tr3_l3_get_host_ent_by_idx(int unit, void *dma_ptr, soc_mem_t mem,
   1486                                 int idx, _bcm_l3_cfg_t *l3cfg, int *nh_idx)
   1487 {
   1488     uint32 ipv6;                       /* IPv6 entry indicator.   */
   1489     int key_type;
   1490     int clear_hit;                     /* Clear hit bit flag.     */
   1491     int esm = TRUE;
   1492     _bcm_l3_fields_t *fld;             /* L3 table common fields. */
   1493     uint32 *buf_entry;                 /* Key and entry buffer ptrs*/
   1494     l3_entry_1_entry_t l3v4_entry;     /* Lookup entry     */
   1495     l3_entry_2_entry_t l3v4v6_entry;   /* Lookup entry*/
   1496     l3_entry_4_entry_t l3v6_ext_entry; /* Lookup entry*/
   1497     ext_ipv4_ucast_entry_t          l3v4esm_entry;    
   1498     ext_ipv4_ucast_wide_entry_t     l3v4wide_entry;
   1499     ext_ipv6_128_ucast_entry_t      l3v6_entry; 
   1500     ext_ipv6_128_ucast_wide_entry_t l3v6wide_entry;
   1501 
   1502     /* Get entry type. */
   1503     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
   1504     /* Get clear hit flag. */
   1505     clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR;
   1506 
   1507     if ((BCM_XGS3_L3_MEM(unit, v4) == mem)   ||
   1508         (BCM_XGS3_L3_MEM(unit, v4_2) == mem) ||
   1509         (BCM_XGS3_L3_MEM(unit, v6_4) == mem)) {
   1510         esm = FALSE;
   1511         BCM_TR3_ISM_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
   1512         BCM_TR3_ISM_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry,
   1513                                             l3v4_entry,
   1514                                             l3v4v6_entry,
   1515                                             l3v6_ext_entry);
   1516     } else {
   1517         esm = TRUE;
   1518         BCM_TR3_ESM_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
   1519         BCM_TR3_ESM_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry,
   1520                                             l3v4esm_entry,
   1521                                             l3v4wide_entry,
   1522                                             l3v6_entry,
   1523                                             l3v6wide_entry);
   1524     }
   1525     
   1526     if (NULL == dma_ptr) { /* Read from hardware. */
   1527         /* Zero buffers. */
   1528         sal_memset(buf_entry, 0, BCM_L3_MEM_ENT_SIZE(unit, mem));
   1529 
   1530         /* Read entry from hw. */
   1531         BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, buf_entry)); 
   1532     } else { /* Read from dma. */
   1533         buf_entry = soc_mem_table_idx_to_pointer(unit, mem,
   1534                                    uint32 *, dma_ptr, idx);
   1535     }
   1536 
   1537     if (esm) {
   1538         if (((BCM_XGS3_L3_MEM(unit, v6_esm)) == mem) || 
   1539             ((BCM_XGS3_L3_MEM(unit, v6_esm_wide)) == mem)) {
   1540             l3cfg->l3c_flags = BCM_L3_IP6;
   1541             ipv6 = TRUE;
   1542         }
   1543         
   1544         if (ipv6) {
   1545             soc_mem_ip6_addr_get(unit, mem, buf_entry,
   1546                                  IP_ADDRf, l3cfg->l3c_ip6, 0);
   1547         }
   1548 
   1549     } else {
   1550         if(!soc_mem_field32_get(unit, mem, buf_entry, fld->valid)) {
   1551             return (BCM_E_NOT_FOUND);
   1552         }
   1553   
   1554         key_type = soc_mem_field32_get(unit, mem, buf_entry, fld->key_type);
   1555 
   1556         if (BCM_XGS3_L3_MEM(unit, v4) == mem) {
   1557             if (key_type != SOC_MEM_KEY_L3_ENTRY_1_IPV4UC_IPV4_UNICAST) {
   1558                 return (BCM_E_NOT_FOUND);
   1559             }
   1560             l3cfg->l3c_flags = 0;
   1561         } else if (BCM_XGS3_L3_MEM(unit, v4_2) == mem) {
   1562             if (key_type == SOC_MEM_KEY_L3_ENTRY_2_IPV4UC_IPV4_UNICAST) {
   1563                 l3cfg->l3c_flags = 0;
   1564             } else if (key_type ==
   1565                     SOC_MEM_KEY_L3_ENTRY_2_IPV4MC_IPV4_MULTICAST) {
   1566                 l3cfg->l3c_flags = BCM_L3_IPMC;
   1567             } else if (key_type ==
   1568                     SOC_MEM_KEY_L3_ENTRY_2_IPV6UC_IPV6_UNICAST) {
   1569                 l3cfg->l3c_flags = BCM_L3_IP6;
   1570             } else {
   1571                 return (BCM_E_NOT_FOUND);
   1572             }
   1573         } else if (BCM_XGS3_L3_MEM(unit, v6_4) == mem) {
   1574             if (key_type == SOC_MEM_KEY_L3_ENTRY_4_IPV6UC_IPV6_UNICAST) {
   1575                 l3cfg->l3c_flags = BCM_L3_IP6;
   1576             } else if (key_type == 
   1577                     SOC_MEM_KEY_L3_ENTRY_4_IPV6MC_IPV6_MULTICAST) {
   1578                 l3cfg->l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC;
   1579             } else {
   1580                 return (BCM_E_NOT_FOUND);
   1581             }
   1582         }
   1583 
   1584         /* Ignore protocol mismatch & multicast entries. */
   1585         if ((ipv6  != (l3cfg->l3c_flags & BCM_L3_IP6)) ||
   1586             (l3cfg->l3c_flags & BCM_L3_IPMC)) {
   1587             return (BCM_E_NONE);
   1588         }
   1589 
   1590         if (ipv6) {
   1591             /* Extract host info from the entry. */
   1592             soc_mem_ip6_addr_get(unit, mem, buf_entry,
   1593                                  IPV6UC__IP_ADDR_LWR_64f, l3cfg->l3c_ip6,
   1594                                  SOC_MEM_IP6_LOWER_ONLY);
   1595 
   1596             soc_mem_ip6_addr_get(unit, mem, buf_entry,
   1597                                  IPV6UC__IP_ADDR_UPR_64f, l3cfg->l3c_ip6,
   1598                                  SOC_MEM_IP6_UPPER_ONLY);
   1599         }
   1600     }
   1601 
   1602     /* Set index to l3cfg. */
   1603     l3cfg->l3c_hw_index = idx;
   1604 
   1605     if (!ipv6) {
   1606         l3cfg->l3c_ip_addr = 
   1607             soc_mem_field32_get(unit, mem, buf_entry, fld->ip4);
   1608     }
   1609 
   1610     /* Parse entry data. */
   1611     BCM_IF_ERROR_RETURN(
   1612         _bcm_tr3_l3_ent_parse(unit, mem, l3cfg, nh_idx, buf_entry));
   1613 
   1614     /* Clear the HIT bit */
   1615     if (clear_hit) {
   1616         BCM_IF_ERROR_RETURN(_bcm_tr3_l3_clear_hit(unit, mem, l3cfg,
   1617                                            (void *)buf_entry, idx));
   1618     }
   1619 
   1620     return (BCM_E_NONE);
   1621 }
   1622 
   1623 /*
   1624  * Function:
   1625  *      _bcm_tr3_l3_get_tbl_info
   1626  * Purpose:
   1627  *      Get an entry from Tr3 ISM/ESM L3 host table
   1628  *      and also the info where it was found.
   1629  * Parameters:
   1630  *      unit     - (IN) SOC unit number.
   1631  *      l3cfg    - (IN/OUT) L3 entry  lookup key & search result.
   1632  *      nh_index - (IN/OUT) Next hop index.
   1633  *      esm      - (OUT) If TRUE, entry found in ESM. 
   1634  *      embd     - (OUT) If TRUE, entry is embedded NH entry.
   1635  * Returns:
   1636  *      BCM_E_XXX
   1637  */
   1638 STATIC int
   1639 _bcm_tr3_l3_get_tbl_info(int unit, _bcm_l3_cfg_t *l3cfg,
   1640                           int *nh_idx, int *esm, int *embd)
   1641 {
   1642     int rv;
   1643     *esm  = _BCM_TR3_HOST_ENTRY_NOT_FOUND;
   1644     *embd = _BCM_TR3_HOST_ENTRY_NOT_FOUND;
   1645 
   1646     /* Search ISM tables first */
   1647     rv = _bcm_tr3_l3_ism_get(unit, l3cfg, nh_idx, embd);
   1648     if (BCM_E_NOT_FOUND == rv && BCM_TR3_ESM_HOST_TBL_PRESENT(unit)) {       
   1649         /* Not found in ISM, search ESM */
   1650         rv = _bcm_tr3_l3_esm_get(unit, l3cfg, nh_idx, embd);
   1651         if (BCM_SUCCESS(rv)) {
   1652             *esm = TRUE;
   1653         }
   1654         return rv;
   1655     } else if (BCM_FAILURE(rv)) { 
   1656         /* ISM search failed */
   1657         return rv;
   1658     } else {                      
   1659         /* Found match in ISM */
   1660         *esm = FALSE;
   1661         return BCM_E_NONE;
   1662     }
   1663 }
   1664 
   1665 /*
   1666  * Function:
   1667  *      _bcm_tr3_l3_ipmc_ent_parse
   1668  * Purpose:
   1669  *      Service routine used to parse hw l3 ipmc entry to api format.
   1670  * Parameters:
   1671  *      unit      - (IN)SOC unit number. 
   1672  *      l3cfg     - (IN/OUT)l3 entry parsing destination buf.
   1673  *      l3x_entry - (IN/OUT)hw buffer.
   1674  * Returns:
   1675  *      void
   1676  */
   1677 STATIC void
   1678 _bcm_tr3_l3_ipmc_ent_parse(int unit, _bcm_l3_cfg_t *l3cfg,
   1679                           l3_entry_4_entry_t *l3x_entry)
   1680 {
   1681     soc_mem_t mem;                     /* IPMC table memory.    */
   1682     uint32 *buf_p;                     /* HW buffer address.    */
   1683     int ipv6;                          /* IPv6 entry indicator. */
   1684     int idx;                           /* Iteration index.      */
   1685     soc_field_t hitf[] = {HIT_0f, HIT_1f, HIT_2f};
   1686     soc_field_t rpe, dst_discard, vrf_id, l3mc_idx, class_id, pri;
   1687 
   1688     buf_p = (uint32 *)l3x_entry;
   1689 
   1690     /* Get entry type. */
   1691     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
   1692 
   1693     /* Get table memory and table fields */
   1694     if (ipv6) {
   1695         mem         = L3_ENTRY_4m;
   1696         pri         = IPV6MC__PRIf;
   1697         rpe         = IPV6MC__RPEf;
   1698         vrf_id      = IPV6MC__VRF_IDf;
   1699         l3mc_idx    = IPV6MC__L3MC_INDEXf;
   1700         class_id    = IPV6MC__CLASS_IDf;
   1701         dst_discard = IPV6MC__DST_DISCARDf;
   1702     } else {
   1703         mem         = L3_ENTRY_2m;
   1704         pri         = IPV4MC__PRIf;
   1705         rpe         = IPV4MC__RPEf;
   1706         vrf_id      = IPV4MC__VRF_IDf;
   1707         l3mc_idx    = IPV4MC__L3MC_INDEXf;
   1708         class_id    = IPV4MC__CLASS_IDf;
   1709         dst_discard = IPV4MC__DST_DISCARDf;
   1710     }
   1711 
   1712     /* Mark entry as multicast & clear rest of the flags. */
   1713     l3cfg->l3c_flags = BCM_L3_IPMC;
   1714     if (ipv6) {
   1715        l3cfg->l3c_flags |= BCM_L3_IP6;
   1716     }
   1717 
   1718     /* Read hit value. */
   1719     if(soc_mem_field32_get(unit, mem, buf_p, HIT_0f)) {
   1720         l3cfg->l3c_flags |= BCM_L3_HIT;
   1721     } else if (ipv6) {
   1722         /* Get hit bit. */
   1723         for (idx = 0; idx < 3; idx++) {
   1724             if(soc_mem_field32_get(unit, mem, buf_p, hitf[idx])) { 
   1725                 l3cfg->l3c_flags |= BCM_L3_HIT;
   1726                 break;
   1727             }
   1728         }
   1729     }
   1730 
   1731     /* Set ipv6 group address to multicast. */
   1732     if (ipv6) {
   1733         l3cfg->l3c_ip6[0] = 0xff;   /* Set entry ip to mcast address. */
   1734     }
   1735 
   1736     /* Read priority override */
   1737     if(soc_mem_field32_get(unit, mem, buf_p, rpe)) { 
   1738         l3cfg->l3c_flags |= BCM_L3_RPE;
   1739     }
   1740 
   1741     /* Read destination discard bit. */
   1742     if(soc_mem_field32_get(unit, mem, buf_p, dst_discard)) { 
   1743         l3cfg->l3c_flags |= BCM_L3_DST_DISCARD;
   1744     }
   1745 
   1746     /* Read Virtual Router Id. */
   1747     l3cfg->l3c_vrf = soc_mem_field32_get(unit, mem, buf_p, vrf_id);
   1748 
   1749     /* Pointer to ipmc replication table. */
   1750     l3cfg->l3c_ipmc_ptr = soc_mem_field32_get(unit, mem, buf_p, l3mc_idx);
   1751 
   1752     /* Classification lookup class id. */
   1753     l3cfg->l3c_lookup_class = soc_mem_field32_get(unit, mem, buf_p, class_id);
   1754 
   1755     /* Read priority value. */
   1756     l3cfg->l3c_prio = soc_mem_field32_get(unit, mem, buf_p, pri);
   1757     return;
   1758 }
   1759 
   1760 /*
   1761  * Function:
   1762  *      _bcm_tr3_l3_defip_mem_get
   1763  * Purpose:
   1764  *      Resolve route table memory for a given route entry.
   1765  * Parameters:
   1766  *      unit       - (IN)SOC unit number.
   1767  *      flags      - (IN)IPv6/IPv4 route.
   1768  *      plen       - (IN)Prefix length.
   1769  *      mem        - (OUT)Route table memory.
   1770  * Returns:
   1771  *      BCM_E_XXX
   1772  */
   1773 STATIC int
   1774 _bcm_tr3_l3_defip_mem_get(int unit, uint32 flags, int plen, soc_mem_t *mem)
   1775 {
   1776     /* default value */
   1777     *mem = L3_DEFIPm;
   1778 
   1779     if (flags & BCM_L3_IP6) {
   1780         if (plen > 64) {
   1781             *mem = (BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV6_128_DEFIPm)) ?\
   1782                     EXT_IPV6_128_DEFIPm : L3_DEFIP_PAIR_128m;
   1783         } else {
   1784             *mem = (BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV6_64_DEFIPm)) ?\
   1785                     EXT_IPV6_64_DEFIPm :
   1786                    ((BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV6_128_DEFIPm)) ?\
   1787                     EXT_IPV6_128_DEFIPm : L3_DEFIPm);
   1788         }
   1789     } else {
   1790         *mem = (BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV4_DEFIPm)) ?\
   1791                 EXT_IPV4_DEFIPm : L3_DEFIPm ;
   1792     }
   1793 
   1794     return BCM_E_NONE;
   1795 }
   1796 
   1797 /*
   1798  * Function:
   1799  *      _bcm_tr3_defip_pair128_init
   1800  * Purpose:
   1801  *      Initialize sw image for L3_DEFIP_PAIR_128 internal tcam.
   1802  * Parameters:
   1803  *      unit        - (IN)SOC unit number.
   1804  * Returns:
   1805  *      BCM_E_XXX
   1806  */
   1807 STATIC int
   1808 _bcm_tr3_defip_pair128_init(int unit)
   1809 {
   1810     int rv;    
   1811     int mem_sz;   
   1812     int defip_config;
   1813     int ipv6_128_depth;
   1814     int ranger_device;    /* Ranger specific config */
   1815 
   1816     /* De-allocate any existing structures. */
   1817     if (BCM_DEFIP_PAIR128(unit) != NULL) {
   1818         rv = _bcm_defip_pair128_deinit(unit);
   1819         BCM_IF_ERROR_RETURN(rv);
   1820     }
   1821 
   1822     /* Allocate cam control structure. */
   1823     mem_sz = sizeof(_bcm_defip_pair128_table_t);
   1824     BCM_DEFIP_PAIR128(unit) = sal_alloc(mem_sz, "tr3_l3_defip_pair128");
   1825     if (BCM_DEFIP_PAIR128(unit) == NULL) {
   1826         return (BCM_E_MEMORY);
   1827     }
   1828 
   1829     /* Reset cam control structure. */
   1830     sal_memset(BCM_DEFIP_PAIR128(unit), 0, mem_sz);
   1831 
   1832     ranger_device = FALSE;
   1833     if (soc_feature(unit, soc_feature_l3_256_defip_table)) {
   1834         ranger_device = TRUE;
   1835     }
   1836 
   1837     defip_config = soc_property_get(unit, spn_IPV6_LPM_128B_ENABLE,
   1838                                         ((ranger_device) ? 0 : 1));
   1839     ipv6_128_depth =  SOC_L3_DEFIP_MAX_128B_ENTRIES(unit);
   1840 
   1841     if (ranger_device ) { 
   1842         if (defip_config) {
   1843             ipv6_128_depth = _BCM_HX4_RANGER_DEFIP_TCAM_DEPTH;
   1844         } else { /* tcams are not paired - no ipv6/65-ipv6/128 routes */
   1845             ipv6_128_depth      = 0;
   1846         }
   1847     }
   1848 
   1849     BCM_DEFIP_PAIR128_TOTAL(unit) = ipv6_128_depth;
   1850     BCM_DEFIP_PAIR128_URPF_OFFSET(unit) = 0;
   1851     BCM_DEFIP_PAIR128_IDX_MAX(unit) = ipv6_128_depth - 1;
   1852     BCM_XGS3_L3_IP6_MAX_128B_ENTRIES(unit) = ipv6_128_depth;
   1853     if (ipv6_128_depth) {
   1854         mem_sz = ipv6_128_depth * sizeof(_bcm_defip_pair128_entry_t);
   1855         BCM_DEFIP_PAIR128_ARR(unit) = 
   1856                                 sal_alloc(mem_sz, "tr3_l3_defip_pair128_entry_array");
   1857         if (BCM_DEFIP_PAIR128_ARR(unit) == NULL) {
   1858             BCM_IF_ERROR_RETURN(_bcm_defip_pair128_deinit(unit));
   1859             return (BCM_E_MEMORY);
   1860         }
   1861         sal_memset(BCM_DEFIP_PAIR128_ARR(unit), 0, mem_sz);
   1862     }
   1863 
   1864     rv = _bcm_defip_pair128_field_cache_init(unit);
   1865     if (BCM_FAILURE(rv)) {
   1866         BCM_IF_ERROR_RETURN(_bcm_defip_pair128_deinit(unit));
   1867         return rv;
   1868     }
   1869     
   1870     return (BCM_E_NONE);
   1871 }
   1872 
   1873 /*
   1874  * Function:
   1875  *      _bcm_tr3_l3_host_stat_get_table_info
   1876  * Description:
   1877  *      Provides relevant flex table information(table-name,index with
   1878  *      direction)  for given L3 Host entry
   1879  *
   1880  * Parameters:
   1881  *      unit             - (IN) unit number
   1882  *      port             - (IN) GPORT ID
   1883  *      num_of_tables    - (OUT) Number of flex counter tables
   1884  *      table_info       - (OUT) Flex counter tables information
   1885  *
   1886  * Return Value:
   1887  *      BCM_E_XXX
   1888  * Notes:
   1889  */
   1890 STATIC bcm_error_t
   1891 _bcm_tr3_l3_host_stat_get_table_info(
   1892                    int                        unit,
   1893                    bcm_l3_host_t              *info,
   1894                    uint32                     *num_of_tables,
   1895                    bcm_stat_flex_table_info_t *table_info)
   1896 {
   1897     int rv, embd;
   1898     soc_mem_t mem;          
   1899     _bcm_l3_cfg_t l3cfg;     
   1900 
   1901     if (NULL == info) {
   1902         return (BCM_E_PARAM);
   1903     }
   1904 
   1905     if (!(soc_feature(unit, soc_feature_l3_extended_host_entry))) {
   1906         return BCM_E_UNAVAIL;
   1907     }
   1908 
   1909     mem = INVALIDm;
   1910     /* Vrf is in device supported range check. */
   1911     if ((info->l3a_vrf > SOC_VRF_MAX(unit)) || 
   1912         (info->l3a_vrf < BCM_L3_VRF_DEFAULT)) {
   1913         return (BCM_E_PARAM);
   1914     }
   1915   
   1916     sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   1917     l3cfg.l3c_flags = info->l3a_flags;
   1918     l3cfg.l3c_vrf = info->l3a_vrf;
   1919 
   1920     if (info->l3a_flags & BCM_L3_IP6) {
   1921         sal_memcpy(l3cfg.l3c_ip6, info->l3a_ip6_addr, BCM_IP6_ADDRLEN);
   1922     } else {
   1923         l3cfg.l3c_ip_addr = info->l3a_ip_addr;
   1924     }
   1925    
   1926     rv = _bcm_tr3_l3_ism_get(unit, &l3cfg, NULL, &embd);
   1927     if (BCM_SUCCESS(rv)) { /* Entry found in ISM */
   1928         mem = (l3cfg.l3c_flags & BCM_L3_IP6) ? L3_ENTRY_4m :
   1929                                                L3_ENTRY_2m;       
   1930     }
   1931 
   1932     if (BCM_E_NOT_FOUND == rv && BCM_TR3_ESM_HOST_TBL_PRESENT(unit)) {   
   1933         /* Not found in ISM, search ESM */
   1934         rv = _bcm_tr3_l3_esm_get(unit, &l3cfg, NULL, &embd);
   1935         if (BCM_SUCCESS(rv)) { /* Entry found in ESM */
   1936             mem = (l3cfg.l3c_flags & BCM_L3_IP6) ?
   1937                          EXT_IPV6_128_UCAST_WIDEm :
   1938                          EXT_IPV4_UCAST_WIDEm;       
   1939         }
   1940     } 
   1941 
   1942     if (BCM_SUCCESS(rv)) {
   1943         table_info[*num_of_tables].table = mem;
   1944         table_info[*num_of_tables].index = l3cfg.l3c_hw_index;
   1945         table_info[*num_of_tables].direction = bcmStatFlexDirectionIngress;
   1946         (*num_of_tables)++;
   1947     }
   1948     
   1949     return rv;
   1950 }
   1951 
   1952 /*----- END STATIC FUNCS ----- */
   1953 
   1954 /*
   1955  * Function:
   1956  *      _bcm_tr3_l3_add
   1957  * Purpose:
   1958  *      Add and entry to Tr3 ISM/ESM L3 host table.
   1959  *      The decision to add to ISM/ESM is based on 
   1960  *      switch control(s) and ESM/ISM table full conditions.
   1961  *      conditions.
   1962  * Parameters:
   1963  *      unit   - (IN) SOC unit number.
   1964  *      l3cfg  - (IN) L3 entry info.
   1965  *      nh_idx - (IN) Next hop index.
   1966  * Returns:
   1967  *      BCM_E_XXX
   1968  */
   1969 int
   1970 _bcm_tr3_l3_add(int unit, _bcm_l3_cfg_t *l3cfg, int nh_idx)
   1971 {
   1972     int rv;
   1973 
   1974     /* Access ISM before ESM */
   1975     rv = _bcm_tr3_l3_ism_add(unit, l3cfg, nh_idx);
   1976     if (BCM_E_FULL == rv && BCM_TR3_ESM_HOST_TBL_PRESENT(unit)) {       
   1977         if (BCM_L3_RPE_SET(l3cfg->l3c_flags)) {
   1978             if (l3cfg->l3c_lookup_class > SOC_ADDR_CLASS_MAX(unit)) {
   1979                 return (BCM_E_PARAM);
   1980             }
   1981         } else {
   1982             l3cfg->l3c_prio = (l3cfg->l3c_lookup_class & 0x3C0) >> 6;
   1983             l3cfg->l3c_lookup_class = l3cfg->l3c_lookup_class & 0x3F;
   1984         }
   1985 
   1986         /* ISM host table full, try to add to ESM */
   1987         return (_bcm_tr3_l3_esm_add(unit, l3cfg, nh_idx));
   1988     } else if (BCM_FAILURE(rv)) { 
   1989         /* ISM host add failed */
   1990         return rv;
   1991     } else {                      
   1992         /* ISM host add successful */
   1993         return BCM_E_NONE;
   1994     }
   1995 }
   1996 
   1997 /*
   1998  * Function:
   1999  *      _bcm_tr3_l3_get
   2000  * Purpose:
   2001  *      Get an entry from Tr3 ISM/ESM L3 host table.
   2002  * Parameters:
   2003  *      unit     - (IN) SOC unit number.
   2004  *      l3cfg    - (IN/OUT) L3 entry  lookup key & search result.
   2005  *      nh_index - (IN/OUT) Next hop index.
   2006  * Returns:
   2007  *      BCM_E_XXX
   2008  */
   2009 int
   2010 _bcm_tr3_l3_get(int unit, _bcm_l3_cfg_t *l3cfg, int *nh_idx)
   2011 {
   2012     int rv;
   2013     int embd = _BCM_TR3_HOST_ENTRY_NOT_FOUND;
   2014 
   2015     /* Search ISM tables first */
   2016     rv = _bcm_tr3_l3_ism_get(unit, l3cfg, nh_idx, &embd);
   2017     if (BCM_E_NOT_FOUND == rv && BCM_TR3_ESM_HOST_TBL_PRESENT(unit)) {   
   2018         /* Not found in ISM, search ESM */
   2019         BCM_IF_ERROR_RETURN((_bcm_tr3_l3_esm_get(unit, l3cfg, nh_idx, &embd)));
   2020         if (!BCM_L3_RPE_SET(l3cfg->l3c_flags)) {
   2021             l3cfg->l3c_lookup_class = (((l3cfg->l3c_prio & 0xF) << 6) |
   2022                                        (l3cfg->l3c_lookup_class & 0x3F));
   2023         }
   2024 
   2025         return BCM_E_NONE;
   2026     } else if (BCM_FAILURE(rv)) { 
   2027         /* ISM search failed */
   2028         return rv;
   2029     } else {                      
   2030         /* Found match in ISM */
   2031         return BCM_E_NONE;
   2032     }
   2033 }
   2034 
   2035 /*
   2036  * Function:
   2037  *      _bcm_tr3_l3_del
   2038  * Purpose:
   2039  *      Del an entry from Tr3 ISM/ESM L3 host table.
   2040  * Parameters:
   2041  *      unit     - (IN) SOC unit number.
   2042  *      l3cfg    - (IN/OUT) L3 entry  lookup key & search result.
   2043  *      nh_index - (IN/OUT) Next hop index.
   2044  * Returns:
   2045  *      BCM_E_XXX
   2046  */
   2047 int
   2048 _bcm_tr3_l3_del(int unit, _bcm_l3_cfg_t *l3cfg)
   2049 {
   2050     int rv;
   2051 
   2052     /* Attempt to delete entry from ISM tables first */
   2053     rv = _bcm_tr3_l3_ism_del(unit, l3cfg);
   2054     if ((BCM_E_NOT_FOUND == rv) && BCM_TR3_ESM_HOST_TBL_PRESENT(unit)) { 
   2055         rv = _bcm_tr3_l3_esm_del(unit, l3cfg);
   2056         if (BCM_E_NOT_FOUND == rv) {
   2057             rv = BCM_E_NONE; /* Ignore if entry to del is not found */
   2058         }
   2059     }
   2060 
   2061     return rv;
   2062 }
   2063 
   2064 /*
   2065  * Function:
   2066  *      _bcm_tr3_l3_traverse
   2067  * Purpose:
   2068  *      Walk over range of entries in l3 host table.
   2069  * Parameters:
   2070  *      unit - SOC unit number.
   2071  *      flags - L3 entry flags to match during traverse.  
   2072  *      start - First index to read. 
   2073  *      end - Last index to read.
   2074  *      cb  - Caller notification callback.
   2075  *      user_data - User cookie, which should be returned in cb. 
   2076  * Returns:
   2077  *      BCM_E_XXX
   2078  */
   2079 int
   2080 _bcm_tr3_l3_traverse(int unit, int flags, uint32 start, uint32 end,
   2081                       bcm_l3_host_traverse_cb cb, void *user_data)
   2082 {
   2083     int rv = BCM_E_NONE;
   2084     int ipv6;                   /* Protocol IPv6/IPv4          */
   2085     int nh_idx;                 /* Next hop index.                 */
   2086     int total = 0;              /* Total number of entries walked. */
   2087     int table_size;             /* Number of entries in the table. */
   2088     int table_ent_size;         /* Table entry size. */
   2089     bcm_l3_host_t info;         /* Callback info buffer.           */
   2090     _bcm_l3_cfg_t l3cfg;        /* HW entry info.                  */
   2091     uint8 *l3_tbl_buf = NULL;    /* Table dma pointer.              */
   2092     int tbl, idx, idx_min, idx_max;  /* Min and Max iteration index */
   2093     int chunk_size, num_chunks, chunk_index;
   2094     int num_tables = _BCM_TR3_NUM_ESM_HOST_TABLES/2;
   2095     soc_mem_t mem[_BCM_TR3_NUM_ESM_HOST_TABLES] =
   2096               {INVALIDm, INVALIDm, INVALIDm, INVALIDm};
   2097     int host_table_entry = 0;
   2098 
   2099     /* If no callback provided, we are done.  */
   2100     if (NULL == cb) {
   2101         return (BCM_E_NONE);
   2102     }
   2103 
   2104     ipv6 = (flags & BCM_L3_IP6) ? TRUE : FALSE;
   2105     /* If table is empty -> there is nothing to read. */
   2106     if (ipv6 && (!BCM_XGS3_L3_IP6_CNT(unit))) {
   2107         return (BCM_E_NONE);
   2108     }
   2109     if (!ipv6 && (!BCM_XGS3_L3_IP4_CNT(unit))) {
   2110         return (BCM_E_NONE);
   2111     }
   2112 
   2113     if (ipv6) {
   2114         mem[0] = BCM_XGS3_L3_MEM(unit, v6); 
   2115         if (soc_feature(unit, soc_feature_l3_extended_host_entry)) {
   2116             mem[1] = BCM_XGS3_L3_MEM(unit, v6_4); 
   2117             num_tables++;
   2118         }
   2119     } else {
   2120         mem[0] = BCM_XGS3_L3_MEM(unit, v4); 
   2121         if (soc_feature(unit, soc_feature_l3_extended_host_entry)) {
   2122             mem[1] = BCM_XGS3_L3_MEM(unit, v4_2); 
   2123             num_tables++;
   2124         }
   2125     }
   2126 
   2127     for(tbl = 0; tbl < num_tables; tbl++) {
   2128   
   2129         if (INVALIDm == mem[tbl]) {
   2130             continue;
   2131         }
   2132         if (soc_mem_index_count(unit, mem[tbl]) == 0) {
   2133             continue;
   2134         }
   2135 
   2136         chunk_size = 1024;
   2137         table_size = soc_mem_index_count(unit, mem[tbl]);
   2138         table_ent_size = BCM_L3_MEM_ENT_SIZE(unit, mem[tbl]);
   2139         num_chunks = soc_mem_index_count(unit, mem[tbl]) / chunk_size;
   2140         if (soc_mem_index_count(unit, mem[tbl]) % chunk_size) {
   2141             num_chunks++;
   2142         }
   2143 
   2144         l3_tbl_buf = soc_cm_salloc(unit, table_ent_size * chunk_size,
   2145                                            "l3_tbl_chunk buffer");
   2146         if (NULL == l3_tbl_buf) {
   2147             rv = BCM_E_MEMORY;
   2148             goto cleanup;
   2149         }
   2150         
   2151         for (chunk_index = 0; chunk_index < num_chunks; chunk_index++) {
   2152             idx_min = chunk_index * chunk_size;
   2153             idx_max = idx_min + chunk_size - 1;
   2154             if (idx_max > soc_mem_index_max(unit, mem[tbl])) {
   2155                 idx_max = soc_mem_index_max(unit, mem[tbl]);
   2156             }
   2157 
   2158             /* Reset allocated buffer. */
   2159             sal_memset(l3_tbl_buf, 0, (table_ent_size * chunk_size));
   2160 
   2161             rv = soc_mem_read_range(unit, mem[tbl], MEM_BLOCK_ANY,
   2162                     idx_min, idx_max, l3_tbl_buf);
   2163             if (SOC_FAILURE(rv)) {
   2164                 goto cleanup;
   2165             }
   2166 
   2167             /* Input index`s sanity. */
   2168             if (start > (uint32)table_size || start > end) {
   2169                 if(l3_tbl_buf) {
   2170                     soc_cm_sfree(unit, l3_tbl_buf);
   2171                     l3_tbl_buf = NULL;
   2172                 }
   2173                 return (BCM_E_NOT_FOUND);
   2174             }
   2175 
   2176             /* Iterate over all the entries - show matching ones. */
   2177             for (idx = idx_min; idx <= idx_max; idx++) {
   2178                 /* Reset buffer before read. */
   2179                 sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   2180                 l3cfg.l3c_flags = flags;
   2181 
   2182                 /* Get entry from  hw. */
   2183                 rv = _bcm_tr3_l3_get_host_ent_by_idx(unit, l3_tbl_buf, mem[tbl],
   2184                                            (idx % chunk_size), &l3cfg, &nh_idx);
   2185 
   2186                 /* Check for read errors & invalid entries. */
   2187                 if (rv < 0) {
   2188                     if (rv != BCM_E_NOT_FOUND) {
   2189                         break;
   2190                     }
   2191                     continue;
   2192                 }
   2193     
   2194                 /* Check read entry flags & update index accordingly. */
   2195                 if (BCM_L3_CMP_EQUAL !=
   2196                     _bcm_xgs3_trvrs_flags_cmp(unit, flags, l3cfg.l3c_flags, &idx)) {
   2197                     continue;
   2198                 }
   2199     
   2200                 /* Valid entry found -> increment total table_sizeer */
   2201                 total++;
   2202                 if ((uint32)total < start) {
   2203                     continue;
   2204                 }
   2205     
   2206                 /* Don't read beyond last required index. */
   2207                 if ((uint32)total > end) {
   2208                     break;
   2209                 }
   2210     
   2211                 /* Get next hop info. */
   2212                 rv = _bcm_xgs3_l3_get_nh_info(unit, &l3cfg, nh_idx);
   2213                 if (rv < 0) {
   2214                     continue;
   2215                 }
   2216     
   2217                 /* Fill host info. */
   2218                 _bcm_xgs3_host_ent_init(unit, &l3cfg, TRUE, &info);
   2219                 rv = (*cb) (unit, total, &info, user_data);
   2220 #ifdef BCM_CB_ABORT_ON_ERR
   2221                 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   2222                     break;
   2223                 }
   2224 #endif
   2225             }
   2226         }
   2227         if(l3_tbl_buf) {
   2228             soc_cm_sfree(unit, l3_tbl_buf);
   2229             l3_tbl_buf = NULL;
   2230         }
   2231     }
   2232 
   2233     if (BCM_TR3_ESM_HOST_TBL_PRESENT(unit)) {
   2234         idx = 0;
   2235         num_tables =  1;
   2236 
   2237         if (ipv6) {
   2238             mem[0] = BCM_XGS3_L3_MEM(unit, v6_esm); 
   2239             if (soc_feature(unit, soc_feature_l3_extended_host_entry)) {
   2240                 mem[1] = BCM_XGS3_L3_MEM(unit, v6_esm_wide); 
   2241                 num_tables++;
   2242             }
   2243         } else {
   2244             mem[0] = BCM_XGS3_L3_MEM(unit, v4_esm); 
   2245             if (soc_feature(unit, soc_feature_l3_extended_host_entry)) {
   2246                 mem[1] = BCM_XGS3_L3_MEM(unit, v4_esm_wide); 
   2247                 num_tables++;
   2248             }
   2249         }
   2250 
   2251         for(tbl = 0; tbl < num_tables; tbl++) {
   2252       
   2253             if (INVALIDm == mem[tbl]) {
   2254                 continue;
   2255             }
   2256             if (soc_mem_index_count(unit, mem[tbl]) == 0) {
   2257                 continue;
   2258             }
   2259 
   2260             table_size = soc_mem_index_count(unit, mem[tbl]);
   2261             table_ent_size = BCM_L3_MEM_ENT_SIZE(unit, mem[tbl]);
   2262             chunk_size = 1024;
   2263             num_chunks = soc_mem_index_count(unit, mem[tbl]) / chunk_size;
   2264             if (soc_mem_index_count(unit, mem[tbl]) % chunk_size) {
   2265                 num_chunks++;
   2266             }
   2267 
   2268             l3_tbl_buf = soc_cm_salloc(unit, table_ent_size * chunk_size,
   2269                                                "l3esm_tbl_chunk buffer");
   2270             if (NULL == l3_tbl_buf) {
   2271                 rv = BCM_E_MEMORY;
   2272                 goto cleanup;
   2273             }
   2274             host_table_entry = _TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl+(2 * ipv6));
   2275         
   2276             for (chunk_index = num_chunks - 1; chunk_index >= 0; chunk_index--) {
   2277                 idx_min = chunk_index * chunk_size;
   2278                 idx_max = idx_min + chunk_size - 1;
   2279                 if (idx_max > soc_mem_index_max(unit, mem[tbl])) {
   2280                     idx_max = soc_mem_index_max(unit, mem[tbl]);
   2281                 }
   2282 
   2283                 if (idx_min > host_table_entry) {
   2284                     continue;
   2285                 }
   2286 
   2287                 /* Reset allocated buffer. */
   2288                 sal_memset(l3_tbl_buf, 0, (table_ent_size * chunk_size));
   2289 
   2290                 rv = soc_mem_read_range(unit, mem[tbl], MEM_BLOCK_ANY,
   2291                         idx_min, idx_max, l3_tbl_buf);
   2292                 if (SOC_FAILURE(rv)) {
   2293                     goto cleanup;
   2294                 }
   2295 
   2296                 /* Input index`s sanity. */
   2297                 if (start > (uint32)table_size || start > end) {
   2298                     if(l3_tbl_buf) {
   2299                         soc_cm_sfree(unit, l3_tbl_buf);
   2300                         l3_tbl_buf = NULL;
   2301                     }
   2302                     return (BCM_E_NOT_FOUND);
   2303                 }
   2304 
   2305                 /* Iterate over all the entries - show matching ones. */
   2306                 for (idx = idx_min; idx <= idx_max; idx++) {
   2307                     if (idx < host_table_entry) {
   2308                         /* Reset buffer before read. */
   2309                         sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   2310                         l3cfg.l3c_flags = flags;
   2311         
   2312                         /* Get entry from  hw. */
   2313                         rv = _bcm_tr3_l3_get_host_ent_by_idx(unit, l3_tbl_buf,
   2314                                  mem[tbl], (idx % chunk_size), &l3cfg, &nh_idx);
   2315     
   2316                         /* Check for read errors & invalid entries. */
   2317                         if (rv < 0) {
   2318                             if (rv != BCM_E_NOT_FOUND) {
   2319                                 break;
   2320                             }
   2321                             continue;
   2322                         }
   2323         
   2324                         /* Check read entry flags & update index accordingly. */
   2325                         if (BCM_L3_CMP_EQUAL !=
   2326                             _bcm_xgs3_trvrs_flags_cmp(unit, flags,
   2327                                           l3cfg.l3c_flags, &idx)) {
   2328                             continue;
   2329                         }
   2330         
   2331                         /* Valid entry found -> increment total table_sizeer */
   2332                         total++;
   2333                         if ((uint32)total < start) {
   2334                             continue;
   2335                         }
   2336         
   2337                         /* Don't read beyond last required index. */
   2338                         if ((uint32)total > end) {
   2339                             break;
   2340                         }
   2341         
   2342                         /* Get next hop info. */
   2343                         rv = _bcm_xgs3_l3_get_nh_info(unit, &l3cfg, nh_idx);
   2344                         if (rv < 0) {
   2345                             break;
   2346                         }
   2347     
   2348                         /* Fill host info. */
   2349                         _bcm_xgs3_host_ent_init(unit, &l3cfg, TRUE, &info);
   2350                         rv = (*cb) (unit, total, &info, user_data);
   2351 #ifdef BCM_CB_ABORT_ON_ERR
   2352                         if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   2353                            break;
   2354                         }
   2355 #endif
   2356                     }
   2357                 }
   2358             }
   2359             if(l3_tbl_buf) {
   2360                 soc_cm_sfree(unit, l3_tbl_buf);
   2361                 l3_tbl_buf = NULL;
   2362             }
   2363         }
   2364     }
   2365 
   2366     /* Reset last read status. */
   2367     if (BCM_E_NOT_FOUND == rv) {
   2368         rv = BCM_E_NONE;
   2369     }
   2370 
   2371 cleanup:
   2372     if (l3_tbl_buf) {
   2373         soc_cm_sfree(unit, l3_tbl_buf);
   2374     }
   2375 
   2376     return (rv);
   2377 
   2378 }
   2379 
   2380 /*
   2381  * Function:
   2382  *      bcm_tr3_l3_replace
   2383  * Purpose:
   2384  *      Replace an entry in TR3 L3 host table.
   2385  * Parameters:
   2386  *      unit -  (IN)SOC unit number.
   2387  *      l3cfg - (IN)L3 entry information.
   2388  * Returns:
   2389  *      BCM_E_XXX
   2390  */
   2391 int
   2392 bcm_tr3_l3_replace(int unit, _bcm_l3_cfg_t *l3cfg)
   2393 {
   2394     
   2395     _bcm_l3_cfg_t entry;        /* Original l3 entry.             */
   2396     int nh_idx_old;             /* Original entry next hop index. */
   2397     int nh_idx_new;             /* New allocated next hop index   */
   2398     int rv = BCM_E_UNAVAIL;     /* Operation return status.       */
   2399     int esm_old, embd_old, embd_new;
   2400 
   2401     /*  Make sure module was initialized. */
   2402     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   2403         return (BCM_E_INIT);
   2404     }
   2405 
   2406     /* Input parameters check. */
   2407     if (NULL == l3cfg) {
   2408         return (BCM_E_PARAM); 
   2409     }
   2410 
   2411     /* Set lookup key. */
   2412     entry = *l3cfg;
   2413 
   2414     esm_old  = _BCM_TR3_HOST_ENTRY_NOT_FOUND;
   2415     embd_old = _BCM_TR3_HOST_ENTRY_NOT_FOUND;
   2416 
   2417     if (BCM_XGS3_L3_MCAST_ENTRY(l3cfg)) {
   2418         /* Check if identical entry exits. */
   2419         if (BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_get)) {
   2420             BCM_XGS3_L3_MODULE_LOCK(unit);
   2421             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_get) (unit, &entry);
   2422             BCM_XGS3_L3_MODULE_UNLOCK(unit);
   2423         }
   2424         if (rv < 0) {
   2425             return rv;
   2426         }
   2427 
   2428         /* Write mcast entry to hw. */
   2429         l3cfg->l3c_hw_index = entry.l3c_hw_index;       /*Replacement index & flag. */
   2430         if (BCM_XGS3_L3_HWCALL_CHECK(unit, ipmc_add)) {
   2431             BCM_XGS3_L3_MODULE_LOCK(unit);
   2432             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, ipmc_add) (unit, l3cfg);
   2433             BCM_XGS3_L3_MODULE_UNLOCK(unit);
   2434         } else {
   2435             return (BCM_E_UNAVAIL);
   2436         }
   2437     } else {
   2438         if (!(BCM_XGS3_L3_EGRESS_MODE_ISSET(unit))) {
   2439             /* Trunk id validation. */
   2440             BCM_XGS3_L3_IF_INVALID_TGID_RETURN(unit, l3cfg->l3c_flags,
   2441                                                l3cfg->l3c_port_tgid);
   2442         }
   2443 
   2444         /* Check if identical entry exits. */
   2445         rv = _bcm_tr3_l3_get_tbl_info(unit, &entry, &nh_idx_old, &esm_old, &embd_old);
   2446 
   2447         if ((BCM_E_NOT_FOUND == rv) || (BCM_E_DISABLED == rv)) {
   2448             return  bcm_xgs3_host_as_route(unit, l3cfg, BCM_XGS3_L3_OP_ADD, rv);
   2449         } else if (BCM_FAILURE(rv)) {
   2450             return rv;
   2451         }
   2452          
   2453         if (BCM_GPORT_IS_BLACK_HOLE(l3cfg->l3c_port_tgid)) {
   2454              nh_idx_new = 0;
   2455         } else { /* If new entry is in indexed NH table */
   2456             /* Get next hop index. */
   2457             BCM_IF_ERROR_RETURN
   2458                 (_bcm_xgs3_nh_init_add(unit, l3cfg, NULL, &nh_idx_new));
   2459         }
   2460 
   2461         embd_new = BCM_TR3_L3_USE_EMBEDDED_NEXT_HOP(unit, l3cfg->l3c_intf, nh_idx_new);
   2462         if (embd_old != embd_new) {
   2463             rv = bcm_xgs3_l3_del(unit, &entry);
   2464             l3cfg->l3c_hw_index = BCM_XGS3_L3_INVALID_INDEX;
   2465         } else {
   2466             /*Replacement index & flag. */
   2467             l3cfg->l3c_hw_index = entry.l3c_hw_index; 
   2468         }        
   2469         if (BCM_XGS3_L3_HWCALL_CHECK(unit, l3_add)) {
   2470             BCM_XGS3_L3_MODULE_LOCK(unit);
   2471             rv = BCM_XGS3_L3_HWCALL_EXEC(unit, l3_add)(unit, l3cfg, nh_idx_new);
   2472             BCM_XGS3_L3_MODULE_UNLOCK(unit);
   2473         } else {
   2474             rv = BCM_E_UNAVAIL;
   2475         }
   2476 
   2477         /* Do best effort clean_up if needed. */
   2478         if (BCM_FAILURE(rv)) {
   2479             bcm_xgs3_nh_del(unit, 0, nh_idx_new);
   2480         }
   2481 
   2482         /* Free original next hop index. */
   2483         if (embd_old == embd_new) {
   2484             BCM_IF_ERROR_RETURN(bcm_xgs3_nh_del(unit, 0, nh_idx_old));
   2485         }
   2486     }
   2487     return rv;
   2488 }
   2489 
   2490 /*
   2491  * Function:
   2492  *      bcm_tr3_l3_del_intf
   2493  * Purpose:
   2494  *      Delete all the entries in Tr3 L3 host table with
   2495  *      NH matching a certain interface.
   2496  * Parameters:
   2497  *      unit   - (IN)SOC unit number.
   2498  *      l3cfg  - (IN)Pointer to memory for l3 table related information.
   2499  *      negate - (IN)0 means interface match; 1 means not match
   2500  * Returns:
   2501  *      BCM_E_XXX
   2502  */
   2503 int
   2504 bcm_tr3_l3_del_intf(int unit, _bcm_l3_cfg_t *l3cfg, int negate)
   2505 {
   2506     int rv;                             /* Operation return status.      */
   2507     int tmp_rv;                         /* First error occured.          */
   2508     bcm_if_t intf;                      /* Deleted interface id.         */
   2509     int nh_index;                       /* Next hop index.               */
   2510     bcm_l3_egress_t egr;                /* Egress object.                */
   2511     _bcm_if_del_pattern_t pattern;      /* Interface & negate combination 
   2512                                            to be used for every l3 entry
   2513                                            comparision.                  */
   2514 
   2515     /*  Make sure module was initialized. */
   2516     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   2517         return (BCM_E_INIT);
   2518     }
   2519 
   2520     /* Input parameters check */
   2521     if (NULL == l3cfg) {
   2522         return (BCM_E_PARAM);
   2523     }
   2524 
   2525     intf = l3cfg->l3c_intf;
   2526 
   2527     /* Check l3 switching mode. */ 
   2528     if (BCM_XGS3_L3_EGRESS_MODE_ISSET(unit)) {
   2529         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf) || 
   2530             BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) {
   2531             if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) {
   2532                 nh_index = intf - BCM_XGS3_EGRESS_IDX_MIN(unit); 
   2533             } else {
   2534                 nh_index = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   2535             }
   2536             /* Get egress object information. */
   2537             BCM_IF_ERROR_RETURN(bcm_xgs3_nh_get(unit, nh_index, &egr));
   2538             /* Use egress object interface for iteration */
   2539             intf = egr.intf;
   2540         }
   2541     }
   2542 
   2543     pattern.l3_intf = intf;
   2544     pattern.negate = negate;
   2545 
   2546     /* Delete all ipv4 entries matching the interface. */
   2547     tmp_rv = _bcm_tr3_l3_del_match(unit, 0, (void *)&pattern,
   2548                                     _bcm_xgs3_l3_intf_cmp, NULL, NULL);
   2549 
   2550     /* Delete all ipv6 entries matching the interface. */
   2551     rv = _bcm_tr3_l3_del_match(unit, BCM_L3_IP6, (void *)&pattern,
   2552                                 _bcm_xgs3_l3_intf_cmp, NULL, NULL);
   2553 
   2554     return (tmp_rv < 0) ? tmp_rv : rv;
   2555 }
   2556 
   2557 /*
   2558  * Function:
   2559  *      _bcm_tr3_l3_get_by_idx
   2560  * Purpose:
   2561  *      Get an entry from L3 table by index.
   2562  * Parameters:
   2563  *      unit     - (IN)SOC unit number.
   2564  *      dma_ptr  - (IN)Table pointer in dma. 
   2565  *      idx      - (IN)Index to read.
   2566  *      l3cfg    - (OUT)l3 entry search result.
   2567  *      nh_index - (OUT)Next hop index.
   2568  * Returns:
   2569  *      BCM_E_XXX
   2570  */
   2571 int
   2572 _bcm_tr3_l3_get_by_idx(int unit, void *dma_ptr, int idx,
   2573                         _bcm_l3_cfg_t *l3cfg, int *nh_idx)
   2574 {
   2575     int v6;
   2576     int embeded_nh;
   2577     soc_mem_t mem;
   2578     int rv = BCM_E_UNAVAIL;     /* Operation return code. */
   2579 
   2580     /*  Make sure module was initialized. */
   2581     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
   2582         return (BCM_E_INIT);
   2583     }
   2584 
   2585     if (l3cfg->l3c_flags & BCM_L3_IPMC) {
   2586         /* Get multicast entry. */
   2587         rv = _bcm_tr3_l3_ipmc_get_by_idx(unit, NULL, idx, l3cfg);
   2588     } else {
   2589         /* Get unicast entry. */
   2590         v6 = (l3cfg->l3c_flags & BCM_L3_IP6); 
   2591         embeded_nh = (l3cfg->l3c_flags & BCM_L3_DEREFERENCED_NEXTHOP); 
   2592         mem = (v6) ? 
   2593               ((embeded_nh) ? 
   2594               BCM_XGS3_L3_MEM(unit, v6_4) : BCM_XGS3_L3_MEM(unit, v6)) :
   2595               ((embeded_nh) ?  
   2596               BCM_XGS3_L3_MEM(unit, v4_2) : BCM_XGS3_L3_MEM(unit, v4)); 
   2597         rv = _bcm_tr3_l3_get_host_ent_by_idx(unit, NULL, mem, idx, l3cfg, nh_idx);
   2598     }
   2599     return rv;
   2600 }
   2601 
   2602 /*
   2603  * Function:
   2604  *      _bcm_tr3_l3_del_match
   2605  * Purpose:
   2606  *      Delete an entry in L3 table matches a certain rule.
   2607  * Parameters:
   2608  *      unit      - (IN)SOC unit number.
   2609  *      flags.    - (IN)Generic l3 flags. 
   2610  *      pattern   - (IN)Comparison match argurment.
   2611  *      cmp_func  - (IN)Comparison function.
   2612  *      notify_cb - (IN)Delete notification callback. 
   2613  *      user_data - (IN)User provided cookie for callback.
   2614  * Returns:
   2615  *      BCM_E_XXX
   2616  */
   2617 int
   2618 _bcm_tr3_l3_del_match(int unit, int flags, void *pattern,
   2619                        bcm_xgs3_ent_op_cb cmp_func,
   2620                        bcm_l3_host_traverse_cb notify_cb, void *user_data)
   2621 {
   2622     int rv;
   2623     int ipv6;             /* IPv6/IPv4 lookup flag. */
   2624     int nh_idx;           /* Next hop index.        */
   2625     int tbl, idx;         /* Iteration indices.     */
   2626     int cmp_result;       /* Compare against pattern result. */
   2627     bcm_l3_host_t info;   /* Host cb buffer.        */
   2628     _bcm_l3_cfg_t l3cfg;  /* Hw entry info.         */
   2629     int idx_max;
   2630     int num_tables = 1;
   2631     int table_ent_size;
   2632     int table_size;
   2633     char *l3_tbl_ptr = NULL;
   2634 
   2635     soc_mem_t mem[_BCM_TR3_NUM_ESM_HOST_TABLES] =
   2636               {INVALIDm, INVALIDm, INVALIDm, INVALIDm};
   2637 
   2638     /* Check Protocol. */
   2639     ipv6 = (flags & BCM_L3_IP6) ? TRUE : FALSE;
   2640 
   2641     if (ipv6) {
   2642         if (BCM_XGS3_L3_IP6_CNT(unit) == 0) {
   2643             /* No Ipv6 entries. Nothing to delete */
   2644             return BCM_E_NONE;
   2645         }
   2646         mem[0] = BCM_XGS3_L3_MEM(unit, v6); 
   2647         if (soc_feature(unit, soc_feature_l3_extended_host_entry)) {
   2648             mem[1] = BCM_XGS3_L3_MEM(unit, v6_4); 
   2649             num_tables++;
   2650         }
   2651     } else {
   2652         if (BCM_XGS3_L3_IP4_CNT(unit) == 0) {
   2653             /* No Ipv4 entries. Nothing to delete */
   2654             return BCM_E_NONE;
   2655         }
   2656         mem[0] = BCM_XGS3_L3_MEM(unit, v4); 
   2657         if (soc_feature(unit, soc_feature_l3_extended_host_entry)) {
   2658             mem[1] = BCM_XGS3_L3_MEM(unit, v4_2); 
   2659             num_tables++;
   2660         }
   2661     }
   2662 
   2663     for (tbl = 0; tbl < num_tables; tbl++) {
   2664         if (INVALIDm == mem[tbl]) {
   2665             continue;
   2666         }
   2667         idx_max = soc_mem_index_max(unit, mem[tbl]);
   2668         table_ent_size = BCM_L3_MEM_ENT_SIZE(unit, mem[tbl]);
   2669         BCM_IF_ERROR_RETURN(
   2670                 bcm_xgs3_l3_tbl_dma(unit, mem[tbl], table_ent_size,
   2671                     "l3_tbl", &l3_tbl_ptr, &table_size));
   2672         
   2673         for (idx = 0; idx <= idx_max; idx++) {
   2674 
   2675             /* Set protocol. */
   2676             l3cfg.l3c_flags = flags;
   2677 
   2678             rv = _bcm_tr3_l3_get_host_ent_by_idx(unit, l3_tbl_ptr, mem[tbl], idx,
   2679                                                       &l3cfg, &nh_idx);
   2680             /* Check for read errors & invalid entries. */
   2681             if (rv < 0) {
   2682                 if (rv != BCM_E_NOT_FOUND) {
   2683                     if (l3_tbl_ptr) {
   2684                         soc_cm_sfree(unit, l3_tbl_ptr);
   2685                     }
   2686                     return rv;
   2687                 }
   2688                 continue;
   2689             }
   2690 
   2691             /* Check read entry flags & update index accordingly. */
   2692             if (BCM_L3_CMP_EQUAL !=
   2693                 _bcm_xgs3_trvrs_flags_cmp(unit, flags, l3cfg.l3c_flags, &idx)) {
   2694                 continue;
   2695             }
   2696 
   2697             /* If compare function provided match the entry against pattern */
   2698             if (cmp_func) {
   2699                 rv = (*cmp_func) (unit, pattern, (void *)&l3cfg,
   2700                                                  (void *)&nh_idx, &cmp_result);
   2701                 if (BCM_FAILURE(rv)) {
   2702                     soc_cm_sfree(unit, l3_tbl_ptr);
   2703                     return rv;
   2704                 }
   2705                 /* If entry doesn't match the pattern don't delete it. */
   2706                 if (BCM_L3_CMP_EQUAL != cmp_result) {
   2707                     continue;
   2708                 }
   2709             }
   2710 
   2711             /* Entry matches the rule -> delete it. */
   2712             rv = _bcm_tr3_l3_ism_del(unit, &l3cfg);
   2713             if (BCM_FAILURE(rv)) {
   2714                 soc_cm_sfree(unit, l3_tbl_ptr);
   2715                 return rv;
   2716             }
   2717 
   2718             /* Release next hop index. */
   2719             rv = bcm_xgs3_nh_del(unit, 0, nh_idx);
   2720             if (BCM_FAILURE(rv)) {
   2721                 soc_cm_sfree(unit, l3_tbl_ptr);
   2722                 return rv;
   2723             }
   2724    
   2725             /* Check if notification required. */
   2726             if (notify_cb) {
   2727                 /* Fill host info. */
   2728                 _bcm_xgs3_host_ent_init(unit, &l3cfg, FALSE, &info);
   2729                 /* Call notification callback. */
   2730                 (*notify_cb) (unit, idx, &info, user_data);
   2731             }
   2732         }
   2733 
   2734         if (l3_tbl_ptr) {
   2735             soc_cm_sfree(unit, l3_tbl_ptr);
   2736             l3_tbl_ptr = NULL;
   2737         }
   2738     }
   2739 
   2740     if (BCM_TR3_ESM_HOST_TBL_PRESENT(unit)) {
   2741         idx = 0;
   2742         num_tables =  1;
   2743         if (ipv6) {
   2744             mem[0] = BCM_XGS3_L3_MEM(unit, v6_esm); 
   2745             if (soc_feature(unit, soc_feature_l3_extended_host_entry)) {
   2746                 mem[1] = BCM_XGS3_L3_MEM(unit, v6_esm_wide); 
   2747                 num_tables++;
   2748             }
   2749         } else {
   2750             mem[0] = BCM_XGS3_L3_MEM(unit, v4_esm); 
   2751             if (soc_feature(unit, soc_feature_l3_extended_host_entry)) {
   2752                 mem[1] = BCM_XGS3_L3_MEM(unit, v4_esm_wide); 
   2753                 num_tables++;
   2754             }
   2755         }
   2756 
   2757         for (tbl = 0; tbl < num_tables; tbl++) {
   2758             idx = 0; /* reset idx for each table */
   2759             if (INVALIDm == mem[tbl]) {
   2760                 continue;
   2761             }
   2762 
   2763             while (idx < _TR3_ESM_HOST_TBL_FREE_ENTRY(unit, (tbl + (2 * ipv6)))) {
   2764 
   2765                 /* Set protocol. */
   2766                 l3cfg.l3c_flags = flags;
   2767 
   2768                 rv = _bcm_tr3_l3_get_host_ent_by_idx(unit, NULL, mem[tbl], idx,
   2769                                                           &l3cfg, &nh_idx);
   2770                 /* Check for read errors & invalid entries. */
   2771                 if (rv < 0) {
   2772                     if (rv != BCM_E_NOT_FOUND) {
   2773                         return rv;
   2774                     }
   2775                     idx++;
   2776                     continue;
   2777                 }
   2778                 /* Check read entry flags & update index accordingly. */
   2779                 if (BCM_L3_CMP_EQUAL !=
   2780                     _bcm_xgs3_trvrs_flags_cmp(unit, flags, l3cfg.l3c_flags, &idx)) {
   2781                     idx++;
   2782                     continue;
   2783                 }
   2784 
   2785                 /* If compare function provided match the entry against pattern */
   2786                 if (cmp_func) {
   2787                     BCM_IF_ERROR_RETURN((*cmp_func) (unit, pattern, (void *)&l3cfg,
   2788                                                      (void *)&nh_idx, &cmp_result));
   2789                     /* If entry doesn't match the pattern don't delete it. */
   2790                     if (BCM_L3_CMP_EQUAL != cmp_result) {
   2791                         idx++;
   2792                         continue;
   2793                     }
   2794                 }
   2795 
   2796                 /* Entry matches the rule -> delete it. */
   2797                 BCM_IF_ERROR_RETURN(_bcm_tr3_l3_esm_del(unit, &l3cfg));
   2798 
   2799                 /* Release next hop index. */
   2800                 BCM_IF_ERROR_RETURN(bcm_xgs3_nh_del(unit, 0, nh_idx));
   2801    
   2802                 /* Check if notification required. */
   2803                 if (notify_cb) {
   2804                     /* Fill host info. */
   2805                     _bcm_xgs3_host_ent_init(unit, &l3cfg, FALSE, &info);
   2806                     /* Call notification callback. */
   2807                     (*notify_cb) (unit, idx, &info, user_data);
   2808                 }
   2809             }
   2810         } /* per esm table */
   2811     } /* esm */
   2812 
   2813     return (BCM_E_NONE);
   2814 }
   2815 
   2816 /*
   2817  * Function:
   2818  *      _bcm_tr3_esm_host_tbl_init
   2819  * Purpose:
   2820  *      Initialize TR3 external host table sw state. 
   2821  * Parameters:
   2822  *      unit        - (IN)SOC unit number.
   2823  * Returns:
   2824  *      BCM_E_XXX
   2825  */
   2826 int
   2827 _bcm_tr3_esm_host_tbl_init(int unit)
   2828 {
   2829     int tbl;
   2830     int v6 = 0;
   2831     uint32 *esm_entry;
   2832     
   2833     soc_mem_t mem[_BCM_TR3_NUM_ESM_HOST_TABLES];
   2834     ext_ipv4_ucast_entry_t          l3v4_entry;
   2835     ext_ipv4_ucast_wide_entry_t     l3v4wide_entry;
   2836     ext_ipv6_128_ucast_entry_t      l3v6_entry;
   2837     ext_ipv6_128_ucast_wide_entry_t l3v6wide_entry;
   2838 
   2839     mem[0] = EXT_L3_UCAST_DATA_IPV4m;
   2840     mem[1] = EXT_L3_UCAST_DATA_WIDE_IPV4m;
   2841     mem[2] = EXT_L3_UCAST_DATA_IPV6_128m;
   2842     mem[3] = EXT_L3_UCAST_DATA_WIDE_IPV6_128m;
   2843 
   2844     for (tbl = 0; tbl < _BCM_TR3_NUM_ESM_HOST_TABLES; tbl++) {
   2845         if (_TR3_ESM_HOST_TBL_STATE(unit, tbl) != NULL) {
   2846             sal_free(_TR3_ESM_HOST_TBL_STATE(unit, tbl));
   2847             _TR3_ESM_HOST_TBL_STATE(unit, tbl) = NULL;
   2848         }
   2849         
   2850         _TR3_ESM_HOST_TBL_STATE(unit, tbl) = (int*)
   2851                          sal_alloc(sizeof (int), "ESM host free idx info");
   2852 
   2853         if (NULL == _TR3_ESM_HOST_TBL_STATE(unit, tbl)) {
   2854             return (BCM_E_MEMORY);
   2855         }
   2856 
   2857         if (soc_mem_index_count(unit, mem[tbl])) {
   2858             /* ESM table exists and its size is configured */
   2859             if ((mem[tbl] == EXT_L3_UCAST_DATA_IPV6_128m) ||
   2860                 (mem[tbl] == EXT_L3_UCAST_DATA_WIDE_IPV6_128m)) {
   2861                 v6 = 1;
   2862             }
   2863 
   2864             BCM_TR3_ESM_L3_HOST_ENTRY_BUF(v6, mem[tbl], esm_entry,
   2865                                           l3v4_entry,
   2866                                           l3v4wide_entry,
   2867                                           l3v6_entry,
   2868                                           l3v6wide_entry);
   2869             SOC_IF_ERROR_RETURN(soc_mem_read(unit, mem[tbl],
   2870                                 MEM_BLOCK_ANY, 0, esm_entry));
   2871 
   2872             soc_mem_field32_set(unit, mem[tbl], esm_entry, CLASS_IDf,
   2873                                   _TR3_ESM_HOST_ENTRY_INVALID_MARKER);
   2874     
   2875             BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem[tbl],
   2876                                 MEM_BLOCK_ALL, 0, esm_entry));
   2877         }
   2878         _TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl) = 0;
   2879     }
   2880 
   2881     return (BCM_E_NONE);
   2882 }
   2883 
   2884 /*
   2885  * Function:
   2886  *      _bcm_tr3_esm_host_tbl_deinit
   2887  * Purpose:
   2888  *      Free the TR3 external host table sw state. 
   2889  * Parameters:
   2890  *      unit        - (IN)SOC unit number.
   2891  * Returns:
   2892  *      BCM_E_XXX
   2893  */
   2894 int
   2895 _bcm_tr3_esm_host_tbl_deinit(int unit)
   2896 {
   2897     int tbl;
   2898 
   2899     for (tbl = 0; tbl < _BCM_TR3_NUM_ESM_HOST_TABLES; tbl++) {
   2900         if (_TR3_ESM_HOST_TBL_STATE(unit, tbl) != NULL) {
   2901             sal_free(_TR3_ESM_HOST_TBL_STATE(unit, tbl));
   2902             _TR3_ESM_HOST_TBL_STATE(unit, tbl) = NULL;
   2903         }
   2904     }
   2905 
   2906     return (BCM_E_NONE);
   2907 }
   2908 
   2909 /*
   2910  * Function:
   2911  *      _bcm_hx4_l3_defip_init
   2912  * Purpose:
   2913  *      Configure HX4 internal route table as per soc properties.
   2914  *      (tcam pairing for IPv4, 64/128 bit IPV6 prefixes)
   2915  * Parameters:
   2916  *      unit     - (IN)SOC unit number.
   2917  * Returns:
   2918  *      BCM_E_XXX
   2919  */
   2920 STATIC int
   2921 _bcm_hx4_l3_defip_init(int unit)
   2922 {
   2923     int defip_config;
   2924     int ipv6_64_depth = 0;
   2925     uint32 defip_key_sel_0 = 0;
   2926     uint32 defip_key_sel_1 = 0;
   2927     int mem_v4, mem_v6, mem_v6_128; /* Route table memories */
   2928     int ranger_device;              /* Ranger specific config */
   2929     int num_ipv6_128b_entries;
   2930     int tcam_pair_count = 0;
   2931     int tcam_idx = 0;
   2932     int start_index = 0;
   2933     int tcam_depth = SOC_L3_DEFIP_TCAM_DEPTH_GET(unit);
   2934 
   2935     ranger_device = FALSE;
   2936     if (soc_feature(unit, soc_feature_l3_256_defip_table)) {
   2937         ranger_device = TRUE;
   2938     }
   2939 
   2940     defip_config = soc_property_get(unit, spn_IPV6_LPM_128B_ENABLE,
   2941                                         ((ranger_device) ? 0 : 1));
   2942     num_ipv6_128b_entries =  SOC_L3_DEFIP_MAX_128B_ENTRIES(unit);
   2943     BCM_XGS3_L3_IP6_MAX_128B_ENTRIES(unit) = num_ipv6_128b_entries;
   2944 
   2945 
   2946     if (num_ipv6_128b_entries) {
   2947         tcam_pair_count = (num_ipv6_128b_entries / tcam_depth) +
   2948                           ((num_ipv6_128b_entries % tcam_depth) ? 1 : 0);
   2949     } else {
   2950         tcam_pair_count = 0;
   2951     }
   2952 
   2953     if (tcam_pair_count > (SOC_CONTROL(unit)->l3_defip_max_tcams / 2)) {
   2954         tcam_pair_count = (SOC_CONTROL(unit)->l3_defip_max_tcams / 2);
   2955     }
   2956 
   2957     if (!defip_config) {
   2958         if (ranger_device) {
   2959             ipv6_64_depth = _BCM_HX4_RANGER_DEFIP_TCAM_DEPTH;
   2960         } else {
   2961             ipv6_64_depth = SOC_CONTROL(unit)->l3_defip_max_tcams * tcam_depth; 
   2962         }
   2963     } else {
   2964         for (tcam_idx = 0; tcam_idx < tcam_pair_count; tcam_idx++) {
   2965             defip_key_sel_0 |= (0x01 << tcam_idx);
   2966         }
   2967 
   2968         ipv6_64_depth =  soc_mem_index_count(unit, L3_DEFIPm);
   2969         if (ranger_device) {
   2970             defip_key_sel_0 = 0x3;
   2971             ipv6_64_depth = 0;
   2972         }
   2973     }
   2974 
   2975     /* LPM config regs. */
   2976     BCM_IF_ERROR_RETURN(WRITE_L3_DEFIP_KEY_SEL_0r(unit, defip_key_sel_0));
   2977     BCM_IF_ERROR_RETURN(WRITE_L3_DEFIP_KEY_SEL_1r(unit, defip_key_sel_1));
   2978 
   2979     /* Get memory for IPv4 entries. */
   2980     BCM_IF_ERROR_RETURN(_bcm_tr3_l3_defip_mem_get(unit, 0, 0, &mem_v4));
   2981 
   2982     /* Initialize IPv4 entries lookup engine. */
   2983     BCM_IF_ERROR_RETURN(soc_fb_lpm_init(unit));
   2984 
   2985     /* Get memory for IPv6 entries. */
   2986     BCM_IF_ERROR_RETURN
   2987         (_bcm_tr3_l3_defip_mem_get(unit, BCM_L3_IP6, 0, &mem_v6));
   2988 
   2989     /* Initialize IPv6 entries lookup engine. */
   2990     if (mem_v4 != mem_v6) {
   2991         BCM_IF_ERROR_RETURN(soc_fb_lpm_init(unit));
   2992     }
   2993 
   2994     /* Overriding defaults set during lpm init */
   2995     if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   2996         BCM_IF_ERROR_RETURN(soc_fb_lpm128_init(unit));
   2997         ipv6_64_depth -= (tcam_pair_count * tcam_depth * 2);
   2998         start_index = (tcam_pair_count * tcam_depth * 2);
   2999     } else {
   3000         start_index = 0;
   3001     }
   3002 
   3003     SOC_LPM_STATE_FENT(unit, (MAX_PFX_INDEX(unit)))  = ipv6_64_depth;
   3004     SOC_LPM_STATE_START(unit, (MAX_PFX_INDEX(unit))) = start_index;
   3005     SOC_LPM_STATE_END(unit, (MAX_PFX_INDEX(unit)))   = start_index - 1;
   3006 
   3007     BCM_IF_ERROR_RETURN(soc_fb_lpm_state_config(unit, ipv6_64_depth, 
   3008                 start_index));
   3009 
   3010     /* Get memory for IPv6 entries with prefix length > 64. */
   3011     BCM_IF_ERROR_RETURN
   3012         (_bcm_tr3_l3_defip_mem_get(unit, BCM_L3_IP6,
   3013                                   BCM_XGS3_L3_IPV6_PREFIX_LEN,
   3014                                   &mem_v6_128));
   3015 
   3016     /* Initialize IPv6 entries lookup engine. */
   3017     if (mem_v6 != mem_v6_128) {
   3018         if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3019             return soc_fb_lpm128_init(unit);
   3020         } else {
   3021             BCM_IF_ERROR_RETURN(_bcm_tr3_defip_pair128_init(unit));
   3022         }
   3023     }
   3024 
   3025     return BCM_E_NONE;
   3026 }
   3027 
   3028 /*
   3029  * Function:
   3030  *      _bcm_tr3_l3_defip_init
   3031  * Purpose:
   3032  *      Configure TR3 internal route table as per soc properties.
   3033  *      (tcam pairing for IPv4, 64/128 bit IPV6 prefixes)
   3034  * Parameters:
   3035  *      unit     - (IN)SOC unit number.
   3036  * Returns:
   3037  *      BCM_E_XXX
   3038  */
   3039 int
   3040 _bcm_tr3_l3_defip_init(int unit)
   3041 {
   3042     int defip_config;
   3043     int index_min, index_max;
   3044     uint32 defip_key_sel_val = 0;
   3045     int mem_v4, mem_v6, mem_v6_128; /* Route table memories */
   3046     int ipv6_64_depth = 0;
   3047     int rangerplus_device;          /* Ranger plus specific config */
   3048     int num_ipv6_128b_entries;
   3049     int start_index = 0;
   3050     int tcam_pair_count = 0;
   3051     int tcam_depth = SOC_L3_DEFIP_TCAM_DEPTH_GET(unit);
   3052 
   3053     if (soc_feature(unit, soc_feature_l3_expanded_defip_table)) {
   3054         return _bcm_hx4_l3_defip_init(unit);/* HX4, Ranger */
   3055     }
   3056 
   3057     rangerplus_device = FALSE;
   3058     if (soc_feature(unit, soc_feature_l3_256_defip_table)) {
   3059         rangerplus_device = TRUE;
   3060     }
   3061 
   3062     defip_config = soc_property_get(unit, spn_IPV6_LPM_128B_ENABLE,
   3063                                        (rangerplus_device) ? 0 : 1);
   3064     num_ipv6_128b_entries =  SOC_L3_DEFIP_MAX_128B_ENTRIES(unit);
   3065     BCM_XGS3_L3_IP6_MAX_128B_ENTRIES(unit) = num_ipv6_128b_entries;
   3066 
   3067 
   3068     if (num_ipv6_128b_entries) {
   3069         tcam_pair_count = (num_ipv6_128b_entries / tcam_depth) +
   3070                           ((num_ipv6_128b_entries % tcam_depth) ? 1 : 0);
   3071     } else {
   3072         tcam_pair_count = 0;
   3073     }
   3074 
   3075     if ((rangerplus_device == TRUE) || 
   3076         soc_feature(unit, soc_feature_l3_reduced_defip_table)) {
   3077         if (!defip_config) {
   3078             if (soc_feature(unit, soc_feature_l3_reduced_defip_table)) {
   3079                 ipv6_64_depth = 6 * _BCM_TR3_DEFIP_TCAM_DEPTH;
   3080             } else {
   3081                 ipv6_64_depth = 8 * _BCM_TR3_DEFIP_TCAM_DEPTH;
   3082                 if (rangerplus_device) {
   3083                     ipv6_64_depth = _BCM_HX4_RANGER_DEFIP_TCAM_DEPTH;
   3084                 }
   3085             }
   3086         } else if (soc_feature(unit, soc_feature_l3_reduced_defip_table)) {
   3087             switch (tcam_pair_count) {
   3088                 case 1:
   3089                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr,
   3090                                       &defip_key_sel_val, V6_KEY_SEL_CAM0_1f,
   3091                                       0x1);
   3092                 break;
   3093 
   3094                 case 2:
   3095                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr,
   3096                                       &defip_key_sel_val, V6_KEY_SEL_CAM0_1f,
   3097                                       0x1);
   3098                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr,
   3099                                       &defip_key_sel_val, V6_KEY_SEL_CAM2_3f,
   3100                                       0x1);
   3101                 break;
   3102 
   3103                 case 3:
   3104                 default:
   3105                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr,
   3106                                       &defip_key_sel_val, V6_KEY_SEL_CAM0_1f,
   3107                                       0x1);
   3108                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr,
   3109                                       &defip_key_sel_val, V6_KEY_SEL_CAM2_3f,
   3110                                       0x1);
   3111                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr,
   3112                                       &defip_key_sel_val, V6_KEY_SEL_CAM4_5f,
   3113                                       0x1);
   3114                 break;
   3115 
   3116             }
   3117             ipv6_64_depth = soc_mem_index_count(unit, L3_DEFIPm);
   3118         } else {
   3119 
   3120             soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val,
   3121                                V6_KEY_SEL_CAM0_1f, 0x1);
   3122             soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val,
   3123                                V6_KEY_SEL_CAM2_3f, 0x1);
   3124 
   3125             ipv6_64_depth = 4 * _BCM_TR3_DEFIP_TCAM_DEPTH;
   3126             if (rangerplus_device) {
   3127                 ipv6_64_depth = 0;
   3128             }
   3129         }
   3130     } else { /* Tr3 case */
   3131         switch (tcam_pair_count) {
   3132             case 1:
   3133                 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val,
   3134                                   V6_KEY_SEL_CAM0_1f, 0x1);
   3135                 break;
   3136 
   3137             case 2:
   3138                 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val,
   3139                                   V6_KEY_SEL_CAM0_1f, 0x1);
   3140                 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val,
   3141                                   V6_KEY_SEL_CAM2_3f, 0x1);
   3142                 break;
   3143 
   3144             case 3:
   3145                 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   3146                                   &defip_key_sel_val, V6_KEY_SEL_CAM0_1f, 
   3147                                   0x1);
   3148                 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   3149                                   &defip_key_sel_val, V6_KEY_SEL_CAM2_3f, 
   3150                                   0x1);
   3151                 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   3152                                   &defip_key_sel_val, V6_KEY_SEL_CAM4_5f, 
   3153                                   0x1);
   3154                 break;
   3155 
   3156             case 4:
   3157                 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   3158                                   &defip_key_sel_val, V6_KEY_SEL_CAM0_1f, 
   3159                                   0x1);
   3160                 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   3161                                   &defip_key_sel_val, V6_KEY_SEL_CAM2_3f, 
   3162                                   0x1);
   3163                 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   3164                                   &defip_key_sel_val, V6_KEY_SEL_CAM4_5f, 
   3165                                   0x1);
   3166                 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   3167                                   &defip_key_sel_val, V6_KEY_SEL_CAM6_7f, 
   3168                                   0x1);
   3169                 break;
   3170 
   3171             default:
   3172                 break;
   3173         }
   3174         ipv6_64_depth =  soc_mem_index_count(unit, L3_DEFIPm); 
   3175     }
   3176 
   3177     BCM_IF_ERROR_RETURN(WRITE_L3_DEFIP_KEY_SELr(unit, defip_key_sel_val));
   3178 
   3179     /* Get memory for IPv4 entries. */
   3180     BCM_IF_ERROR_RETURN(_bcm_tr3_l3_defip_mem_get(unit, 0, 0, &mem_v4));
   3181 
   3182     /* Initialize IPv4 entries lookup engine. */
   3183     if (BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV4_DEFIPm)) {
   3184         BCM_IF_ERROR_RETURN(_bcm_tr3_ext_lpm_init(unit, mem_v4)); 
   3185     } else {
   3186         BCM_IF_ERROR_RETURN(soc_fb_lpm_init(unit));
   3187     }
   3188 
   3189     /* Get memory for IPv6 entries. */
   3190     BCM_IF_ERROR_RETURN
   3191         (_bcm_tr3_l3_defip_mem_get(unit, BCM_L3_IP6, 0, &mem_v6));
   3192 
   3193     /* Initialize IPv6 entries lookup engine. */
   3194     if (BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV6_64_DEFIPm) ||
   3195         BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV6_128_DEFIPm)) {
   3196         BCM_IF_ERROR_RETURN(_bcm_tr3_ext_lpm_init(unit, mem_v6));
   3197     } else {
   3198         if (mem_v4 != mem_v6) {
   3199             BCM_IF_ERROR_RETURN(soc_fb_lpm_init(unit));
   3200         }
   3201         /* Overriding defaults set during lpm init */
   3202         if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3203             BCM_IF_ERROR_RETURN(soc_fb_lpm128_init(unit));
   3204             ipv6_64_depth -= (tcam_pair_count * tcam_depth * 2);
   3205             start_index = (tcam_pair_count * tcam_depth * 2);
   3206         } else {
   3207             start_index = 0;
   3208         }
   3209 
   3210         SOC_LPM_STATE_START(unit, (MAX_PFX_INDEX(unit))) = start_index;
   3211         SOC_LPM_STATE_END(unit, (MAX_PFX_INDEX(unit))) = start_index - 1;
   3212         SOC_LPM_STATE_FENT(unit, (MAX_PFX_INDEX(unit))) = ipv6_64_depth;
   3213         BCM_IF_ERROR_RETURN(soc_fb_lpm_state_config(unit, ipv6_64_depth, 
   3214                                                     start_index));
   3215     }
   3216 
   3217     /* Get memory for IPv6 entries with prefix length > 64. */
   3218     BCM_IF_ERROR_RETURN
   3219         (_bcm_tr3_l3_defip_mem_get(unit, BCM_L3_IP6,
   3220                                   BCM_XGS3_L3_IPV6_PREFIX_LEN,
   3221                                   &mem_v6_128));
   3222 
   3223     /* Initialize IPv6 entries lookup engine. */
   3224     if (mem_v6 != mem_v6_128) {
   3225         if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3226             return soc_fb_lpm128_init(unit);
   3227         } else {
   3228             BCM_IF_ERROR_RETURN(_bcm_tr3_defip_pair128_init(unit));
   3229         }
   3230     }
   3231 
   3232     /* Update defip size in l3 book keeping if ESM present */
   3233     if (soc_feature(unit, soc_feature_esm_support) && (L3_DEFIPm != mem_v4)) {
   3234         index_min = soc_mem_index_min(unit, mem_v4);
   3235         index_max = soc_mem_index_max(unit, mem_v4);
   3236         BCM_XGS3_L3_DEFIP_TBL_SIZE(unit) = index_max - index_min + 1;
   3237     }
   3238     if (!SOC_LPM_STAT_INIT_CHECK(unit)) {
   3239         if (soc_feature(unit, soc_feature_l3_shared_defip_table)) {
   3240             if (soc_fb_lpm_stat_init(unit) < 0) {
   3241        /* COVERITY
   3242         * soc_fb_lpm_deinit is called in error condition.
   3243         * so irrespective of its return value we are going to release lpm lock
   3244         * and return E_INTERNAL. Hence we can ignore the return value
   3245         */
   3246         /* coverity[check_return] */
   3247                 soc_fb_lpm_deinit(unit);
   3248                 return SOC_E_INTERNAL;
   3249             }
   3250         }
   3251     }
   3252     return BCM_E_NONE;
   3253 }
   3254 
   3255 /*
   3256  * Function:
   3257  *      _bcm_tr3_l3_defip_deinit
   3258  * Purpose:
   3259  *      De-initialize route table for triumph3 devices.
   3260  * Parameters:
   3261  *      unit - (IN)  SOC unit number.
   3262  * Returns:
   3263  *      BCM_E_XXX
   3264  */
   3265 int 
   3266 _bcm_tr3_l3_defip_deinit(int unit)
   3267 {
   3268     soc_mem_t mem_v4;      /* IPv4 Route table memory.             */
   3269     soc_mem_t mem_v6;      /* IPv6 Route table memory.             */
   3270     soc_mem_t mem_v6_128;  /* IPv6 full prefix route table memory. */
   3271 
   3272     /* Get memory for IPv4 entries. */
   3273     BCM_IF_ERROR_RETURN(_bcm_tr3_l3_defip_mem_get(unit, 0, 0, &mem_v4));
   3274 
   3275     /* Initialize IPv4 entries lookup engine. */
   3276     if (BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV4_DEFIPm)) {
   3277         BCM_IF_ERROR_RETURN(_bcm_tr3_ext_lpm_deinit(unit, mem_v4));
   3278     } else {
   3279         BCM_IF_ERROR_RETURN(soc_fb_lpm_deinit(unit));
   3280     }
   3281 
   3282     /* Get memory for IPv6 entries. */
   3283     BCM_IF_ERROR_RETURN
   3284         (_bcm_tr3_l3_defip_mem_get(unit, BCM_L3_IP6, 0, &mem_v6));
   3285 
   3286     /* Initialize IPv6 entries lookup engine. */
   3287     if (BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV6_64_DEFIPm) ||
   3288         BCM_TR3_ESM_LPM_TBL_PRESENT(unit, EXT_IPV6_128_DEFIPm)) {
   3289         BCM_IF_ERROR_RETURN(_bcm_tr3_ext_lpm_deinit(unit, mem_v6));
   3290     } else {
   3291         if (mem_v4 != mem_v6) {
   3292             BCM_IF_ERROR_RETURN(soc_fb_lpm_deinit(unit));
   3293         }
   3294     } 
   3295 
   3296     /* Get memory for IPv6 entries with prefix length > 64. */
   3297     BCM_IF_ERROR_RETURN
   3298         (_bcm_tr3_l3_defip_mem_get(unit, BCM_L3_IP6,
   3299                                   BCM_XGS3_L3_IPV6_PREFIX_LEN,
   3300                                   &mem_v6_128));
   3301 
   3302     /* Initialize IPv6 entries lookup engine. */
   3303     if (mem_v6 != mem_v6_128) {
   3304          if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3305              BCM_IF_ERROR_RETURN(soc_fb_lpm128_deinit(unit));
   3306          } else {
   3307              BCM_IF_ERROR_RETURN(_bcm_defip_pair128_deinit(unit));
   3308          }
   3309     }
   3310     return (BCM_E_NONE);
   3311 
   3312 }
   3313 
   3314 /*
   3315  * Function:
   3316  *      _bcm_tr3_l3_lpm_get
   3317  * Purpose:
   3318  *      Get an entry from the route table.
   3319  * Parameters:
   3320  *      unit        - (IN)SOC unit number.
   3321  *      lpm_cfg     - (IN)Buffer to fill defip information. 
   3322  *      nh_ecmp_idx - (IN)Next hop or ecmp group index
   3323  * Returns:
   3324  *      BCM_E_XXX
   3325  */
   3326 int
   3327 _bcm_tr3_l3_lpm_get(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx)
   3328 {
   3329     soc_mem_t mem = L3_DEFIPm;
   3330     uint32 max_v6_entries = BCM_XGS3_L3_IP6_MAX_128B_ENTRIES(unit);
   3331 
   3332     /* Input parameters check */
   3333     if (NULL == lpm_cfg) {
   3334         return (BCM_E_PARAM);
   3335     }
   3336 
   3337     BCM_IF_ERROR_RETURN(_bcm_tr3_l3_defip_mem_get(unit, lpm_cfg->defip_flags,
   3338                                               lpm_cfg->defip_sub_len, &mem));
   3339 
   3340     if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3341         if (mem == L3_DEFIPm || mem == L3_DEFIP_PAIR_128m) {
   3342             return _bcm_l3_scaled_lpm_get(unit, lpm_cfg, nh_ecmp_idx);
   3343         }
   3344     }
   3345 
   3346     switch (mem) {
   3347         case EXT_IPV4_DEFIPm:
   3348         case EXT_IPV6_64_DEFIPm:
   3349         case EXT_IPV6_128_DEFIPm:
   3350             return _bcm_tr3_ext_lpm_match(unit, lpm_cfg, nh_ecmp_idx);
   3351         case L3_DEFIP_PAIR_128m:
   3352             if (max_v6_entries > 0) {
   3353                 return _bcm_l3_defip_pair128_get(unit, lpm_cfg, nh_ecmp_idx);
   3354             }
   3355             break;
   3356         default:
   3357             if (soc_mem_index_count(unit, L3_DEFIPm) > 0) {
   3358                 return _bcm_fb_lpm_get(unit, lpm_cfg, nh_ecmp_idx);
   3359             }
   3360             break;
   3361     }
   3362 
   3363     return (BCM_E_NOT_FOUND);
   3364 }
   3365 
   3366 /*
   3367  * Function:
   3368  *      _bcm_tr3_l3_lpm_add
   3369  * Purpose:
   3370  *      Add an entry to TR3 route table table.
   3371  * Parameters:
   3372  *      unit        - (IN)SOC unit number.
   3373  *      lpm_cfg     - (IN)Buffer to fill defip information. 
   3374  *      nh_ecmp_idx - (IN)Next hop or ecmp group index.
   3375  * Returns:
   3376  *      BCM_E_XXX
   3377  */
   3378 int
   3379 _bcm_tr3_l3_lpm_add(int unit, _bcm_defip_cfg_t *lpm_cfg, int nh_ecmp_idx)
   3380 {
   3381     soc_mem_t mem = L3_DEFIPm;
   3382 
   3383     /* Input parameters check */
   3384     if (NULL == lpm_cfg) {
   3385         return (BCM_E_PARAM);
   3386     }
   3387 
   3388     BCM_IF_ERROR_RETURN(_bcm_tr3_l3_defip_mem_get(unit, lpm_cfg->defip_flags,
   3389                                               lpm_cfg->defip_sub_len, &mem));
   3390 
   3391     if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3392         if (mem == L3_DEFIPm || mem == L3_DEFIP_PAIR_128m) {
   3393             return _bcm_l3_scaled_lpm_add(unit, lpm_cfg, nh_ecmp_idx);
   3394         }
   3395     }
   3396 
   3397     switch (mem) {
   3398         case EXT_IPV4_DEFIPm:
   3399         case EXT_IPV6_64_DEFIPm:
   3400         case EXT_IPV6_128_DEFIPm:
   3401             if (BCM_L3_RPE_SET(lpm_cfg->defip_flags)) {
   3402                 if (lpm_cfg->defip_lookup_class > SOC_ADDR_CLASS_MAX(unit)) {
   3403                     return (BCM_E_PARAM);
   3404                 }
   3405             } else {
   3406                 lpm_cfg->defip_prio = (lpm_cfg->defip_lookup_class & 0x3C0) >> 6;
   3407                 lpm_cfg->defip_lookup_class = lpm_cfg->defip_lookup_class & 0x3F;
   3408             }
   3409 
   3410             return _bcm_tr3_ext_lpm_add(unit, lpm_cfg, nh_ecmp_idx);
   3411         case L3_DEFIP_PAIR_128m:
   3412             if (soc_mem_index_count(unit, L3_DEFIP_PAIR_128m) > 0) {
   3413                 return _bcm_l3_defip_pair128_add(unit, lpm_cfg, nh_ecmp_idx);
   3414             }
   3415             break;
   3416         default:
   3417             if (soc_mem_index_count(unit, L3_DEFIPm) > 0) {
   3418                 return _bcm_fb_lpm_add(unit, lpm_cfg, nh_ecmp_idx);
   3419             }
   3420             break;
   3421     }
   3422 
   3423     return (BCM_E_FULL);
   3424 }
   3425 
   3426 /*
   3427  * Function:
   3428  *      _bcm_tr3_l3_lpm_del
   3429  * Purpose:
   3430  *      Delete an entry from the route table.
   3431  * Parameters:
   3432  *      unit    - (IN)SOC unit number.
   3433  *      lpm_cfg - (IN)Buffer to fill defip information. 
   3434  * Returns:
   3435  *      BCM_E_XXX
   3436  */
   3437 int
   3438 _bcm_tr3_l3_lpm_del(int unit, _bcm_defip_cfg_t *lpm_cfg)
   3439 {
   3440     soc_mem_t mem = L3_DEFIPm;
   3441     uint32 max_v6_entries = BCM_XGS3_L3_IP6_MAX_128B_ENTRIES(unit);
   3442 
   3443     /* Input parameters check */
   3444     if (NULL == lpm_cfg) {
   3445         return (BCM_E_PARAM);
   3446     }
   3447 
   3448     BCM_IF_ERROR_RETURN(_bcm_tr3_l3_defip_mem_get(unit, lpm_cfg->defip_flags,
   3449                                               lpm_cfg->defip_sub_len, &mem));
   3450 
   3451     if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3452         if (mem == L3_DEFIPm || mem == L3_DEFIP_PAIR_128m) {
   3453             return _bcm_l3_scaled_lpm_del(unit, lpm_cfg);
   3454         }
   3455     }
   3456 
   3457     switch (mem) {
   3458         case EXT_IPV4_DEFIPm:
   3459         case EXT_IPV6_64_DEFIPm:
   3460         case EXT_IPV6_128_DEFIPm:
   3461             return _bcm_tr3_ext_lpm_delete(unit, lpm_cfg);
   3462         case L3_DEFIP_PAIR_128m:
   3463             if (max_v6_entries > 0) {
   3464                 return _bcm_l3_defip_pair128_del(unit, lpm_cfg);
   3465             }
   3466             break;    
   3467         default: 
   3468             if (soc_mem_index_count(unit, L3_DEFIPm) > 0) {
   3469                 return _bcm_fb_lpm_del(unit, lpm_cfg);
   3470             }
   3471             break;    
   3472     }
   3473 
   3474     return (BCM_E_NOT_FOUND);
   3475 }
   3476 
   3477 /*
   3478  * Function:
   3479  *      _bcm_tr3_l3_lpm_update_match
   3480  * Purpose:
   3481  *      Update/Delete all entries in defip table matching a certain rule.
   3482  * Parameters:
   3483  *      unit     - (IN)SOC unit number.
   3484  *      trv_data - (IN)Delete pattern + compare,act,notify routines.  
   3485  * Returns:
   3486  *      BCM_E_XXX
   3487  */
   3488 int
   3489 _bcm_tr3_l3_lpm_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data)
   3490 {
   3491     soc_mem_t mem = L3_DEFIPm;  /* Route table memory.      */
   3492     int rv1 = BCM_E_NONE;
   3493     int rv2 = BCM_E_NONE;
   3494     uint32 max_v6_entries = BCM_XGS3_L3_IP6_MAX_128B_ENTRIES(unit);
   3495 
   3496     BCM_IF_ERROR_RETURN(_bcm_tr3_l3_defip_mem_get(unit, trv_data->flags, 0, &mem));
   3497 
   3498     switch (mem) {
   3499         case EXT_IPV4_DEFIPm:
   3500         case EXT_IPV6_64_DEFIPm:
   3501         case EXT_IPV6_128_DEFIPm:
   3502             return  _bcm_tr3_defip_traverse(unit, trv_data);
   3503         default: 
   3504             if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3505                 return _bcm_l3_scaled_lpm_update_match(unit, trv_data);
   3506             }
   3507 
   3508             if ((trv_data->flags & BCM_L3_IP6) && (max_v6_entries > 0)) {
   3509                 rv2 = _bcm_l3_defip_pair128_update_match(unit, trv_data);
   3510             }
   3511 
   3512             if (soc_mem_index_count(unit, L3_DEFIPm) > 0) {
   3513                 rv1 = _bcm_fb_lpm_update_match(unit, trv_data);
   3514             }
   3515             BCM_IF_ERROR_RETURN(rv1);
   3516             BCM_IF_ERROR_RETURN(rv2);
   3517     }
   3518 
   3519     return (BCM_E_NONE);
   3520 }
   3521 
   3522 /*
   3523  * Function:
   3524  *      _bcm_fs_l3_defip_urpf_enable
   3525  * Purpose:
   3526  *      Configure HX4 internal route table for URPF mode
   3527  * Parameters:
   3528  *      unit     - (IN)SOC unit number.
   3529  *      enable   - (IN)Enable/disable URPF.
   3530  * Returns:
   3531  *      BCM_E_XXX
   3532  */
   3533 STATIC int
   3534 _bcm_fs_l3_defip_urpf_enable(int unit, int enable)
   3535 {
   3536     int defip_config;
   3537     int ipv6_64_depth = 0;
   3538     int ipv6_128_depth = 0;
   3539     int ipv6_128_dip_offset = 0;
   3540     uint32 defip_key_sel_0 = 0;
   3541     uint32 defip_key_sel_1 = 0;
   3542     uint32 num_ipv6_128b_entries = 0;
   3543     int    tcam_pair_count = 0;
   3544     uint32 tcam_depth = SOC_L3_DEFIP_TCAM_DEPTH_GET(unit);
   3545     int    tcam_idx = 0;
   3546     int start_index = 0;
   3547 
   3548     defip_config = soc_property_get(unit, spn_IPV6_LPM_128B_ENABLE, 1);
   3549     num_ipv6_128b_entries =  SOC_L3_DEFIP_MAX_128B_ENTRIES(unit);
   3550 
   3551     if (num_ipv6_128b_entries) {
   3552         tcam_pair_count = (num_ipv6_128b_entries / tcam_depth) +
   3553                           ((num_ipv6_128b_entries % tcam_depth) ? 1 : 0);
   3554     } else {
   3555         tcam_pair_count = 0;
   3556     }
   3557 
   3558     if (tcam_pair_count > (SOC_CONTROL(unit)->l3_defip_max_tcams / 2)) {
   3559         tcam_pair_count = (SOC_CONTROL(unit)->l3_defip_max_tcams / 2);
   3560     }
   3561 
   3562     if (enable) {
   3563 
   3564         /* Ranger device does not support URPF */
   3565         defip_key_sel_1 = 0xFF00;
   3566         if (defip_config) {
   3567             switch (tcam_pair_count) {
   3568                 case 0:
   3569                     ipv6_64_depth = 8 * tcam_depth;
   3570                     start_index = 0;
   3571                     break;
   3572 
   3573                 case 1:
   3574                 case 2:
   3575                     defip_key_sel_0 = 0x11;
   3576                     if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3577                         ipv6_64_depth = 6 * tcam_depth;
   3578                         start_index = 2 * tcam_depth;
   3579                     }
   3580                     break;
   3581                 case 3:
   3582                 case 4:
   3583                     defip_key_sel_0 = 0x33;
   3584                     if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3585                         ipv6_64_depth = 4 * tcam_depth;
   3586                         start_index = 4 * tcam_depth;
   3587                     }
   3588                     break;
   3589                 case 5:
   3590                 case 6:
   3591                     defip_key_sel_0 = 0x77;
   3592                     if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3593                         ipv6_64_depth = 2 * tcam_depth;
   3594                         start_index = 6 * tcam_depth;
   3595                     }
   3596                     break;
   3597                 case 7:
   3598                 case 8:
   3599                 default:
   3600                     defip_key_sel_0 = 0xFF;
   3601                     if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3602                         ipv6_64_depth = 0;
   3603                         start_index = 8 * tcam_depth;
   3604                     }
   3605                     break;
   3606             }
   3607 
   3608             if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3609                 ipv6_64_depth       = soc_mem_index_count(unit, L3_DEFIPm) / 2;
   3610                 ipv6_128_dip_offset = num_ipv6_128b_entries / 2;
   3611                 ipv6_128_depth      = num_ipv6_128b_entries / 2;
   3612             }
   3613         } else {
   3614             ipv6_64_depth       = soc_mem_index_count(unit, L3_DEFIPm) / 2;
   3615             ipv6_128_dip_offset = 0;
   3616             ipv6_128_depth      = 0;
   3617         }
   3618     } else { /* Disable uRPF */
   3619         if (defip_config) {
   3620             for (tcam_idx = 0; tcam_idx < tcam_pair_count; tcam_idx++) {
   3621                 defip_key_sel_0 |= (0x01 << tcam_idx);
   3622             }
   3623 
   3624             ipv6_64_depth       = soc_mem_index_count(unit, L3_DEFIPm);
   3625             ipv6_128_dip_offset = num_ipv6_128b_entries;
   3626             ipv6_128_depth      = num_ipv6_128b_entries;
   3627             if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3628                 ipv6_64_depth -= (tcam_pair_count * tcam_depth * 2);
   3629                 start_index = (tcam_pair_count * tcam_depth * 2);
   3630             }
   3631         } else {
   3632             ipv6_64_depth       = soc_mem_index_count(unit, L3_DEFIPm);
   3633             ipv6_128_dip_offset = 0;
   3634             ipv6_128_depth      = 0;
   3635         }
   3636 
   3637     }
   3638 
   3639     SOC_LPM_STATE_FENT(unit, (MAX_PFX_INDEX(unit)))  = ipv6_64_depth;
   3640 
   3641     if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3642         BCM_DEFIP_PAIR128_URPF_OFFSET(unit)    = ipv6_128_dip_offset;
   3643         BCM_DEFIP_PAIR128_IDX_MAX(unit)        = ipv6_128_depth - 1;
   3644         BCM_DEFIP_PAIR128_TOTAL(unit)          = ipv6_128_depth;
   3645     }
   3646 
   3647     SOC_LPM_STATE_START(unit, (MAX_PFX_INDEX(unit))) = start_index;
   3648     SOC_LPM_STATE_END(unit, (MAX_PFX_INDEX(unit)))   = start_index-1;
   3649     BCM_IF_ERROR_RETURN(WRITE_L3_DEFIP_KEY_SEL_0r(unit, defip_key_sel_0));
   3650     BCM_IF_ERROR_RETURN(WRITE_L3_DEFIP_KEY_SEL_1r(unit, defip_key_sel_1));
   3651 
   3652     return BCM_E_NONE;
   3653 }
   3654 /*
   3655  * Function:
   3656  *      _bcm_hx4_l3_defip_urpf_enable
   3657  * Purpose:
   3658  *      Configure HX4 internal route table for URPF mode
   3659  * Parameters:
   3660  *      unit     - (IN)SOC unit number.
   3661  *      enable   - (IN)Enable/disable URPF.
   3662  * Returns:
   3663  *      BCM_E_XXX
   3664  */
   3665 STATIC int
   3666 _bcm_hx4_l3_defip_urpf_enable(int unit, int enable)
   3667 {
   3668     int defip_config;
   3669     int ipv6_64_depth = 0;
   3670     int ipv6_128_depth = 0;
   3671     int ipv6_128_dip_offset = 0;
   3672     uint32 defip_key_sel_0 = 0;
   3673     uint32 defip_key_sel_1 = 0;
   3674     uint32 num_ipv6_128b_entries = 0;
   3675     int    tcam_pair_count = 0;
   3676     uint32 tcam_depth = SOC_L3_DEFIP_TCAM_DEPTH_GET(unit);
   3677     int    tcam_idx = 0;
   3678     int start_index = 0;
   3679 
   3680     defip_config = soc_property_get(unit, spn_IPV6_LPM_128B_ENABLE, 1);
   3681     num_ipv6_128b_entries =  SOC_L3_DEFIP_MAX_128B_ENTRIES(unit);
   3682 
   3683     if (num_ipv6_128b_entries) {
   3684         tcam_pair_count = (num_ipv6_128b_entries / tcam_depth) +
   3685                           ((num_ipv6_128b_entries % tcam_depth) ? 1 : 0);
   3686     } else {
   3687         tcam_pair_count = 0;
   3688     }
   3689 
   3690     if (tcam_pair_count > (SOC_CONTROL(unit)->l3_defip_max_tcams / 2)) {
   3691         tcam_pair_count = (SOC_CONTROL(unit)->l3_defip_max_tcams / 2);
   3692     }
   3693 
   3694     if (enable) {
   3695 
   3696         /* Ranger device does not support URPF */
   3697         defip_key_sel_1 = 0xF0;
   3698         if (SOC_CONTROL(unit)->l3_defip_max_tcams == 4) {
   3699             defip_key_sel_1 = 0xC;
   3700         }
   3701 
   3702         if (defip_config) {
   3703             switch (tcam_pair_count) {
   3704                 case 0:
   3705                     ipv6_64_depth = 4 * tcam_depth;
   3706                     start_index = 0;
   3707                 break;
   3708 
   3709                 case 1:
   3710                 case 2:
   3711                    defip_key_sel_0 = 0x5; /* 0x0101 */
   3712 
   3713                    if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3714                        ipv6_64_depth = 2 * tcam_depth;
   3715                        start_index = 2 * tcam_depth;
   3716 
   3717                        if (SOC_CONTROL(unit)->l3_defip_max_tcams == 4) {
   3718                            defip_key_sel_0 = 0x3;
   3719                        }
   3720                    }
   3721                    break;
   3722 
   3723                 case 3:
   3724                 case 4:
   3725                 default:
   3726                    defip_key_sel_0 = 0xF; /* 0x1111 */
   3727 
   3728                    if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3729                        ipv6_64_depth = 0;
   3730                        start_index = 4 * tcam_depth;
   3731                    }
   3732                    break;
   3733             }
   3734 
   3735             if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3736                 ipv6_64_depth       = soc_mem_index_count(unit, L3_DEFIPm) / 2;
   3737                 ipv6_128_dip_offset = num_ipv6_128b_entries / 2;
   3738                 ipv6_128_depth      = num_ipv6_128b_entries / 2;
   3739             }
   3740         } else {
   3741             ipv6_64_depth       = soc_mem_index_count(unit, L3_DEFIPm) / 2;
   3742             ipv6_128_dip_offset = 0;
   3743             ipv6_128_depth      = 0;
   3744         }
   3745     } else { /* Disable uRPF */
   3746         if (defip_config) {
   3747             for (tcam_idx = 0; tcam_idx < tcam_pair_count; tcam_idx++) {
   3748                 defip_key_sel_0 |= (0x01 << tcam_idx);
   3749             }
   3750 
   3751             ipv6_64_depth       = soc_mem_index_count(unit, L3_DEFIPm);
   3752             ipv6_128_dip_offset = num_ipv6_128b_entries;
   3753             ipv6_128_depth      = num_ipv6_128b_entries;
   3754             if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3755                 ipv6_64_depth -= (tcam_pair_count * tcam_depth * 2);
   3756                 start_index = (tcam_pair_count * tcam_depth * 2);
   3757             }
   3758         } else {
   3759             ipv6_64_depth       = soc_mem_index_count(unit, L3_DEFIPm);
   3760             ipv6_128_dip_offset = 0;
   3761             ipv6_128_depth      = 0;
   3762         }
   3763 
   3764     }
   3765 
   3766     SOC_LPM_STATE_FENT(unit, (MAX_PFX_INDEX(unit)))  = ipv6_64_depth;
   3767     
   3768     if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3769         BCM_DEFIP_PAIR128_URPF_OFFSET(unit)    = ipv6_128_dip_offset;
   3770         BCM_DEFIP_PAIR128_IDX_MAX(unit)        = ipv6_128_depth - 1;
   3771         BCM_DEFIP_PAIR128_TOTAL(unit)          = ipv6_128_depth;
   3772     }
   3773 
   3774     SOC_LPM_STATE_START(unit, (MAX_PFX_INDEX(unit))) = start_index;
   3775     SOC_LPM_STATE_END(unit, (MAX_PFX_INDEX(unit)))   = start_index-1;
   3776     BCM_IF_ERROR_RETURN(soc_fb_lpm_state_config(unit, ipv6_64_depth, 
   3777                 start_index));
   3778 
   3779     BCM_IF_ERROR_RETURN(WRITE_L3_DEFIP_KEY_SEL_0r(unit, defip_key_sel_0));
   3780     BCM_IF_ERROR_RETURN(WRITE_L3_DEFIP_KEY_SEL_1r(unit, defip_key_sel_1));
   3781 
   3782     return BCM_E_NONE;
   3783 }
   3784 
   3785 /*
   3786  * Function:
   3787  *      _bcm_l3_expanded_defip_urpf_enable
   3788  * Purpose:
   3789  *      Configure HX4 internal route table for URPF mode
   3790  * Parameters:
   3791  *      unit     - (IN)SOC unit number.
   3792  *      enable   - (IN)Enable/disable URPF.
   3793  * Returns:
   3794  *      BCM_E_XXX
   3795  */
   3796 STATIC int
   3797 _bcm_l3_expanded_defip_urpf_enable(int unit, int enable)
   3798 {
   3799     if (soc_feature(unit, soc_feature_l3_32k_defip_table)) {
   3800         /* Firescout family - 16 tcams */
   3801         return _bcm_fs_l3_defip_urpf_enable(unit, enable);
   3802     } else {
   3803         /* Helix4 family - 8 tcams */
   3804         return _bcm_hx4_l3_defip_urpf_enable(unit, enable);
   3805     }
   3806 }
   3807 
   3808 /*
   3809  * Function:
   3810  *      _bcm_tr3_l3_defip_urpf_enable
   3811  * Purpose:
   3812  *      Configure TR3 internal route table for URPF mode
   3813  * Parameters:
   3814  *      unit     - (IN)SOC unit number.
   3815  *      enable   - (IN)Enable/disable URPF.
   3816  * Returns:
   3817  *      BCM_E_XXX
   3818  */
   3819 int
   3820 _bcm_tr3_l3_defip_urpf_enable(int unit, int enable)
   3821 {
   3822     int defip_config;
   3823     uint32 defip_key_sel_val = 0;
   3824     int ipv6_64_depth = 0;
   3825     int ipv6_128_dip_offset = 0, ipv6_128_depth = 0;
   3826     int num_ipv6_128b_entries;
   3827     int tcam_pair_count = 0;
   3828     int tcam_depth = SOC_L3_DEFIP_TCAM_DEPTH_GET(unit);
   3829     int start_index = 0;
   3830 
   3831     if (soc_feature(unit, soc_feature_l3_expanded_defip_table)) {/* HX4 */
   3832         return _bcm_l3_expanded_defip_urpf_enable(unit, enable);
   3833     }
   3834 
   3835     defip_config = soc_property_get(unit, spn_IPV6_LPM_128B_ENABLE, 1);
   3836     num_ipv6_128b_entries =  SOC_L3_DEFIP_MAX_128B_ENTRIES(unit);
   3837 
   3838     if (num_ipv6_128b_entries) {
   3839         tcam_pair_count = (num_ipv6_128b_entries / tcam_depth) +
   3840                           ((num_ipv6_128b_entries % tcam_depth) ? 1 : 0);
   3841     } else {
   3842         tcam_pair_count = 0;
   3843     }
   3844     
   3845     if (enable) { 
   3846         if (soc_feature(unit, soc_feature_l3_reduced_defip_table)) {/*Apollo2*/
   3847             soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 
   3848                               URPF_LOOKUP_CAM3f, 0x1);
   3849             soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 
   3850                               URPF_LOOKUP_CAM4f, 0x1);
   3851             soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 
   3852                               URPF_LOOKUP_CAM5f, 0x1);
   3853 
   3854             if (defip_config) {
   3855                 switch (tcam_pair_count) {
   3856                     case 0:
   3857                         ipv6_64_depth       = 3 * _BCM_TR3_DEFIP_TCAM_DEPTH;
   3858                         ipv6_128_depth      = 0;
   3859                         ipv6_128_dip_offset = 0;
   3860                     break;
   3861 
   3862                     default:
   3863                         soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 
   3864                                                 V6_KEY_SEL_CAM0_1f, 0x1);
   3865                         soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 
   3866                                                V6_KEY_SEL_CAM4_5f, 0x1);
   3867                         ipv6_128_dip_offset = num_ipv6_128b_entries / 2;
   3868                         ipv6_128_depth      = num_ipv6_128b_entries / 2;
   3869                         ipv6_64_depth       = soc_mem_index_count(unit, L3_DEFIPm) / 2;
   3870                     break;
   3871                 }
   3872             } else {
   3873                 ipv6_64_depth       = 3 * _BCM_TR3_DEFIP_TCAM_DEPTH;
   3874                 ipv6_128_dip_offset = 0;
   3875                 ipv6_128_depth      = 0;
   3876             }        
   3877         } else { /* TR3 */
   3878             /* All CAMs in URPF mode */
   3879             soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 
   3880                               URPF_LOOKUP_CAM4f, 0x1);
   3881             soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 
   3882                               URPF_LOOKUP_CAM5f, 0x1);
   3883             soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 
   3884                               URPF_LOOKUP_CAM6f, 0x1);
   3885             soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 
   3886                               URPF_LOOKUP_CAM7f, 0x1);
   3887     
   3888             switch (tcam_pair_count) {
   3889                 case 0:
   3890                     /* No pairing of tcams */
   3891                     ipv6_64_depth = 4 * tcam_depth;
   3892                     break;
   3893     
   3894               case 1:
   3895                 case 2:
   3896                 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 
   3897                                        V6_KEY_SEL_CAM0_1f, 0x1);
   3898                 soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 
   3899                                        V6_KEY_SEL_CAM4_5f, 0x1);
   3900                 if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3901                     ipv6_64_depth = 2 * tcam_depth;
   3902                     start_index = 2 * tcam_depth;
   3903                 }
   3904                 break;
   3905 
   3906               case 3:
   3907               case 4:
   3908               default: 
   3909                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   3910                                       &defip_key_sel_val, V6_KEY_SEL_CAM0_1f, 
   3911                                       0x1);
   3912                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   3913                                       &defip_key_sel_val, V6_KEY_SEL_CAM2_3f, 
   3914                                       0x1);
   3915                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   3916                                       &defip_key_sel_val, V6_KEY_SEL_CAM4_5f, 
   3917                                       0x1);
   3918                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   3919                                       &defip_key_sel_val, V6_KEY_SEL_CAM6_7f, 
   3920                                       0x1);
   3921                     if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3922                         ipv6_64_depth = 0;
   3923                         start_index = 4 * tcam_depth;
   3924                     }
   3925 
   3926                 break;
   3927             }
   3928 
   3929             if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   3930                 ipv6_128_dip_offset = num_ipv6_128b_entries / 2;
   3931                 ipv6_128_depth      = num_ipv6_128b_entries / 2;
   3932                 ipv6_64_depth =  soc_mem_index_count(unit, L3_DEFIPm) / 2;
   3933             }
   3934         }
   3935     } else { /* Disable urpf */
   3936         defip_key_sel_val = 0; /* reset */
   3937         if (soc_feature(unit, soc_feature_l3_reduced_defip_table)) {/*Apollo2*/
   3938             if (defip_config) {
   3939                 switch (tcam_pair_count) {
   3940                   case 0:
   3941                   break;   
   3942 
   3943                   case 1:
   3944                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 
   3945                                            V6_KEY_SEL_CAM0_1f, 0x1);
   3946                   break;   
   3947 
   3948                   case 2:
   3949 
   3950                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 
   3951                                            V6_KEY_SEL_CAM0_1f, 0x1);
   3952                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 
   3953                                            V6_KEY_SEL_CAM2_3f, 0x1);
   3954                   break;
   3955 
   3956                   case 3:
   3957                   default:
   3958                      soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 
   3959                                             V6_KEY_SEL_CAM0_1f, 0x1);
   3960                      soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 
   3961                                             V6_KEY_SEL_CAM2_3f, 0x1);
   3962                      soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, &defip_key_sel_val, 
   3963                                             V6_KEY_SEL_CAM4_5f, 0x1);
   3964                 }
   3965                 ipv6_64_depth       = soc_mem_index_count(unit, L3_DEFIPm);
   3966                 ipv6_128_dip_offset = 0;
   3967                 ipv6_128_depth      = num_ipv6_128b_entries;
   3968             } else {
   3969                 ipv6_64_depth       = 6 * _BCM_TR3_DEFIP_TCAM_DEPTH;
   3970                 ipv6_128_dip_offset = 0;
   3971                 ipv6_128_depth      = 0;
   3972             }
   3973         } else {
   3974             switch (tcam_pair_count) {
   3975                 case 1:
   3976                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   3977                                       &defip_key_sel_val, V6_KEY_SEL_CAM0_1f, 
   3978                                       0x1);
   3979                 break;
   3980 
   3981                 case 2:
   3982                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   3983                                       &defip_key_sel_val, V6_KEY_SEL_CAM0_1f, 
   3984                                       0x1);
   3985                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   3986                                       &defip_key_sel_val, V6_KEY_SEL_CAM2_3f, 
   3987                                       0x1);
   3988                 break;
   3989 
   3990                 case 3:
   3991                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   3992                                       &defip_key_sel_val, V6_KEY_SEL_CAM0_1f, 
   3993                                       0x1);
   3994                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   3995                                       &defip_key_sel_val, V6_KEY_SEL_CAM2_3f, 
   3996                                       0x1);
   3997                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   3998                                       &defip_key_sel_val, V6_KEY_SEL_CAM4_5f, 
   3999                                       0x1);
   4000                 break;
   4001 
   4002                 case 4:
   4003                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   4004                                       &defip_key_sel_val, V6_KEY_SEL_CAM0_1f, 
   4005                                       0x1);
   4006                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   4007                                       &defip_key_sel_val, V6_KEY_SEL_CAM2_3f, 
   4008                                       0x1);
   4009                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   4010                                       &defip_key_sel_val, V6_KEY_SEL_CAM4_5f, 
   4011                                       0x1);
   4012                     soc_reg_field_set(unit, L3_DEFIP_KEY_SELr, 
   4013                                       &defip_key_sel_val, V6_KEY_SEL_CAM6_7f, 
   4014                                       0x1);
   4015                 break;   
   4016 
   4017                 default:
   4018                     break;
   4019     }
   4020     
   4021             ipv6_64_depth =  soc_mem_index_count(unit, L3_DEFIPm);
   4022             ipv6_128_dip_offset = 0;
   4023             ipv6_128_depth      = num_ipv6_128b_entries;
   4024             if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   4025                 ipv6_64_depth -= (tcam_pair_count * tcam_depth * 2);
   4026                 start_index = (tcam_pair_count * tcam_depth * 2);
   4027             }
   4028         }
   4029     }
   4030 
   4031     if (!soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   4032         if (BCM_DEFIP_PAIR128_INIT_CHECK(unit)) {
   4033             BCM_DEFIP_PAIR128_URPF_OFFSET(unit)    = ipv6_128_dip_offset;
   4034             BCM_DEFIP_PAIR128_IDX_MAX(unit)        = ipv6_128_depth - 1;
   4035             BCM_DEFIP_PAIR128_TOTAL(unit)          = ipv6_128_depth;
   4036         }
   4037     }
   4038 
   4039     if (SOC_LPM_INIT_CHECK(unit)) {
   4040         SOC_LPM_STATE_FENT(unit, (MAX_PFX_INDEX(unit)))  = ipv6_64_depth;
   4041         SOC_LPM_STATE_START(unit, MAX_PFX_INDEX(unit)) = start_index;
   4042         SOC_LPM_STATE_END(unit, MAX_PFX_INDEX(unit))   = start_index - 1;
   4043         BCM_IF_ERROR_RETURN(soc_fb_lpm_state_config(unit, ipv6_64_depth,
   4044                     start_index));
   4045     }
   4046 
   4047     BCM_IF_ERROR_RETURN(WRITE_L3_DEFIP_KEY_SELr(unit, defip_key_sel_val));
   4048     SOC_IF_ERROR_RETURN(soc_fb_lpm_stat_init(unit));
   4049     if (soc_feature(unit, soc_feature_l3_lpm_scaling_enable)) {
   4050         SOC_IF_ERROR_RETURN(soc_fb_lpm128_stat_init(unit));
   4051     }
   4052     return BCM_E_NONE;
   4053 }
   4054 
   4055 /*
   4056  * Function:
   4057  *      _bcm_tr3_mtu_profile_index_get
   4058  * Purpose:
   4059  *      Get TR3 L3 interface MTU profile table index
   4060  *      given the MTU value to set.
   4061  * Parameters:
   4062  *      unit      - (IN)SOC unit number.
   4063  *      mtu       - (IN)MTU value to set.
   4064  *      index     - (OUT)MTU profile index.
   4065  * Returns:
   4066  *      BCM_E_XXX
   4067  */
   4068 int 
   4069 _bcm_tr3_mtu_profile_index_get(int unit, uint32 mtu, uint32 *index) 
   4070 {
   4071     ing_l3_next_hop_attribute_1_entry_t mtu_value_buf;
   4072     uint32  *mtu_value_buf_p; /* Attribute table buff address */
   4073     void *null_entry = soc_mem_entry_null(unit, ING_L3_NEXT_HOP_ATTRIBUTE_1m);
   4074     void *entries[1];
   4075 
   4076     if (NULL == index) {
   4077         return BCM_E_PARAM;
   4078     }
   4079 
   4080     /* Reset the buffer to default value. */
   4081     mtu_value_buf_p = (uint32 *)&mtu_value_buf;
   4082     sal_memcpy(mtu_value_buf_p, null_entry,
   4083                sizeof(ing_l3_next_hop_attribute_1_entry_t));
   4084 
   4085     soc_mem_field32_set(unit, ING_L3_NEXT_HOP_ATTRIBUTE_1m,
   4086                         mtu_value_buf_p, MTU_SIZEf, mtu);
   4087 
   4088     entries[0] = mtu_value_buf_p;
   4089     BCM_IF_ERROR_RETURN(_bcm_ing_l3_nh_attrib_entry_add(unit, entries, 1, 
   4090                                              (uint32 *)index));
   4091     return BCM_E_NONE;
   4092 } 
   4093 
   4094 /*
   4095  * Function:
   4096  *      _bcm_tr3_l3_intf_mtu_get
   4097  * Purpose:
   4098  *      Get TR3 L3 interface MTU value. 
   4099  * Parameters:
   4100  *      unit      - (IN)SOC unit number.
   4101  *      intf_info - (IN)Interface information.
   4102  * Returns:
   4103  *      BCM_E_XXX
   4104  */
   4105 int
   4106 _bcm_tr3_l3_intf_mtu_get(int unit, _bcm_l3_intf_cfg_t *intf_info)
   4107 {
   4108     /* Buffer for mtu idx */
   4109     ing_l3_next_hop_attribute_1_index_entry_t mtu_idx_value_buf;  
   4110     /* Buffer for mtu profile table entry */
   4111     ing_l3_next_hop_attribute_1_entry_t mtu_value_buf;  
   4112     uint32  *mtu_idx_value_buf_p;          /* Write buffer address */
   4113     uint32  *mtu_value_buf_p;          /* Write buffer address */
   4114     int  mtu_index, mtu_profile_index;
   4115     int  interface_map_mode = 0;
   4116 
   4117     /* Input parameters check */
   4118     if (NULL == intf_info) {
   4119         return (BCM_E_PARAM);
   4120     }
   4121 
   4122     /* Zero the buffer. */
   4123     mtu_idx_value_buf_p = (uint32 *)&mtu_idx_value_buf;
   4124     sal_memset(mtu_idx_value_buf_p, 0, sizeof(ing_l3_next_hop_attribute_1_index_entry_t));
   4125 
   4126     mtu_value_buf_p = (uint32 *)&mtu_value_buf;
   4127     sal_memset(mtu_value_buf_p, 0, sizeof(ing_l3_next_hop_attribute_1_entry_t));
   4128 
   4129     if (!BCM_XGS3_L3_INTF_VLAN_SPLIT_EGRESS_MODE_ISSET(unit)) {
   4130         if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
   4131             BCM_IF_ERROR_RETURN(
   4132                 bcm_xgs3_l3_ingress_intf_map_get(unit, &interface_map_mode));
   4133         }
   4134         if (!interface_map_mode) {
   4135             mtu_index = intf_info->l3i_vid;
   4136         } else {
   4137             mtu_index = intf_info->l3i_index;
   4138         }
   4139         BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, 
   4140                                               ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm,
   4141                                               mtu_index, mtu_idx_value_buf_p));
   4142     } else {
   4143     /* Read mtu table entry by index. */
   4144         BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, 
   4145                                               ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm,
   4146                                               intf_info->l3i_index, 
   4147                                               mtu_idx_value_buf_p));
   4148     }
   4149     mtu_profile_index = 
   4150         soc_mem_field32_get(unit, ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm,
   4151                             mtu_idx_value_buf_p, INDEXf);
   4152 
   4153     BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, ING_L3_NEXT_HOP_ATTRIBUTE_1m,
   4154                                           mtu_profile_index, mtu_value_buf_p));
   4155     intf_info->l3i_mtu = 
   4156         soc_mem_field32_get(unit, ING_L3_NEXT_HOP_ATTRIBUTE_1m,
   4157                             mtu_value_buf_p, MTU_SIZEf);
   4158 
   4159     return BCM_E_NONE;
   4160 }
   4161 
   4162 /*
   4163  * Function:
   4164  *      _bcm_tr3_l3_intf_mtu_set
   4165  * Purpose:
   4166  *      Set TR3 L3 interface MTU value. 
   4167  * Parameters:
   4168  *      unit      - (IN)SOC unit number.
   4169  *      intf_info - (IN)Interface information.
   4170  * Returns:
   4171  *      BCM_E_XXX
   4172  */
   4173 int
   4174 _bcm_tr3_l3_intf_mtu_set(int unit, _bcm_l3_intf_cfg_t *intf_info)
   4175 {
   4176     /* Buffer for mtu idx */
   4177     ing_l3_next_hop_attribute_1_index_entry_t mtu_idx_value_buf; 
   4178     void *null_idx_entry =
   4179                  soc_mem_entry_null(unit, ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm);
   4180     int  mtu_index, mtu_profile_index, interface_map_mode = 0;
   4181     uint32 mtu = _BCM_TR3_L3_DEFAULT_MTU_SIZE; /* Default mtu size */
   4182 
   4183     /* Input parameters check */
   4184     if (NULL == intf_info) {
   4185         return (BCM_E_PARAM);
   4186     }
   4187 
   4188     /* coverity[dead_error_begin : FALSE] */
   4189     if(!SOC_MEM_FIELD32_VALUE_FIT(unit, ING_L3_NEXT_HOP_ATTRIBUTE_1m, 
   4190                                   MTU_SIZEf, intf_info->l3i_mtu)) {
   4191         return (BCM_E_PARAM);
   4192     }
   4193 
   4194     /* Set mtu. */
   4195     if (intf_info->l3i_mtu) {
   4196         mtu = intf_info->l3i_mtu;
   4197     }
   4198     
   4199     /* Get mtu profile table index for the mtu */
   4200     BCM_IF_ERROR_RETURN(
   4201      _bcm_tr3_mtu_profile_index_get(unit, mtu,
   4202                                     (uint32 *)&mtu_profile_index));
   4203 
   4204     sal_memcpy(&mtu_idx_value_buf, null_idx_entry,
   4205                sizeof(ing_l3_next_hop_attribute_1_index_entry_t));
   4206     soc_mem_field32_set(unit, ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm,
   4207                         &mtu_idx_value_buf, INDEXf, mtu_profile_index);
   4208     if (!BCM_XGS3_L3_INTF_VLAN_SPLIT_EGRESS_MODE_ISSET(unit)) {
   4209         if (soc_feature(unit, soc_feature_l3_ingress_interface)) {
   4210             BCM_IF_ERROR_RETURN(
   4211                 bcm_xgs3_l3_ingress_intf_map_get(unit, &interface_map_mode));
   4212         }
   4213         if (!interface_map_mode) {
   4214             mtu_index = intf_info->l3i_vid;
   4215         } else {
   4216             mtu_index = intf_info->l3i_index;
   4217         }
   4218         WRITE_ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm(unit, MEM_BLOCK_ALL,
   4219                                                  mtu_index, &mtu_idx_value_buf);
   4220     } else {
   4221         WRITE_ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm(unit, MEM_BLOCK_ALL,
   4222                                                  intf_info->l3i_index, 
   4223                                                  &mtu_idx_value_buf);
   4224     }
   4225     return BCM_E_NONE;
   4226 }
   4227 
   4228 /*
   4229  * Function:
   4230  *      _bcm_tr3_l3_ecmp_grp_get
   4231  * Purpose:
   4232  *      Get ecmp group next hop members by index.
   4233  * Parameters:
   4234  *      unit     - (IN) SOC unit number.
   4235  *      ecmp_grp - (IN) Ecmp group id to read. 
   4236  *      ecmp_count - (IN) Maximum number of entries to read.
   4237  *      nh_idx     - (OUT) Next hop indexes. 
   4238  * Returns:
   4239  *      BCM_E_XXX
   4240  */
   4241 int
   4242 _bcm_tr3_l3_ecmp_grp_get(int unit, int ecmp_grp, int ecmp_group_size, int *nh_idx)
   4243 {
   4244     int idx;
   4245     void *ecmp_null_entry;
   4246     void *ecmp_grp_null_entry;
   4247     ecmp_entry_t ecmp_entry;
   4248     ecmp_count_entry_t ecmp_grp_entry;
   4249     int ecmp_idx, num_ecmp_entries;
   4250 
   4251     /* Input parameters sanity check. */
   4252     if ((NULL == nh_idx) || (ecmp_group_size < 1)) {
   4253          return (BCM_E_PARAM);
   4254     }
   4255 
   4256     ecmp_grp_null_entry = soc_mem_entry_null(unit, L3_ECMP_COUNTm);
   4257     sal_memcpy(&ecmp_grp_entry, ecmp_grp_null_entry, sizeof(ecmp_count_entry_t));
   4258 
   4259     /* Read ECMP group table entry indexed by group ID */
   4260     BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMP_COUNTm,
   4261                         MEM_BLOCK_ANY, ecmp_grp, &ecmp_grp_entry));
   4262 
   4263     /* Base ptr & path count of the ECMP group in the ECMP entry table */
   4264     ecmp_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, BASE_PTRf);
   4265     num_ecmp_entries = soc_mem_field32_get(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, COUNTf);
   4266     num_ecmp_entries++; /* Count is zero based */ 
   4267 
   4268     sal_memset(nh_idx, 0, ecmp_group_size * sizeof(int));
   4269     ecmp_null_entry = soc_mem_entry_null(unit, L3_ECMPm);
   4270     sal_memcpy(&ecmp_entry, ecmp_null_entry, sizeof(ecmp_entry_t));
   4271 
   4272     /* Read the NH index of each member of the ECMP group */    
   4273     for (idx = 0; idx < num_ecmp_entries; idx++) {
   4274     
   4275         BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMPm,
   4276                             MEM_BLOCK_ANY, (ecmp_idx + idx), &ecmp_entry));
   4277         nh_idx[idx] = soc_mem_field32_get(unit, L3_ECMPm,
   4278                                           &ecmp_entry, NEXT_HOP_INDEXf);
   4279     }
   4280 
   4281     return BCM_E_NONE;
   4282 }
   4283 
   4284 /*
   4285  * Function:
   4286  *      _bcm_tr3_l3_ecmp_grp_add
   4287  * Purpose:
   4288  *      Add ecmp group next hop members, or reset ecmp group entry.  
   4289  *      NOTE: Function always writes all the entries in ecmp group.
   4290  *            If there is not enough nh indexes - next hops written
   4291  *            in cycle. 
   4292  * Parameters:
   4293  *      unit       - (IN)SOC unit number.
   4294  *      ecmp_grp   - (IN)ecmp group id to write.
   4295  *      buf        - (IN)Next hop indexes or NULL for entry reset.
   4296  *      info       - (IN)ECMP additional info
   4297  * Returns:
   4298  *      BCM_E_XXX
   4299  */
   4300 int
   4301 _bcm_tr3_l3_ecmp_grp_add(int unit, int ecmp_grp, void *buf, void *info)
   4302 {
   4303     uint32 reg_val, value;
   4304     _bcm_l3_tbl_op_t data;
   4305     int *nh_idx = NULL;
   4306     int nh_cycle_idx;
   4307     int idx, ecmp_idx, entry_type;
   4308     void *ecmp_null_entry, *initial_ecmp_null_entry;
   4309     void *ecmp_grp_null_entry, *initial_ecmp_grp_null_entry;
   4310     ecmp_entry_t ecmp_entry;
   4311     ing_l3_next_hop_entry_t ing_nh;
   4312     ecmp_count_entry_t ecmp_grp_entry;
   4313     initial_l3_ecmp_entry_t initial_ecmp_entry;
   4314     initial_l3_ecmp_group_entry_t initial_ecmp_grp_entry;
   4315     int l3_ecmp_oif_flds[8] = {  L3_OIF_0f, L3_OIF_1f, L3_OIF_2f, L3_OIF_3f, 
   4316                                  L3_OIF_4f, L3_OIF_5f, L3_OIF_6f, L3_OIF_7f }; 
   4317     int l3_ecmp_oif_type_flds[8] = {  L3_OIF_0_TYPEf, L3_OIF_1_TYPEf, 
   4318                              L3_OIF_2_TYPEf, L3_OIF_3_TYPEf, L3_OIF_4_TYPEf, 
   4319                              L3_OIF_5_TYPEf, L3_OIF_6_TYPEf, L3_OIF_7_TYPEf };
   4320     ecmp_count_entry_t old_ecmp_count_entry;
   4321     int dlb_id, group_enable;
   4322     int rv;
   4323     int ecmp_table_incr = 0;
   4324     _bcm_l3_ecmp_group_info_t *ecmp_info = info;
   4325     _bcm_l3_ecmp_group_buffer_t *ecmp_buffer = buf;
   4326 
   4327     if (NULL == ecmp_buffer || NULL == ecmp_info ||
   4328         NULL == ecmp_buffer->group_buffer) {
   4329         return (BCM_E_PARAM);
   4330     }
   4331 
   4332     nh_idx = ecmp_buffer->group_buffer;
   4333 
   4334     /* Null ECMP and ECMP group table entries */
   4335     ecmp_null_entry = soc_mem_entry_null(unit, L3_ECMPm);
   4336     ecmp_grp_null_entry = soc_mem_entry_null(unit, L3_ECMP_COUNTm);
   4337     initial_ecmp_null_entry = soc_mem_entry_null(unit, INITIAL_L3_ECMPm);
   4338     initial_ecmp_grp_null_entry = soc_mem_entry_null(unit, INITIAL_L3_ECMP_GROUPm);
   4339     sal_memcpy(&ecmp_grp_entry, ecmp_grp_null_entry, sizeof(ecmp_count_entry_t));
   4340     sal_memcpy(&initial_ecmp_grp_entry, initial_ecmp_grp_null_entry,
   4341                sizeof(initial_l3_ecmp_group_entry_t));
   4342 
   4343     if (BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit,
   4344                                 ecmp_grp), ecmp_grp)) {
   4345         /* Group has already exists, get base ptr from group table */ 
   4346         BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMP_COUNTm,
   4347                             MEM_BLOCK_ANY, ecmp_grp, &ecmp_grp_entry));
   4348         if (soc_feature(unit, soc_feature_l3_ecmp_1k_groups)) {
   4349             ecmp_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, BASE_PTRf);
   4350         } else {
   4351             ecmp_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, BASE_PTR_0f);
   4352         }
   4353     } else {  
   4354         /* Get index to the first slot in the ECMP table
   4355          * that can accomodate max_paths */
   4356         data.width = ecmp_info->max_paths;
   4357         data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 
   4358         data.oper_flags = _BCM_L3_SHR_TABLE_TRAVERSE_CONTROL; 
   4359         data.entry_index = -1;
   4360 
   4361         rv = _bcm_xgs3_tbl_free_idx_get(unit, &data);
   4362 
   4363         if (BCM_E_FULL == rv) {
   4364             /* Defragment ECMP table */
   4365             BCM_IF_ERROR_RETURN(bcm_tr2_l3_ecmp_defragment_no_lock(unit, 0));
   4366 
   4367             /* Attempt to get free index again */
   4368             BCM_IF_ERROR_RETURN (_bcm_xgs3_tbl_free_idx_get(unit, &data));
   4369 
   4370         } else if (BCM_FAILURE(rv)) {
   4371             return rv;
   4372         }
   4373 
   4374         ecmp_idx = data.entry_index;
   4375         BCM_XGS3_L3_ENT_REF_CNT_INC(data.tbl_ptr, ecmp_idx, ecmp_info->max_paths);
   4376         ecmp_table_incr = 1;
   4377     }
   4378 
   4379     sal_memcpy(&ecmp_grp_entry, ecmp_grp_null_entry, sizeof(ecmp_count_entry_t));
   4380 
   4381     for (idx = 0, nh_cycle_idx = 0; idx < ecmp_info->max_paths; idx++, nh_cycle_idx++) {
   4382         sal_memcpy(&ecmp_entry, ecmp_null_entry, sizeof(ecmp_entry_t));
   4383         sal_memcpy(&initial_ecmp_entry, initial_ecmp_null_entry,
   4384                    sizeof(initial_l3_ecmp_entry_t));
   4385 
   4386         /* If this is the last nhop then program black-hole. */
   4387         if ( (!idx) && (!nh_idx[nh_cycle_idx]) ) {
   4388               nh_cycle_idx = 0;
   4389         } else  if (!nh_idx[nh_cycle_idx]) {
   4390             break;
   4391         }
   4392 
   4393         /* Write NHs to ECMP entry table */
   4394         soc_mem_field32_set(unit, L3_ECMPm, &ecmp_entry, 
   4395                             NEXT_HOP_INDEXf, nh_idx[nh_cycle_idx]);
   4396         rv = soc_mem_write(unit, L3_ECMPm, MEM_BLOCK_ALL,
   4397                                          (ecmp_idx + idx), &ecmp_entry);
   4398         if (BCM_FAILURE(rv)) {
   4399             if (ecmp_table_incr == 1) {
   4400                 BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ecmp),
   4401                                             ecmp_idx, ecmp_info->max_paths);
   4402             }
   4403             return rv;
   4404         } 
   4405 
   4406         /* Write NHs to initial ECMP entry table */
   4407         soc_mem_field32_set(unit, INITIAL_L3_ECMPm, &initial_ecmp_entry, 
   4408                             NEXT_HOP_INDEXf, nh_idx[idx]);
   4409         rv = soc_mem_write(unit, INITIAL_L3_ECMPm, MEM_BLOCK_ALL,
   4410                                          (ecmp_idx + idx), &initial_ecmp_entry);
   4411         if (BCM_FAILURE(rv)) {
   4412             if (ecmp_table_incr == 1) {
   4413                 BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ecmp),
   4414                                             ecmp_idx, ecmp_info->max_paths);
   4415             }
   4416             return rv;
   4417         } 
   4418 
   4419         if (soc_feature(unit, soc_feature_urpf)) {
   4420             /* Check if URPF is enabled on device */
   4421             BCM_IF_ERROR_RETURN(
   4422                 READ_L3_DEFIP_RPF_CONTROLr(unit, &reg_val));
   4423             if (reg_val) {
   4424                 if (idx < 8) {
   4425                     BCM_IF_ERROR_RETURN (soc_mem_read(unit, 
   4426                          ING_L3_NEXT_HOPm, MEM_BLOCK_ANY, 
   4427                          nh_idx[idx], &ing_nh));
   4428 
   4429                     entry_type = 
   4430                       soc_ING_L3_NEXT_HOPm_field32_get(unit, 
   4431                            &ing_nh, ENTRY_TYPEf);
   4432 
   4433                     if (entry_type == 0x0) {
   4434                         /* 
   4435                          * if l3_oif is valid then read it than vlan.
   4436                          * vlan and l3_oifs are overlaid fields.
   4437                          */
   4438                         if (SOC_MEM_FIELD_VALID(unit, ING_L3_NEXT_HOPm,
   4439                                                 L3_OIFf)) {
   4440                             value = soc_ING_L3_NEXT_HOPm_field32_get(
   4441                                         unit, &ing_nh, L3_OIFf);
   4442                         } else {
   4443                             value = soc_ING_L3_NEXT_HOPm_field32_get(
   4444                                         unit, &ing_nh, VLAN_IDf);
   4445                         }
   4446 
   4447                         soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, 
   4448                                        l3_ecmp_oif_type_flds[idx], entry_type);
   4449                         soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, 
   4450                                             l3_ecmp_oif_flds[idx], value);
   4451                     } else if (entry_type == 0x1) {
   4452                         value  = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, L3_OIFf);
   4453                         soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, 
   4454                                        l3_ecmp_oif_type_flds[idx], entry_type);
   4455                         soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, 
   4456                                        l3_ecmp_oif_flds[idx], value);
   4457                     }
   4458                     soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, URPF_COUNTf, idx);
   4459                 }else {
   4460                     /* Inorder to avoid TRAP_TO_CPU, urpf_mode on L3_IIF/PORT must be set 
   4461                        to STRICT_MODE / LOOSE_MODE */
   4462                     soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, ECMP_GT8f , 1);
   4463                 }
   4464             }
   4465         }
   4466     }
   4467 
   4468     /* Write ECMP group count and base index to group table entry 
   4469      * indexed by group index */
   4470     if (!idx) {
   4471         soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, COUNTf, idx);
   4472         soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm,
   4473                             &initial_ecmp_grp_entry, COUNTf, idx);
   4474     } else {
   4475         soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, COUNTf, idx-1);
   4476         soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm,
   4477                             &initial_ecmp_grp_entry, COUNTf, idx-1);
   4478     }
   4479     soc_mem_field32_set(unit, L3_ECMP_COUNTm,
   4480                         &ecmp_grp_entry, BASE_PTRf, ecmp_idx);
   4481     soc_mem_field32_set(unit, INITIAL_L3_ECMP_GROUPm,
   4482                         &initial_ecmp_grp_entry, BASE_PTRf, ecmp_idx);
   4483 
   4484     if (soc_feature(unit, soc_feature_ecmp_dlb)) {
   4485         /* Preserve the old values of ECMP DLB related fields */
   4486         BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMP_COUNTm, MEM_BLOCK_ANY,
   4487                     ecmp_grp, &old_ecmp_count_entry));
   4488         dlb_id = soc_mem_field32_get(unit, L3_ECMP_COUNTm, &old_ecmp_count_entry,
   4489                 DLB_IDf);
   4490         group_enable = soc_mem_field32_get(unit, L3_ECMP_COUNTm,
   4491                 &old_ecmp_count_entry, GROUP_ENABLEf);
   4492         soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, DLB_IDf,
   4493                 dlb_id);
   4494         soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, GROUP_ENABLEf,
   4495                 group_enable);
   4496     }
   4497 
   4498     rv = soc_mem_write(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL,
   4499                   ecmp_grp, &ecmp_grp_entry);
   4500     if (BCM_FAILURE(rv)) {
   4501         if (ecmp_table_incr == 1) {
   4502             BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ecmp),
   4503                                         ecmp_idx, ecmp_info->max_paths);
   4504         }
   4505         return rv;
   4506     }
   4507 
   4508     rv = soc_mem_write(unit, INITIAL_L3_ECMP_GROUPm, MEM_BLOCK_ALL,
   4509                   ecmp_grp, &initial_ecmp_grp_entry);
   4510 
   4511     if (BCM_FAILURE(rv)) {
   4512         if (ecmp_table_incr == 1) {
   4513             BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ecmp),
   4514                                         ecmp_idx, ecmp_info->max_paths);
   4515         }
   4516         return rv;
   4517     }
   4518 
   4519     /* Save the max possible paths for this ECMP group in s/w */ 
   4520     BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[ecmp_grp] = ecmp_info->max_paths;
   4521 
   4522     return BCM_E_NONE;
   4523 }
   4524 
   4525 /*
   4526  * Function:
   4527  *      _bcm_tr3_l3_ecmp_grp_del
   4528  * Purpose:
   4529  *      Reset ecmp group next hop members
   4530  * Parameters:
   4531  *      unit       - (IN)SOC unit number.
   4532  *      ecmp_grp   - (IN)ecmp group id to write.
   4533  *      info       - (IN)ECMP additional info
   4534  * Returns:
   4535  *      BCM_E_XXX
   4536  */
   4537 int
   4538 _bcm_tr3_l3_ecmp_grp_del(int unit, int ecmp_grp, void *info)
   4539 {
   4540     int idx, ecmp_idx;
   4541     _bcm_l3_tbl_op_t data;
   4542     void *ecmp_null_entry, *initial_ecmp_null_entry;
   4543     void *ecmp_grp_null_entry, *initial_ecmp_grp_null_entry;
   4544     ecmp_entry_t ecmp_entry;
   4545     ecmp_count_entry_t ecmp_grp_entry;
   4546     initial_l3_ecmp_entry_t initial_ecmp_entry;
   4547     initial_l3_ecmp_group_entry_t initial_ecmp_grp_entry;
   4548     ecmp_count_entry_t old_ecmp_count_entry;
   4549     int dlb_id, group_enable;
   4550 
   4551     if (NULL == info) {
   4552         return BCM_E_INTERNAL;
   4553     }
   4554 
   4555     /* Null ECMP and ECMP group table entries */
   4556     ecmp_null_entry = soc_mem_entry_null(unit, L3_ECMPm);
   4557     ecmp_grp_null_entry = soc_mem_entry_null(unit, L3_ECMP_COUNTm);
   4558     initial_ecmp_null_entry = soc_mem_entry_null(unit, INITIAL_L3_ECMPm);
   4559     initial_ecmp_grp_null_entry = soc_mem_entry_null(unit, INITIAL_L3_ECMP_GROUPm);
   4560     sal_memcpy(&ecmp_entry, ecmp_null_entry, sizeof(ecmp_entry_t));
   4561     sal_memcpy(&ecmp_grp_entry, ecmp_grp_null_entry, sizeof(ecmp_count_entry_t));
   4562     sal_memcpy(&initial_ecmp_entry, initial_ecmp_null_entry,
   4563                sizeof(initial_l3_ecmp_entry_t));
   4564     sal_memcpy(&initial_ecmp_grp_entry, initial_ecmp_grp_null_entry,
   4565                sizeof(initial_l3_ecmp_group_entry_t));
   4566 
   4567     /* Get the base entry index of the group */
   4568     BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMP_COUNTm,
   4569                                      MEM_BLOCK_ANY, ecmp_grp, &ecmp_grp_entry));
   4570     ecmp_idx = soc_mem_field32_get(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, BASE_PTRf);
   4571 
   4572     /* Write null entries in the ECMP entry tables per group member
   4573      * starting from the base group entry */
   4574     for (idx = 0; idx < ((_bcm_l3_ecmp_group_info_t*)info)->max_paths; idx++) {
   4575          /* ECMP entry table */
   4576          BCM_IF_ERROR_RETURN(soc_mem_write(unit, L3_ECMPm, MEM_BLOCK_ALL, 
   4577                                           (ecmp_idx + idx), &ecmp_entry));
   4578          /* Initial ECMP entry table */
   4579          BCM_IF_ERROR_RETURN(soc_mem_write(unit, INITIAL_L3_ECMPm, MEM_BLOCK_ALL, 
   4580                                           (ecmp_idx + idx), &initial_ecmp_entry));
   4581     }
   4582 
   4583     /* Decrement ref count for the entries in ecmp table
   4584      * Ref count for ecmp_group table is decremented in common table del func. */
   4585     data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 
   4586     BCM_XGS3_L3_ENT_REF_CNT_DEC(data.tbl_ptr, ecmp_idx,
   4587                                 ((_bcm_l3_ecmp_group_info_t*)info)->max_paths);
   4588 
   4589     /* Reset group entry */
   4590     sal_memcpy(&ecmp_grp_entry, ecmp_grp_null_entry, sizeof(ecmp_count_entry_t));
   4591 
   4592     if (soc_feature(unit, soc_feature_ecmp_dlb)) {
   4593         /* Preserve the old values of ECMP DLB related fields */
   4594         BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_ECMP_COUNTm, MEM_BLOCK_ANY,
   4595                     ecmp_grp, &old_ecmp_count_entry));
   4596         dlb_id = soc_mem_field32_get(unit, L3_ECMP_COUNTm, &old_ecmp_count_entry,
   4597                 DLB_IDf);
   4598         group_enable = soc_mem_field32_get(unit, L3_ECMP_COUNTm,
   4599                 &old_ecmp_count_entry, GROUP_ENABLEf);
   4600         soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, DLB_IDf,
   4601                 dlb_id);
   4602         soc_mem_field32_set(unit, L3_ECMP_COUNTm, &ecmp_grp_entry, GROUP_ENABLEf,
   4603                 group_enable);
   4604     }
   4605 
   4606     /* Write null entries in the ECMP group tables indexed by group id */
   4607     BCM_IF_ERROR_RETURN(soc_mem_write(unit, L3_ECMP_COUNTm, MEM_BLOCK_ALL,
   4608                                       ecmp_grp, &ecmp_grp_entry));
   4609     BCM_IF_ERROR_RETURN(soc_mem_write(unit, INITIAL_L3_ECMP_GROUPm, MEM_BLOCK_ALL,
   4610                                       ecmp_grp, &initial_ecmp_grp_entry));
   4611 
   4612     /* Reset the max paths of the deleted group */
   4613     BCM_XGS3_L3_MAX_PATHS_PERGROUP_PTR(unit)[ecmp_grp] = 0;
   4614 
   4615     return BCM_E_NONE;
   4616 }
   4617 
   4618 /*
   4619  * Function:
   4620  *      _bcm_tr3_l3_tnl_term_add
   4621  * Purpose:
   4622  *      Add tunnel termination entry to the hw.
   4623  * Parameters:
   4624  *      unit     - (IN) BCM device number. 
   4625  *      tnl_info - (IN) Tunnel terminator parameters.
   4626  * Returns:
   4627  *      BCM_E_XXX
   4628  */
   4629 int
   4630 _bcm_tr3_l3_tnl_term_add(int unit, uint32 *entry_ptr, bcm_tunnel_terminator_t *tnl_info)
   4631 {
   4632     bcm_module_t mod_in, mod_out, my_mod;
   4633     bcm_port_t port_in, port_out;
   4634     _bcm_l3_ingress_intf_t iif;
   4635     int tunnel, wlan;
   4636     int rv;
   4637 
   4638     /* Program remote port */
   4639     if ((tnl_info->type == bcmTunnelTypeWlanWtpToAc) || 
   4640         (tnl_info->type == bcmTunnelTypeWlanAcToAc) ||
   4641         (tnl_info->type == bcmTunnelTypeWlanWtpToAc6) ||
   4642         (tnl_info->type == bcmTunnelTypeWlanAcToAc6)) {
   4643         wlan = 1;
   4644     } else {
   4645         wlan = 0;
   4646     }
   4647     if (wlan) {
   4648         if (tnl_info->flags & BCM_TUNNEL_TERM_WLAN_REMOTE_TERMINATE) {
   4649             if (!BCM_GPORT_IS_MODPORT(tnl_info->remote_port)) {
   4650                 return BCM_E_PARAM;
   4651             }
   4652             mod_in = BCM_GPORT_MODPORT_MODID_GET(tnl_info->remote_port);
   4653             port_in = BCM_GPORT_MODPORT_PORT_GET(tnl_info->remote_port); 
   4654             BCM_IF_ERROR_RETURN
   4655                 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, mod_in, 
   4656                                         port_in, &mod_out, &port_out));
   4657             if (!SOC_MODID_ADDRESSABLE(unit, mod_out)) {
   4658                 return (BCM_E_BADID);
   4659             }
   4660             if (!SOC_PORT_ADDRESSABLE(unit, port_out)) {
   4661                 return (BCM_E_PORT);
   4662             }
   4663             soc_L3_TUNNELm_field32_set(unit, entry_ptr, REMOTE_TERM_GPPf,
   4664                                        (mod_out << 6) | port_out);
   4665         } else {
   4666             /* Send to the local loopback port */
   4667             rv = bcm_esw_stk_my_modid_get(unit, &my_mod);
   4668             BCM_IF_ERROR_RETURN(rv);
   4669             port_in = AXP_PORT(unit,SOC_AXP_NLF_WLAN_DECAP);
   4670             mod_in = my_mod;
   4671             rv = _bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, mod_in, 
   4672                                         port_in, &mod_out, &port_out);
   4673             BCM_IF_ERROR_RETURN(rv);
   4674 
   4675             soc_L3_TUNNELm_field32_set(unit, entry_ptr, REMOTE_TERM_GPPf,
   4676                                        (mod_out << 6) | port_out);
   4677             /* Locally Terminated */
   4678             soc_L3_TUNNELm_field32_set(unit, entry_ptr, 
   4679                                        LOCAL_TUNNEL_TERMINATIONf, 1 );
   4680         }
   4681         /* Program tunnel id */
   4682         if (tnl_info->flags & BCM_TUNNEL_TERM_TUNNEL_WITH_ID) {
   4683             if (!BCM_GPORT_IS_TUNNEL(tnl_info->tunnel_id)) {
   4684                 return BCM_E_PARAM;
   4685             }
   4686             if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, TUNNEL_IDf)) {
   4687                 tunnel = BCM_GPORT_TUNNEL_ID_GET(tnl_info->tunnel_id);
   4688                 soc_L3_TUNNELm_field32_set(unit, entry_ptr, TUNNEL_IDf,
   4689                                            tunnel);
   4690             }
   4691         }
   4692 
   4693         /* Program HA/FA for Ac2Ac tunnels */
   4694         if (((tnl_info->type == bcmTunnelTypeWlanAcToAc) ||
   4695             (tnl_info->type == bcmTunnelTypeWlanAcToAc6)) &&
   4696             (tnl_info->flags &  BCM_TUNNEL_TERM_WLAN_SET_ROAM)) {
   4697             _bcm_tr3_wlan_tunnel_set_roam(unit, tnl_info->tunnel_id);    
   4698         }
   4699     }
   4700     if ((tnl_info->type == bcmTunnelTypeAutoMulticast) ||
   4701         (tnl_info->type == bcmTunnelTypeAutoMulticast6)) {
   4702         /* Program L3_IIFm */
   4703         if(SOC_MEM_FIELD_VALID(unit, L3_IIFm, IPMC_L3_IIFf)) {
   4704             sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t));
   4705             iif.intf_id = tnl_info->vlan;
   4706 
   4707             rv = _bcm_tr_l3_ingress_interface_get(unit, NULL, &iif);
   4708             BCM_IF_ERROR_RETURN(rv);
   4709             iif.vrf = tnl_info->vrf;
   4710             rv = _bcm_tr_l3_ingress_interface_set(unit, &iif, NULL, NULL);
   4711             BCM_IF_ERROR_RETURN(rv);
   4712         }
   4713 
   4714         /* Program tunnel id */
   4715         if (tnl_info->flags & BCM_TUNNEL_TERM_TUNNEL_WITH_ID) {
   4716             if (!BCM_GPORT_IS_TUNNEL(tnl_info->tunnel_id)) {
   4717                 return BCM_E_PARAM;
   4718             }
   4719             if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, TUNNEL_IDf)) {
   4720                 tunnel = BCM_GPORT_TUNNEL_ID_GET(tnl_info->tunnel_id);
   4721                 soc_L3_TUNNELm_field32_set(unit, entry_ptr, TUNNEL_IDf,
   4722                                            tunnel);
   4723             }
   4724         }
   4725     }
   4726     return (BCM_E_NONE);
   4727 }
   4728 
   4729 /*
   4730  * Function:
   4731  *      _bcm_tr3_nh_update_match
   4732  * Purpose:
   4733  *      Update/Show/Delete all entries in nh table matching a certain rule.
   4734  * Parameters:
   4735  *      unit     - (IN)SOC unit number.
   4736  *      trv_data - (IN)Delete pattern + compare,act,notify routines.  
   4737  * Returns:
   4738  *      BCM_E_XXX
   4739  */
   4740 int
   4741 _bcm_tr3_nh_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data)
   4742 {
   4743     bcm_l3_egress_t nh_entry;     /* Next hop entry info.           */
   4744     uint32 *ing_entry_ptr;        /* Ingress next hop entry pointer.*/ 
   4745     char *ing_tbl_ptr;            /* Dma table pointer.             */
   4746     int cmp_result;               /* Test routine result.           */
   4747     soc_mem_t mem;                /* Next hop memory.               */
   4748     soc_mem_t mem_egr_nh;                /* Next hop memory.               */
   4749     int idx;                      /* Iteration index.               */
   4750     char *egr_tbl_buf;            /* Dma egress nh table pointer.   */
   4751     uint32 *egr_entry_ptr = NULL; /* Egress next hop entry pinter.  */ 
   4752     int rv = BCM_E_NONE;          /* Operation return status.       */
   4753     int table_ent_size;           /* Table entry size. */
   4754     int idx_min, idx_max, chunk_size, num_chunks, chunk_index;
   4755     int entry_type;
   4756 
   4757     /* Get next table memory. */
   4758     mem = BCM_XGS3_L3_MEM(unit, nh);
   4759     mem_egr_nh = EGR_L3_NEXT_HOPm;
   4760 
   4761     /* Table DMA the nhtable to software copy */
   4762     BCM_IF_ERROR_RETURN 
   4763         (bcm_xgs3_l3_tbl_dma(unit, mem, BCM_XGS3_L3_ENT_SZ(unit, nh), "nh_tbl",
   4764                              &ing_tbl_ptr, NULL));
   4765 
   4766     chunk_size = 1024;
   4767     table_ent_size = BCM_L3_MEM_ENT_SIZE(unit, mem_egr_nh);
   4768     num_chunks = soc_mem_index_count(unit, mem_egr_nh) / chunk_size;
   4769     if (soc_mem_index_count(unit, mem_egr_nh) % chunk_size) {
   4770         num_chunks++;
   4771     }
   4772 
   4773     egr_tbl_buf = soc_cm_salloc(unit, table_ent_size * chunk_size,
   4774                                        "egr_tbl_chunk buffer");
   4775     if (NULL == egr_tbl_buf) {
   4776         rv = BCM_E_MEMORY;
   4777         goto cleanup;
   4778     }
   4779         
   4780     for (chunk_index = 0; chunk_index < num_chunks; chunk_index++) {
   4781         idx_min = chunk_index * chunk_size;
   4782         idx_max = idx_min + chunk_size - 1;
   4783         if (idx_max > soc_mem_index_max(unit, mem_egr_nh)) {
   4784             idx_max = soc_mem_index_max(unit, mem_egr_nh);
   4785         }
   4786 
   4787         /* Reset allocated buffer. */
   4788         sal_memset(egr_tbl_buf, 0, (table_ent_size * chunk_size));
   4789 
   4790         rv = soc_mem_read_range(unit, mem_egr_nh, MEM_BLOCK_ANY,
   4791                 idx_min, idx_max, egr_tbl_buf);
   4792         if (SOC_FAILURE(rv)) {
   4793             goto cleanup;
   4794         }
   4795 
   4796         /* Iterate over all the entries - show matching ones. */
   4797         for (idx = idx_min; idx <= idx_max; idx++) {
   4798             /* Skip unused entries. */
   4799             if (!BCM_XGS3_L3_ENT_REF_CNT (BCM_XGS3_L3_TBL_PTR(unit,
   4800                                                    next_hop), idx)) {
   4801                 continue;
   4802             }
   4803 
   4804             /* Skip trap to CPU entry internally installed entry. */
   4805             if (BCM_XGS3_L3_L2CPU_NH_IDX(unit) == idx) {
   4806                 continue;
   4807             }
   4808 
   4809             /* Skip the internally installed BLACK_HOLE entry */
   4810             if (BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit) == idx) {
   4811                 continue;
   4812             }
   4813 
   4814             /* Calculate entry ofset. */
   4815             ing_entry_ptr =
   4816                 soc_mem_table_idx_to_pointer(unit, mem, uint32 *, ing_tbl_ptr, idx);
   4817 
   4818             /*  Read egress next hop entry. */
   4819             egr_entry_ptr = 
   4820                 soc_mem_table_idx_to_pointer(unit, mem_egr_nh,
   4821                                      uint32 *, egr_tbl_buf, (idx % chunk_size));
   4822             entry_type = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
   4823                     egr_entry_ptr, ENTRY_TYPEf);
   4824             if (entry_type == 0 || entry_type == 1 || entry_type == 7 ||
   4825                 (entry_type == 4 && soc_feature(unit, soc_feature_wlan))) {
   4826                 /* Valid entry types for L3 egress object are L3UC, MPLS,
   4827                  * WLAN, and L3MC.
   4828                  */
   4829             } else {
   4830                 continue;
   4831             }
   4832 
   4833             /* coverity[var_deref_model : FALSE] */
   4834             _bcm_xgs3_nh_entry_parse(unit, ing_entry_ptr, egr_entry_ptr, NULL,  idx,
   4835                                      &nh_entry, NULL);
   4836     
   4837             if (soc_feature(unit, soc_feature_ecmp_dlb)) {
   4838                 bcm_tr3_l3_egress_dlb_attr_get(unit, idx, &nh_entry);
   4839             }
   4840 
   4841             /* Execute operation routine if any. */
   4842             if (trv_data->op_cb) {
   4843                 rv = (*trv_data->op_cb)(unit, (void *)trv_data,
   4844                                         (void *)&nh_entry,(void *)&idx, &cmp_result);
   4845                 if (rv < 0) {
   4846 #ifdef BCM_CB_ABORT_ON_ERR
   4847                     if(SOC_CB_ABORT_ON_ERR(unit)) {
   4848                         break;
   4849                     }
   4850 #endif
   4851                 }
   4852             }
   4853         }
   4854     }
   4855 
   4856 cleanup:
   4857     if (ing_tbl_ptr) {
   4858         soc_cm_sfree(unit, ing_tbl_ptr);
   4859     }
   4860 
   4861     if (egr_tbl_buf) {
   4862         soc_cm_sfree(unit, egr_tbl_buf);
   4863     }
   4864 
   4865     return (rv);
   4866 }
   4867 
   4868 /*
   4869  * Function:
   4870  *      _bcm_tr3_l3_tnl_term_entry_init
   4871  * Purpose:
   4872  *      Initialize soc tunnel terminator entry key portion.
   4873  * Parameters:
   4874  *      unit     - (IN)  BCM device number. 
   4875  *      tnl_info - (IN)  BCM buffer with tunnel info.
   4876  *      entry    - (OUT) SOC buffer with key filled in.  
   4877  * Returns:
   4878  *      BCM_E_XXX
   4879  */
   4880 int
   4881 _bcm_tr3_l3_tnl_term_entry_init(int unit, bcm_tunnel_terminator_t *tnl_info,
   4882                                 soc_tunnel_term_t *entry)
   4883 {
   4884     int       idx;                /* Entry iteration index.     */
   4885     int       idx_max;            /* Entry widht.               */
   4886     uint32    *entry_ptr;         /* Filled entry pointer.      */
   4887     _bcm_tnl_term_type_t tnl_type;/* Tunnel type.               */
   4888     int       rv;                 /* Operation return status.   */
   4889 
   4890     /* Input parameters check. */
   4891     if ((NULL == tnl_info) || (NULL == entry)) {
   4892         return (BCM_E_PARAM);
   4893     }
   4894 
   4895     /* Get tunnel type & sub_type. */
   4896     BCM_IF_ERROR_RETURN
   4897         (_bcm_xgs3_l3_set_tnl_term_type(unit, tnl_info, &tnl_type));
   4898 
   4899     /* Reset destination structure. */
   4900     sal_memset(entry, 0, sizeof(soc_tunnel_term_t));
   4901 
   4902     /* Set Destination/Source pair. */
   4903     entry_ptr = (uint32 *)&entry->entry_arr[0];
   4904     if (tnl_type.tnl_outer_hdr_ipv6) {
   4905         /* Apply mask on source address. */
   4906         rv = bcm_xgs3_l3_mask6_apply(tnl_info->sip6_mask, tnl_info->sip6);
   4907         BCM_IF_ERROR_RETURN(rv);
   4908 
   4909         /* SIP [0-63] */
   4910         soc_mem_ip6_addr_set(unit, L3_TUNNELm, 
   4911                              (uint32 *)&entry->entry_arr[0], IP_ADDRf,
   4912                              tnl_info->sip6, SOC_MEM_IP6_LOWER_ONLY);
   4913         /* SIP [64-127] */
   4914         soc_mem_ip6_addr_set(unit, L3_TUNNELm, 
   4915                              (uint32 *)&entry->entry_arr[1], IP_ADDRf,
   4916                              tnl_info->sip6, SOC_MEM_IP6_UPPER_ONLY);
   4917         /* DIP [0-63] */
   4918         soc_mem_ip6_addr_set(unit, L3_TUNNELm, 
   4919                              (uint32 *)&entry->entry_arr[2], IP_ADDRf,
   4920                              tnl_info->dip6, SOC_MEM_IP6_LOWER_ONLY);
   4921         /* DIP [64-127] */
   4922         soc_mem_ip6_addr_set(unit, L3_TUNNELm, 
   4923                              (uint32 *)&entry->entry_arr[3], IP_ADDRf,
   4924                              tnl_info->dip6, SOC_MEM_IP6_UPPER_ONLY);
   4925 
   4926         /* SIP MASK [0-63] */
   4927         soc_mem_ip6_addr_set(unit, L3_TUNNELm, 
   4928                              (uint32 *)&entry->entry_arr[0], IP_ADDR_MASKf,
   4929                              tnl_info->sip6_mask, SOC_MEM_IP6_LOWER_ONLY);
   4930         /* SIP MASK [64-127] */
   4931         soc_mem_ip6_addr_set(unit, L3_TUNNELm, 
   4932                              (uint32 *)&entry->entry_arr[1], IP_ADDR_MASKf,
   4933                              tnl_info->sip6_mask, SOC_MEM_IP6_UPPER_ONLY);
   4934         /* DIP MASK [0-63] */
   4935         soc_mem_ip6_addr_set(unit, L3_TUNNELm, 
   4936                              (uint32 *)&entry->entry_arr[2], IP_ADDR_MASKf,
   4937                              tnl_info->dip6_mask, SOC_MEM_IP6_LOWER_ONLY);
   4938         /* DIP MASK [64-127] */
   4939         soc_mem_ip6_addr_set(unit, L3_TUNNELm, 
   4940                              (uint32 *)&entry->entry_arr[3], IP_ADDR_MASKf,
   4941                              tnl_info->dip6_mask, SOC_MEM_IP6_UPPER_ONLY);
   4942     } else {
   4943         tnl_info->sip &= tnl_info->sip_mask;
   4944 
   4945         /* Set destination ip. */
   4946         soc_L3_TUNNELm_field32_set(unit, entry_ptr, DIPf, tnl_info->dip);
   4947 
   4948         /* Set source ip. */
   4949         soc_L3_TUNNELm_field32_set(unit, entry_ptr, SIPf, tnl_info->sip);
   4950 
   4951         /* Set destination subnet mask. */
   4952         soc_L3_TUNNELm_field32_set(unit, entry_ptr, DIP_MASKf,
   4953                                    tnl_info->dip_mask);
   4954 
   4955         /* Set source subnet mask. */
   4956         soc_L3_TUNNELm_field32_set(unit, entry_ptr, SIP_MASKf,
   4957                                    tnl_info->sip_mask);
   4958     }
   4959 
   4960     /* Resolve number of entries hw entry occupies. */
   4961     idx_max = (tnl_type.tnl_outer_hdr_ipv6) ? SOC_TNL_TERM_IPV6_ENTRY_WIDTH : \
   4962               SOC_TNL_TERM_IPV4_ENTRY_WIDTH;  
   4963     
   4964     for (idx = 0; idx < idx_max; idx++) {
   4965         entry_ptr = (uint32 *)&entry->entry_arr[idx];
   4966 
   4967         /* Set valid bit. */
   4968         soc_L3_TUNNELm_field32_set(unit, entry_ptr, VALIDf, 1);
   4969 
   4970         /* Set tunnel subtype. */
   4971         soc_L3_TUNNELm_field32_set(unit, entry_ptr, SUB_TUNNEL_TYPEf,
   4972                                    tnl_type.tnl_sub_type);
   4973 
   4974         /* Set tunnel type. */
   4975         soc_L3_TUNNELm_field32_set(unit, entry_ptr, TUNNEL_TYPEf,
   4976                                    tnl_type.tnl_auto);
   4977 
   4978         /* Set entry mode. */
   4979         soc_L3_TUNNELm_field32_set(unit, entry_ptr, KEY_TYPEf,
   4980                                tnl_type.tnl_outer_hdr_ipv6);
   4981         soc_L3_TUNNELm_field32_set(unit, entry_ptr, KEY_TYPE_MASKf, 1);
   4982 
   4983         if (0 == idx) {
   4984             /* Set the PROTOCOL field */
   4985             if ((tnl_info->type == bcmTunnelTypeIpAnyIn4) || 
   4986                 (tnl_info->type == bcmTunnelTypeIpAnyIn6))
   4987             {
   4988               /* Set PROTOCOL and PROTOCOL_MASK field to zero for IpAnyInx tunnel type*/
   4989                soc_L3_TUNNELm_field32_set(unit, entry_ptr, PROTOCOLf, 0x0);
   4990                soc_L3_TUNNELm_field32_set(unit, entry_ptr, PROTOCOL_MASKf, 0x0);
   4991             } else { 
   4992                 soc_L3_TUNNELm_field32_set(unit, entry_ptr, PROTOCOLf,
   4993                                            tnl_type.tnl_protocol);
   4994                 soc_L3_TUNNELm_field32_set(unit, entry_ptr, 
   4995                                            PROTOCOL_MASKf, 0xff);
   4996             }
   4997         }
   4998         
   4999         if ((tnl_info->type == bcmTunnelTypeWlanWtpToAc) ||
   5000             (tnl_info->type == bcmTunnelTypeWlanAcToAc) ||
   5001             (tnl_info->type == bcmTunnelTypeWlanWtpToAc6) ||
   5002             (tnl_info->type == bcmTunnelTypeWlanAcToAc6)) { 
   5003 
   5004             /* Set the L4 ports - WLAN/AMT tunnels */
   5005             if (0 == idx) {
   5006                 soc_L3_TUNNELm_field32_set(unit, entry_ptr, L4_DEST_PORTf,
   5007                                            tnl_info->udp_dst_port);
   5008 
   5009                 soc_L3_TUNNELm_field32_set(unit, entry_ptr,
   5010                                            L4_DEST_PORT_MASKf, 0xffff);
   5011 
   5012                 soc_L3_TUNNELm_field32_set(unit, entry_ptr, L4_SRC_PORTf,
   5013                                            tnl_info->udp_src_port);
   5014     
   5015                 soc_L3_TUNNELm_field32_set(unit, entry_ptr,
   5016                                            L4_SRC_PORT_MASKf, 0xffff);
   5017             }
   5018 
   5019             /* Set UDP tunnel type. */
   5020             if (soc_mem_field_valid(unit, L3_TUNNELm, UDP_TUNNEL_TYPEf)) {
   5021                 soc_L3_TUNNELm_field32_set(unit, entry_ptr, UDP_TUNNEL_TYPEf,
   5022                                            tnl_type.tnl_udp_type);
   5023             }
   5024             /* Ignore UDP checksum */
   5025             soc_L3_TUNNELm_field32_set(unit, entry_ptr,
   5026                                        UDP_CHECKSUM_CONTROLf, 0x0);
   5027         } else if (tnl_info->type == bcmTunnelTypeAutoMulticast) {
   5028 
   5029             /* Set UDP tunnel type. */
   5030             if (soc_mem_field_valid(unit, L3_TUNNELm, UDP_TUNNEL_TYPEf)) {
   5031                 soc_L3_TUNNELm_field32_set(unit, entry_ptr, UDP_TUNNEL_TYPEf,
   5032                                            tnl_type.tnl_udp_type);
   5033             }
   5034 
   5035             soc_L3_TUNNELm_field32_set(unit, entry_ptr,
   5036                                        UDP_CHECKSUM_CONTROLf, 0x0);
   5037             soc_L3_TUNNELm_field32_set(unit, entry_ptr, CTRL_PKTS_TO_CPUf,
   5038                        0x1);
   5039         } else if (tnl_info->type == bcmTunnelTypeAutoMulticast6) {
   5040 
   5041             /* Set UDP tunnel type. */
   5042             if (soc_mem_field_valid(unit, L3_TUNNELm, UDP_TUNNEL_TYPEf)) {
   5043                 soc_L3_TUNNELm_field32_set(unit, entry_ptr, UDP_TUNNEL_TYPEf,
   5044                                            tnl_type.tnl_udp_type);
   5045             }
   5046             soc_L3_TUNNELm_field32_set(unit, entry_ptr,
   5047                                                 UDP_CHECKSUM_CONTROLf, 0x0);
   5048             soc_L3_TUNNELm_field32_set(unit, entry_ptr, CTRL_PKTS_TO_CPUf, 0x1);
   5049         }
   5050 
   5051         /* Save vlan id for ipmc lookup.*/
   5052         soc_L3_TUNNELm_field32_set(unit, entry_ptr, L3_IIFf, tnl_info->vlan);
   5053 
   5054         /* Set GRE payload */
   5055         if (tnl_type.tnl_gre) {
   5056             /* GRE IPv6 payload is allowed. */
   5057             soc_L3_TUNNELm_field32_set(unit, entry_ptr, GRE_PAYLOAD_IPV6f,
   5058                                        tnl_type.tnl_gre_v6_payload);
   5059 
   5060             /* GRE IPv6 payload is allowed. */
   5061             soc_L3_TUNNELm_field32_set(unit, entry_ptr, GRE_PAYLOAD_IPV4f,
   5062                                        tnl_type.tnl_gre_v4_payload);
   5063         }
   5064     }
   5065     return (BCM_E_NONE);
   5066 
   5067 }
   5068 
   5069 /*
   5070  * Function:
   5071  *      _bcm_tr3_l3_tnl_term_entry_parse
   5072  * Purpose:
   5073  *      Parse tunnel terminator entry portion.
   5074  * Parameters:
   5075  *      unit     - (IN)  BCM device number. 
   5076  *      entry    - (IN)  SOC buffer with tunne information.  
   5077  *      tnl_info - (OUT) BCM buffer with tunnel info.
   5078  * Returns:
   5079  *      BCM_E_XXX
   5080  */
   5081 int
   5082 _bcm_tr3_l3_tnl_term_entry_parse(int unit, soc_tunnel_term_t *entry,
   5083                                   bcm_tunnel_terminator_t *tnl_info)
   5084 {
   5085     _bcm_tnl_term_type_t tnl_type;     /* Tunnel type information.   */
   5086     uint32 *entry_ptr;                 /* Filled entry pointer.      */
   5087     int tunnel_id;                     /* Tunnel ID */
   5088     int remote_port;                   /* Remote port */
   5089     bcm_module_t mod, mod_out, my_mod; /* Module IDs */
   5090     bcm_port_t port, port_out;         /* Physical ports */
   5091 
   5092     /* Input parameters check. */
   5093     if ((NULL == tnl_info) || (NULL == entry)) {
   5094         return (BCM_E_PARAM);
   5095     }
   5096 
   5097     /* Reset destination structure. */
   5098     bcm_tunnel_terminator_t_init(tnl_info);
   5099     sal_memset(&tnl_type, 0, sizeof(_bcm_tnl_term_type_t));
   5100 
   5101     entry_ptr = (uint32 *)&entry->entry_arr[0];
   5102 
   5103     /* Get valid bit. */
   5104     if (!soc_L3_TUNNELm_field32_get(unit, entry_ptr, VALIDf)) {
   5105         return (BCM_E_NOT_FOUND);
   5106     }
   5107 
   5108     tnl_type.tnl_outer_hdr_ipv6 =
   5109         (soc_L3_TUNNELm_field32_get(unit, entry_ptr, KEY_TYPEf) == 0x1) ? 1 : 0;
   5110      
   5111     /* Get Destination/Source pair. */
   5112     if (tnl_type.tnl_outer_hdr_ipv6) {
   5113         /* SIP [0-63] */
   5114         soc_mem_ip6_addr_get(unit, L3_TUNNELm, 
   5115                              (uint32 *)&entry->entry_arr[0], IP_ADDRf,
   5116                              tnl_info->sip6, SOC_MEM_IP6_LOWER_ONLY);
   5117         /* SIP [64-127] */
   5118         soc_mem_ip6_addr_get(unit, L3_TUNNELm, 
   5119                              (uint32 *)&entry->entry_arr[1], IP_ADDRf,
   5120                              tnl_info->sip6, SOC_MEM_IP6_UPPER_ONLY);
   5121         /* DIP [0-63] */
   5122         soc_mem_ip6_addr_get(unit, L3_TUNNELm, 
   5123                              (uint32 *)&entry->entry_arr[2], IP_ADDRf,
   5124                              tnl_info->dip6, SOC_MEM_IP6_LOWER_ONLY);
   5125         /* DIP [64-127] */
   5126         soc_mem_ip6_addr_get(unit, L3_TUNNELm, 
   5127                              (uint32 *)&entry->entry_arr[3], IP_ADDRf,
   5128                              tnl_info->dip6, SOC_MEM_IP6_UPPER_ONLY);
   5129 
   5130         /* SIP MASK [0-63] */
   5131         soc_mem_ip6_addr_get(unit, L3_TUNNELm, 
   5132                              (uint32 *)&entry->entry_arr[0], IP_ADDR_MASKf,
   5133                              tnl_info->sip6_mask, SOC_MEM_IP6_LOWER_ONLY);
   5134         /* SIP MASK [64-127] */
   5135         soc_mem_ip6_addr_get(unit, L3_TUNNELm, 
   5136                              (uint32 *)&entry->entry_arr[1], IP_ADDR_MASKf,
   5137                              tnl_info->sip6_mask, SOC_MEM_IP6_UPPER_ONLY);
   5138         /* DIP MASK [0-63] */
   5139         soc_mem_ip6_addr_get(unit, L3_TUNNELm, 
   5140                              (uint32 *)&entry->entry_arr[2], IP_ADDR_MASKf,
   5141                              tnl_info->dip6_mask, SOC_MEM_IP6_LOWER_ONLY);
   5142         /* DIP MASK [64-127] */
   5143         soc_mem_ip6_addr_get(unit, L3_TUNNELm, 
   5144                              (uint32 *)&entry->entry_arr[3], IP_ADDR_MASKf,
   5145                              tnl_info->dip6_mask, SOC_MEM_IP6_UPPER_ONLY);
   5146 
   5147     }  else {
   5148         /* Get destination ip. */
   5149         tnl_info->dip = soc_L3_TUNNELm_field32_get(unit, entry_ptr, DIPf);
   5150 
   5151         /* Get source ip. */
   5152         tnl_info->sip = soc_L3_TUNNELm_field32_get(unit, entry_ptr, SIPf);
   5153 
   5154         /* Destination subnet mask. */
   5155         tnl_info->dip_mask = BCM_XGS3_L3_IP4_FULL_MASK;
   5156 
   5157         /* Source subnet mask. */
   5158         tnl_info->sip_mask = soc_L3_TUNNELm_field32_get(unit, entry_ptr, 
   5159                                                         SIP_MASKf);
   5160     }
   5161 
   5162     /* Get tunnel subtype. */
   5163     tnl_type.tnl_sub_type = 
   5164         soc_L3_TUNNELm_field32_get(unit, entry_ptr, SUB_TUNNEL_TYPEf);
   5165 
   5166     /* Get UDP tunnel type. */
   5167     if (soc_mem_field_valid(unit, L3_TUNNELm, UDP_TUNNEL_TYPEf)) {
   5168         tnl_type.tnl_udp_type =
   5169             soc_L3_TUNNELm_field32_get(unit, entry_ptr, UDP_TUNNEL_TYPEf);
   5170     }
   5171 
   5172     /* Get tunnel type. */
   5173     tnl_type.tnl_auto = 
   5174         soc_L3_TUNNELm_field32_get(unit, entry_ptr, TUNNEL_TYPEf);
   5175 
   5176     /* Copy DSCP from outer header flag. */
   5177     if (soc_L3_TUNNELm_field32_get(unit, entry_ptr, USE_OUTER_HDR_DSCPf)) {
   5178         tnl_info->flags |= BCM_TUNNEL_TERM_USE_OUTER_DSCP;
   5179     }
   5180     /* Copy TTL from outer header flag. */
   5181     if (soc_L3_TUNNELm_field32_get(unit, entry_ptr, USE_OUTER_HDR_TTLf)) {
   5182         tnl_info->flags |= BCM_TUNNEL_TERM_USE_OUTER_TTL;
   5183     }
   5184     /* Keep inner header DSCP flag. */
   5185     if (soc_L3_TUNNELm_field32_get(unit, entry_ptr,
   5186                                    DONOT_CHANGE_INNER_HDR_DSCPf)) {
   5187         tnl_info->flags |= BCM_TUNNEL_TERM_KEEP_INNER_DSCP;
   5188     }
   5189 
   5190     soc_mem_pbmp_field_get(unit, L3_TUNNELm, entry_ptr, ALLOWED_PORT_BITMAPf,
   5191                            &tnl_info->pbmp);
   5192 
   5193     /* Tunnel or IPMC lookup vlan id */
   5194     tnl_info->vlan = soc_L3_TUNNELm_field32_get(unit, entry_ptr, IINTFf);
   5195 
   5196     /*  Get trust dscp per tunnel */ 
   5197     if (soc_L3_TUNNELm_field32_get(unit, entry_ptr, USE_OUTER_HDR_DSCPf)) {
   5198         tnl_info->flags |= BCM_TUNNEL_TERM_DSCP_TRUST;
   5199     }
   5200     
   5201     /* Get Tunnel class id for VFP match */
   5202     if(SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, TUNNEL_CLASS_IDf)) {                 
   5203         tnl_info->tunnel_class = soc_L3_TUNNELm_field32_get(unit, entry_ptr, 
   5204                                     TUNNEL_CLASS_IDf);
   5205     }
   5206 
   5207     /* Get the protocol field and make some decisions */
   5208     tnl_type.tnl_protocol = soc_L3_TUNNELm_field32_get(unit, entry_ptr, 
   5209                                                        PROTOCOLf);
   5210     switch (tnl_type.tnl_protocol) {
   5211         case 0x2F:
   5212             tnl_type.tnl_gre = 1;
   5213             break;
   5214         case 0x67:
   5215             tnl_type.tnl_pim_sm = 1;
   5216         default:
   5217             break;
   5218     }
   5219     /* Get gre IPv4 payload allowed. */
   5220     tnl_type.tnl_gre_v4_payload = 
   5221         soc_L3_TUNNELm_field32_get(unit, entry_ptr, GRE_PAYLOAD_IPV4f); 
   5222 
   5223     /* Get gre IPv6 payload allowed. */
   5224     tnl_type.tnl_gre_v6_payload = 
   5225         soc_L3_TUNNELm_field32_get(unit, entry_ptr, GRE_PAYLOAD_IPV6f);
   5226 
   5227     /* Get the L4 data */
   5228     if (soc_mem_field_valid (unit, L3_TUNNELm, L4_SRC_PORTf)) {
   5229         tnl_info->udp_src_port = soc_L3_TUNNELm_field32_get(unit, entry_ptr, 
   5230                                                         L4_SRC_PORTf);
   5231     }
   5232     if (soc_mem_field_valid (unit, L3_TUNNELm, L4_DEST_PORTf)) {
   5233         tnl_info->udp_dst_port = soc_L3_TUNNELm_field32_get(unit, entry_ptr, 
   5234                                                         L4_DEST_PORTf);
   5235     }
   5236     /* Get the tunnel ID */
   5237     if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, TUNNEL_IDf)) {
   5238         tunnel_id = soc_L3_TUNNELm_field32_get(unit, entry_ptr, TUNNEL_IDf);
   5239         if (tunnel_id) {
   5240             BCM_GPORT_TUNNEL_ID_SET(tnl_info->tunnel_id, tunnel_id);
   5241             tnl_info->flags |= BCM_TUNNEL_TERM_TUNNEL_WITH_ID;
   5242         }
   5243     }
   5244 
   5245     /* Get tunnel type, sub_type and protocol. */
   5246     BCM_IF_ERROR_RETURN
   5247         (_bcm_xgs3_l3_get_tnl_term_type(unit, tnl_info, &tnl_type));
   5248     /* Get the remote port member */
   5249     if (SOC_MEM_FIELD_VALID(unit, L3_TUNNELm, REMOTE_TERM_GPPf)) {
   5250         remote_port = soc_L3_TUNNELm_field32_get(unit, entry_ptr,
   5251                                              REMOTE_TERM_GPPf);
   5252         mod = (remote_port >> 6) & 0x7F;
   5253         port = remote_port & 0x3F;
   5254         BCM_IF_ERROR_RETURN
   5255             (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
   5256                                     mod, port, &mod_out, &port_out));
   5257         BCM_GPORT_MODPORT_SET(tnl_info->remote_port, mod_out, port_out);
   5258         BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &my_mod));
   5259         if (mod != my_mod) {
   5260             if ((tnl_info->type == bcmTunnelTypeWlanWtpToAc) ||
   5261                 (tnl_info->type == bcmTunnelTypeWlanAcToAc) ||
   5262                 (tnl_info->type == bcmTunnelTypeWlanWtpToAc6) ||
   5263                 (tnl_info->type == bcmTunnelTypeWlanAcToAc6)) {
   5264                 tnl_info->flags |= BCM_TUNNEL_TERM_WLAN_REMOTE_TERMINATE;
   5265             }
   5266         }
   5267     }
   5268     if ((tnl_info->type == bcmTunnelTypeWlanAcToAc) ||
   5269         (tnl_info->type == bcmTunnelTypeWlanAcToAc6)) {
   5270         if (_bcm_tr3_wlan_tunnel_get_roam(unit, tnl_info->tunnel_id)) {
   5271             tnl_info->flags |= BCM_TUNNEL_TERM_WLAN_SET_ROAM;
   5272         }
   5273      }
   5274     /* Get IIF if l3 ingress mode is not set */
   5275     if (!BCM_XGS3_L3_INGRESS_MODE_ISSET(unit) &&
   5276         BCM_XGS3_L3_ING_IF_TBL_SIZE(unit) && (tnl_info->vlan > BCM_VLAN_MAX)) {
   5277         _bcm_l3_ingress_intf_t iif;
   5278         sal_memset(&iif, 0, sizeof(_bcm_l3_ingress_intf_t));
   5279         iif.intf_id = tnl_info->vlan;
   5280         BCM_IF_ERROR_RETURN(_bcm_tr_l3_ingress_interface_get(unit, NULL, &iif));
   5281 
   5282         tnl_info->vrf = iif.vrf;
   5283         tnl_info->if_class = iif.if_class;
   5284         tnl_info->qos_map_id = iif.qos_map_id;
   5285     }
   5286 
   5287     return (BCM_E_NONE);
   5288 }
   5289 
   5290 /*
   5291  * Function:
   5292  *      _bcm_tr3_l3_ipmc_get
   5293  * Purpose:
   5294  *      Get TR3 L3 multicast entry.
   5295  * Parameters:
   5296  *      unit  - (IN)SOC unit number.
   5297  *      l3cfg - (IN/OUT)Group/Source key & Get result buffer.
   5298  * Returns:
   5299  *    BCM_E_XXX
   5300  */
   5301 int
   5302 _bcm_tr3_l3_ipmc_get(int unit, _bcm_l3_cfg_t *l3cfg)
   5303 {
   5304     l3_entry_4_entry_t l3x_key;    /* Lookup key buffer.    */
   5305     l3_entry_4_entry_t l3x_entry;  /* Search result buffer. */
   5306     int clear_hit;                              /* Clear hit flag.       */
   5307     soc_mem_t mem;                              /* IPMC table memory.    */
   5308     int ipv6;                                   /* IPv6 entry indicator. */
   5309     int rv;                                     /* Return value.         */
   5310     int l3_entry_idx;                           /* Entry index           */
   5311 
   5312     /* Get entry type. */
   5313     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
   5314 
   5315     /* Get table memory. */
   5316     mem =  (ipv6) ? L3_ENTRY_4m : L3_ENTRY_2m;
   5317 
   5318     /*  Zero buffers. */
   5319     sal_memcpy(&l3x_key, soc_mem_entry_null(unit, mem), 
   5320                    soc_mem_entry_words(unit,mem) * 4);
   5321     sal_memcpy(&l3x_entry, soc_mem_entry_null(unit, mem), 
   5322                    soc_mem_entry_words(unit,mem) * 4);
   5323 
   5324     /* Check if clear hit bit is required. */
   5325     clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR;
   5326 
   5327     /* Lookup Key preparation. */
   5328     _bcm_tr3_l3_ipmc_ent_init(unit, (uint32 *)&l3x_key, l3cfg);
   5329 
   5330     /* Perform hw lookup. */
   5331     MEM_LOCK(unit, mem);
   5332     rv = soc_mem_generic_lookup(unit, mem, MEM_BLOCK_ANY,
   5333                                 _BCM_TR3_L3_MEM_BANKS_ALL,
   5334                                 &l3x_key, &l3x_entry, &l3_entry_idx);
   5335     l3cfg->l3c_hw_index = l3_entry_idx;
   5336 
   5337     MEM_UNLOCK(unit, mem);
   5338     BCM_XGS3_LKUP_IF_ERROR_RETURN(rv, BCM_E_NOT_FOUND);
   5339 
   5340     /* Extract buffer information. */
   5341     _bcm_tr3_l3_ipmc_ent_parse(unit, l3cfg, &l3x_entry);
   5342 
   5343     /* Clear the HIT bit */
   5344     if (clear_hit) {
   5345         BCM_IF_ERROR_RETURN(_bcm_tr3_l3_clear_hit(unit, mem, l3cfg, &l3x_entry,
   5346                                                   l3_entry_idx));
   5347     }
   5348     return rv;
   5349 }
   5350 
   5351 /*
   5352  * Function:
   5353  *      _bcm_tr3_l3_ipmc_get_by_idx
   5354  * Purpose:
   5355  *      Get l3 multicast entry by entry index.
   5356  * Parameters:
   5357  *      unit      - (IN)SOC unit number.
   5358  *      dma_ptr  - (IN)Table pointer in dma. 
   5359  *      idx       - (IN)Index to read. 
   5360  *      l3cfg     - (IN/OUT)Entry data.
   5361  * Returns:
   5362  *    BCM_E_XXX
   5363  */
   5364 int
   5365 _bcm_tr3_l3_ipmc_get_by_idx(int unit, void *dma_ptr,
   5366                            int idx, _bcm_l3_cfg_t *l3cfg)
   5367 {
   5368     l3_entry_4_entry_t l3_entry_v6;    /* Read buffer.            */
   5369     l3_entry_2_entry_t l3_entry_v4;    /* Read buffer.            */
   5370     void *buf_p;                      /* Hardware buffer ptr     */
   5371     soc_mem_t mem;                     /* IPMC table memory.      */
   5372     uint32 ipv6;                       /* IPv6 entry indicator.   */
   5373     int clear_hit;                     /* Clear hit bit indicator.*/
   5374     int key_type;
   5375     soc_field_t l3iif;
   5376 
   5377     /* Get entry type. */
   5378     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
   5379 
   5380     /* Get table memory. */
   5381     if (ipv6) {
   5382         mem   = L3_ENTRY_4m;
   5383         buf_p = (l3_entry_4_entry_t *)&l3_entry_v6;
   5384         l3iif = IPV6MC__L3_IIFf;
   5385     } else {
   5386         mem   = L3_ENTRY_2m;
   5387         buf_p = (l3_entry_2_entry_t *)&l3_entry_v4;
   5388         l3iif = IPV4MC__L3_IIFf;
   5389     }
   5390 
   5391     /* Check if clear hit is required. */
   5392     clear_hit = l3cfg->l3c_flags & BCM_L3_HIT_CLEAR;
   5393 
   5394     if (NULL == dma_ptr) {             /* Read from hardware. */
   5395         /* Zero buffers. */
   5396         sal_memcpy(buf_p, soc_mem_entry_null(unit, mem), 
   5397                      soc_mem_entry_words(unit,mem) * 4);
   5398 
   5399         /* Read entry from hw. */
   5400         BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, mem, idx, buf_p));
   5401     } else {                    /* Read from dma. */
   5402         if (ipv6) {
   5403             buf_p = soc_mem_table_idx_to_pointer(unit, mem,
   5404                      l3_entry_4_entry_t *, dma_ptr, idx);
   5405         } else {
   5406             buf_p = soc_mem_table_idx_to_pointer(unit, mem,
   5407                      l3_entry_2_entry_t *, dma_ptr, idx);
   5408         }
   5409     }
   5410 
   5411     /* Ignore invalid entries. */
   5412     if (!soc_mem_field32_get(unit, mem, buf_p, VALID_0f)) {
   5413         return (BCM_E_NOT_FOUND);
   5414     }
   5415 
   5416     key_type = soc_mem_field32_get(unit, mem, buf_p, KEY_TYPE_0f);
   5417 
   5418     switch (key_type) {
   5419       case SOC_MEM_KEY_L3_ENTRY_2_IPV4MC_IPV4_MULTICAST:
   5420           l3cfg->l3c_flags = BCM_L3_IPMC;
   5421           break;
   5422       case SOC_MEM_KEY_L3_ENTRY_2_IPV6UC_IPV6_UNICAST:
   5423       case SOC_MEM_KEY_L3_ENTRY_4_IPV6UC_IPV6_UNICAST:
   5424           l3cfg->l3c_flags = BCM_L3_IP6;
   5425           break;
   5426       case SOC_MEM_KEY_L3_ENTRY_4_IPV6MC_IPV6_MULTICAST:
   5427           l3cfg->l3c_flags = BCM_L3_IP6 | BCM_L3_IPMC;
   5428           break;
   5429       default:
   5430           /* Catch all other key types, set flags to zero so that the 
   5431            * following flag check is effective for all key types */
   5432           l3cfg->l3c_flags = 0;  
   5433           break;
   5434     }
   5435 
   5436     /* Ignore protocol mismatch & multicast entries. */
   5437     if ((ipv6  != (l3cfg->l3c_flags & BCM_L3_IP6)) ||
   5438         (!(l3cfg->l3c_flags & BCM_L3_IPMC))) {
   5439         return (BCM_E_NOT_FOUND);
   5440     }
   5441 
   5442     /* Set index to l3cfg. */
   5443     l3cfg->l3c_hw_index = idx;
   5444 
   5445     if (ipv6) {
   5446         /* Get group address. */
   5447         soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6MC__GROUP_IP_ADDR_LWR_96f,
   5448                              l3cfg->l3c_ip6, SOC_MEM_IP6_LOWER_96BIT);
   5449 
   5450         soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6MC__GROUP_IP_ADDR_UPR_24f,
   5451                              l3cfg->l3c_ip6, SOC_MEM_IP6_BITS_119_96);
   5452 
   5453         /* Get source  address. */
   5454         soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6MC__SOURCE_IP_ADDR_LWR_64f, 
   5455                              l3cfg->l3c_sip6, SOC_MEM_IP6_LOWER_ONLY);
   5456         soc_mem_ip6_addr_get(unit, mem, buf_p, IPV6MC__SOURCE_IP_ADDR_UPR_64f, 
   5457                              l3cfg->l3c_sip6, SOC_MEM_IP6_UPPER_ONLY);
   5458 
   5459         l3cfg->l3c_ip6[0] = 0xff;    /* Set entry to multicast*/
   5460     } else {
   5461         /* Get group id. */
   5462         l3cfg->l3c_ip_addr =
   5463             soc_mem_field32_get(unit, mem, buf_p, IPV4MC__GROUP_IP_ADDRf);
   5464 
   5465         /* Get source address. */
   5466         l3cfg->l3c_src_ip_addr =
   5467             soc_mem_field32_get(unit, mem,  buf_p, IPV4MC__SOURCE_IP_ADDRf);
   5468     }
   5469 
   5470     /* Get L3_IIF or vlan id. */
   5471     l3cfg->l3c_vid = soc_mem_field32_get(unit, mem, buf_p, l3iif);
   5472 
   5473     /* Parse entry data. */
   5474     _bcm_tr3_l3_ipmc_ent_parse(unit, l3cfg, buf_p);
   5475 
   5476     /* Clear the HIT bit */
   5477     if (clear_hit) {
   5478         BCM_IF_ERROR_RETURN(_bcm_tr3_l3_clear_hit(unit, mem, l3cfg, buf_p,
   5479                                                      l3cfg->l3c_hw_index));
   5480     }
   5481     return (BCM_E_NONE);
   5482 }
   5483 
   5484 /*
   5485  * Function:
   5486  *      _bcm_tr3_l3_ipmc_add
   5487  * Purpose:
   5488  *      Add TR3 L3 multicast entry.
   5489  * Parameters:
   5490  *      unit  - (IN)SOC unit number.
   5491  *      l3cfg - (IN/OUT)Group/Source key.
   5492  * Returns:
   5493  *    BCM_E_XXX
   5494  */
   5495 int
   5496  _bcm_tr3_l3_ipmc_add(int unit, _bcm_l3_cfg_t *l3cfg)
   5497 {
   5498     l3_entry_4_entry_t l3x_entry;  /* Write entry buffer.   */
   5499     soc_mem_t mem;                              /* IPMC table memory.    */
   5500     uint32 *buf_p;                              /* HW buffer address.    */
   5501     int ipv6;                                   /* IPv6 entry indicator. */
   5502     int idx;                                    /* Iteration index.      */
   5503     int rv;                                     /* Return value.         */
   5504     soc_field_t hitf[] = { HIT_0f, HIT_1f, HIT_2f};
   5505     soc_field_t rpe, dst_discard, vrf_id, l3mc_idx, class_id, pri;
   5506 
   5507     /* Get entry type. */
   5508     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
   5509 
   5510     /* Get table memory and table fields */
   5511     if (ipv6) {
   5512         mem         = L3_ENTRY_4m;
   5513         pri         = IPV6MC__PRIf;
   5514         rpe         = IPV6MC__RPEf;
   5515         vrf_id      = IPV6MC__VRF_IDf;
   5516         l3mc_idx    = IPV6MC__L3MC_INDEXf;
   5517         class_id    = IPV6MC__CLASS_IDf;
   5518         dst_discard = IPV6MC__DST_DISCARDf;
   5519     } else {
   5520         mem         = L3_ENTRY_2m;
   5521         pri         = IPV4MC__PRIf;
   5522         rpe         = IPV4MC__RPEf;
   5523         vrf_id      = IPV4MC__VRF_IDf;
   5524         l3mc_idx    = IPV4MC__L3MC_INDEXf;
   5525         class_id    = IPV4MC__CLASS_IDf;
   5526         dst_discard = IPV4MC__DST_DISCARDf;
   5527     }
   5528 
   5529     /*  Zero buffers. */
   5530     buf_p = (uint32 *)&l3x_entry; 
   5531     sal_memcpy(buf_p, soc_mem_entry_null(unit, mem), 
   5532                    soc_mem_entry_words(unit,mem) * 4);
   5533 
   5534    /* Prepare entry to write. */
   5535     _bcm_tr3_l3_ipmc_ent_init(unit, (uint32 *)&l3x_entry, l3cfg);
   5536 
   5537     /* Set priority override bit. */
   5538     if (l3cfg->l3c_flags & BCM_L3_RPE) {
   5539         soc_mem_field32_set(unit, mem, buf_p, rpe, 1);
   5540     }
   5541 
   5542     /* Set destination discard. */
   5543     if (l3cfg->l3c_flags & BCM_L3_DST_DISCARD) {
   5544         soc_mem_field32_set(unit, mem, buf_p, dst_discard, 1);
   5545     }
   5546 	
   5547     /* Virtual router id. */
   5548     soc_mem_field32_set(unit, mem, buf_p, vrf_id, l3cfg->l3c_vrf);
   5549 
   5550     /* Set priority. */
   5551     soc_mem_field32_set(unit, mem, buf_p, pri, l3cfg->l3c_prio);
   5552 
   5553     /* Pointer to ipmc table. */
   5554     soc_mem_field32_set(unit, mem, buf_p, l3mc_idx, l3cfg->l3c_ipmc_ptr);
   5555 
   5556     /* Classification lookup class id. */
   5557     soc_mem_field32_set(unit, mem, buf_p, class_id, l3cfg->l3c_lookup_class);
   5558 
   5559     for (idx = 0; idx < COUNTOF(hitf); idx++) {
   5560         /* Set hit bit. */
   5561         if (l3cfg->l3c_flags & BCM_L3_HIT) {
   5562             soc_mem_field32_set(unit, mem, buf_p, hitf[idx], 1);
   5563         }
   5564     }
   5565 
   5566     /* Write entry to the hw. */
   5567     MEM_LOCK(unit, mem);
   5568     /* Handle replacement. */
   5569     if (BCM_XGS3_L3_INVALID_INDEX != l3cfg->l3c_hw_index) {
   5570         rv = BCM_XGS3_MEM_WRITE(unit, mem, l3cfg->l3c_hw_index, buf_p);
   5571     } else {
   5572         rv = soc_mem_insert(unit, mem, MEM_BLOCK_ANY, (void *)buf_p);
   5573     }
   5574 
   5575     /* Increment number of ipmc routes. */
   5576     if (BCM_SUCCESS(rv) && (BCM_XGS3_L3_INVALID_INDEX == l3cfg->l3c_hw_index)) {
   5577         (ipv6) ? BCM_XGS3_L3_IP6_IPMC_CNT(unit)++ : \
   5578                  BCM_XGS3_L3_IP4_IPMC_CNT(unit)++;
   5579     }
   5580     /*    coverity[overrun-local : FALSE]    */
   5581     MEM_UNLOCK(unit, mem);
   5582     return rv;
   5583 }
   5584 
   5585 /*
   5586  * Function:
   5587  *      _bcm_tr3_l3_ipmc_del
   5588  * Purpose:
   5589  *      Delete TR3 L3 multicast entry.
   5590  * Parameters:
   5591  *      unit  - (IN)SOC unit number.
   5592  *      l3cfg - (IN)Group/Source deletion key.
   5593  * Returns:
   5594  *    BCM_E_XXX
   5595  */
   5596 int
   5597 _bcm_tr3_l3_ipmc_del(int unit, _bcm_l3_cfg_t *l3cfg)
   5598 {
   5599     l3_entry_4_entry_t l3x_entry;  /* Delete buffer.          */
   5600     soc_mem_t mem;                              /* IPMC table memory.      */
   5601     int ipv6;                                   /* IPv6 entry indicator.   */
   5602     int rv;                                     /* Operation return value. */
   5603 
   5604     /* Get entry type. */
   5605     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
   5606 
   5607     /* Get table memory. */
   5608     mem =  (ipv6) ? L3_ENTRY_4m : L3_ENTRY_2m;
   5609 
   5610     /*  Zero entry buffer. */
   5611     sal_memcpy(&l3x_entry, soc_mem_entry_null(unit, mem), 
   5612                soc_mem_entry_words(unit,mem) * 4);
   5613 
   5614 
   5615     /* Key preparation. */
   5616     _bcm_tr3_l3_ipmc_ent_init(unit, (uint32 *)&l3x_entry, l3cfg);
   5617 
   5618     /* Delete the entry from hw. */
   5619     MEM_LOCK(unit, mem);
   5620 
   5621     rv = soc_mem_delete(unit, mem, MEM_BLOCK_ANY, (void *)&l3x_entry);
   5622 
   5623     /* Decrement number of ipmc routes. */
   5624     if (BCM_SUCCESS(rv)) {
   5625         (ipv6) ? BCM_XGS3_L3_IP6_IPMC_CNT(unit)-- : \
   5626             BCM_XGS3_L3_IP4_IPMC_CNT(unit)--;
   5627     }
   5628     MEM_UNLOCK(unit, mem);
   5629     return rv;
   5630 }
   5631 
   5632 /*----- ECMP DLB FUNCS ----- */
   5633 
   5634 /*
   5635  * Function:
   5636  *      _bcm_tr3_ecmp_dlb_member_id_alloc
   5637  * Purpose:
   5638  *      Get a free ECMP DLB Member ID and mark it used.
   5639  * Parameters:
   5640  *      unit - (IN) SOC unit number.
   5641  *      member_id - (OUT) Allocated Member ID.
   5642  * Returns:
   5643  *      BCM_E_xxx
   5644  */
   5645 STATIC int
   5646 _bcm_tr3_ecmp_dlb_member_id_alloc(int unit, int *member_id)
   5647 {
   5648     int vla;
   5649     int i;
   5650     int max_members;
   5651 
   5652     BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit,
   5653                         bcmSwitchEcmpDynamicAccountingSelect, &vla));
   5654     if (vla) {
   5655         max_members = soc_mem_index_count(unit, DLB_ECMP_MEMBER_ATTRIBUTEm);
   5656     } else {
   5657         /* In physical link accounting, the number of members is limited to
   5658          * the number of physical ports.
   5659          */
   5660         max_members = soc_reg_field_length(unit, DLB_ECMP_MEMBER_HW_STATE_64r,
   5661                 BITMAPf);
   5662     }
   5663 
   5664     for (i = 0; i < max_members; i++) {
   5665         if (!_BCM_ECMP_DLB_MEMBER_ID_USED_GET(unit, i)) {
   5666             _BCM_ECMP_DLB_MEMBER_ID_USED_SET(unit, i);
   5667             *member_id = i;
   5668             return BCM_E_NONE;
   5669         }
   5670     }
   5671 
   5672     return BCM_E_RESOURCE;
   5673 }
   5674 
   5675 /*
   5676  * Function:
   5677  *      _bcm_tr3_ecmp_dlb_member_id_free
   5678  * Purpose:
   5679  *      Free an ECMP DLB Member ID.
   5680  * Parameters:
   5681  *      unit - (IN) SOC unit number.
   5682  *      member_id - (IN) Member ID to be freed.
   5683  * Returns:
   5684  *      BCM_E_xxx
   5685  */
   5686 STATIC int
   5687 _bcm_tr3_ecmp_dlb_member_id_free(int unit, int member_id)
   5688 {
   5689     if (member_id < 0 || member_id > soc_mem_index_max(unit,
   5690                 DLB_ECMP_MEMBER_ATTRIBUTEm)) {
   5691         return BCM_E_PARAM;
   5692     }
   5693 
   5694     _BCM_ECMP_DLB_MEMBER_ID_USED_CLR(unit, member_id);
   5695 
   5696     return BCM_E_NONE;
   5697 }
   5698 
   5699 /*
   5700  * Function:
   5701  *      _bcm_tr3_ecmp_dlb_quality_assign
   5702  * Purpose:
   5703  *      Assign quality based on loading and queue size.
   5704  * Parameters:
   5705  *      unit - (IN)SOC unit number. 
   5706  *      tx_load_percent - (IN) Percent weight of loading in determing quality.
   5707  *                             The remaining percentage is the weight of queue
   5708  *                             size.
   5709  *      entry_arr - (IN) Array of 64 quality map table entries.
   5710  * Returns:
   5711  *      BCM_X_XXX
   5712  */
   5713 STATIC int 
   5714 _bcm_tr3_ecmp_dlb_quality_assign(int unit, int tx_load_percent,
   5715         uint32 *entry_arr)
   5716 {
   5717     int quantized_tx_load;
   5718     int quantized_qsize;
   5719     int quality;
   5720     int entry_index;
   5721 
   5722     if (entry_arr == NULL) {
   5723         return BCM_E_PARAM;
   5724     }
   5725 
   5726     for (quantized_tx_load = 0; quantized_tx_load < 8; quantized_tx_load++) {
   5727         for (quantized_qsize = 0; quantized_qsize < 8; quantized_qsize++) {
   5728             quality = (quantized_tx_load * tx_load_percent +
   5729                     quantized_qsize * (100 - tx_load_percent)) / 100;
   5730             entry_index = (quantized_tx_load << 3) + quantized_qsize;
   5731             soc_DLB_ECMP_QUALITY_MAPPINGm_field32_set(unit,
   5732                     &entry_arr[entry_index], QUALITYf, quality);
   5733         }
   5734     }
   5735 
   5736     return BCM_E_NONE;
   5737 }
   5738 
   5739 /*
   5740  * Function:
   5741  *      _bcm_tr3_ecmp_dlb_member_quality_map_set
   5742  * Purpose:
   5743  *      Set per-member ECMP DLB quality mapping table.
   5744  * Parameters:
   5745  *      unit - (IN) SOC unit number.
   5746  *      member_id - (IN) Member ID.
   5747  *      tx_load_percent - (IN) Percent weight of loading in determing quality.
   5748  *                             The remaining percentage is the weight of queue
   5749  *                             size.
   5750  * Returns:
   5751  *      BCM_E_xxx
   5752  */
   5753 STATIC int
   5754 _bcm_tr3_ecmp_dlb_member_quality_map_set(int unit, int member_id,
   5755         int tx_load_percent)
   5756 {
   5757     soc_profile_mem_t *profile;
   5758     soc_mem_t mem;
   5759     int entry_bytes;
   5760     int entries_per_profile;
   5761     int alloc_size;
   5762     uint32 *entry_arr;
   5763     int rv = BCM_E_NONE;
   5764     void *entries;
   5765     uint32 base_index;
   5766     uint32 old_base_index;
   5767     dlb_ecmp_quality_control_entry_t quality_control_entry;
   5768 
   5769     profile = ECMP_DLB_INFO(unit)->ecmp_dlb_quality_map_profile;
   5770 
   5771     entries_per_profile = 64;
   5772     entry_bytes = sizeof(dlb_ecmp_quality_mapping_entry_t);
   5773     alloc_size = entries_per_profile * entry_bytes;
   5774     entry_arr = sal_alloc(alloc_size, "ECMP DLB Quality Map entries");
   5775     if (entry_arr == NULL) {
   5776         return BCM_E_MEMORY;
   5777     }
   5778     sal_memset(entry_arr, 0, alloc_size);
   5779 
   5780     /* Assign quality in the entry array */
   5781     rv = _bcm_tr3_ecmp_dlb_quality_assign(unit, tx_load_percent, entry_arr);
   5782     if (BCM_FAILURE(rv)) {
   5783         sal_free(entry_arr);
   5784         return rv;
   5785     }
   5786 
   5787     mem = DLB_ECMP_QUALITY_MAPPINGm;
   5788     soc_mem_lock(unit, mem);
   5789 
   5790     /* Add profile */
   5791     entries = entry_arr;
   5792     rv = soc_profile_mem_add(unit, profile, &entries, entries_per_profile,
   5793             &base_index);
   5794     sal_free(entry_arr);
   5795     if (SOC_FAILURE(rv)) {
   5796         soc_mem_unlock(unit, mem);
   5797         return rv;
   5798     }
   5799 
   5800     /* Update member profile pointer */
   5801     rv = READ_DLB_ECMP_QUALITY_CONTROLm(unit, MEM_BLOCK_ANY, member_id,
   5802             &quality_control_entry);
   5803     if (SOC_FAILURE(rv)) {
   5804         soc_mem_unlock(unit, mem);
   5805         return rv;
   5806     }
   5807     old_base_index = entries_per_profile * soc_mem_field32_get(unit,
   5808             DLB_ECMP_QUALITY_CONTROLm, &quality_control_entry,
   5809             PROFILE_PTRf);
   5810     soc_DLB_ECMP_QUALITY_CONTROLm_field32_set(unit, &quality_control_entry, 
   5811             PROFILE_PTRf, base_index / entries_per_profile);
   5812     rv = WRITE_DLB_ECMP_QUALITY_CONTROLm(unit, MEM_BLOCK_ALL, member_id,
   5813             &quality_control_entry);
   5814     if (SOC_FAILURE(rv)) {
   5815         soc_mem_unlock(unit, mem);
   5816         return rv;
   5817     }
   5818 
   5819     /* Delete old profile */
   5820     rv = soc_profile_mem_delete(unit, profile, old_base_index);
   5821     soc_mem_unlock(unit, mem);
   5822 
   5823     ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[base_index/entries_per_profile] =
   5824         tx_load_percent;
   5825 
   5826     return rv;
   5827 }
   5828 
   5829 /*
   5830  * Function:
   5831  *      _bcm_tr3_ecmp_dlb_member_attr_set
   5832  * Purpose:
   5833  *      Set ECMP dynamic load balancing attributes for a member.
   5834  * Parameters:
   5835  *      unit      - (IN) SOC unit number.
   5836  *      member_id - (IN) Member ID.
   5837  *      nh_index  - (IN) Next hop index.
   5838  *      scaling_factor - (IN) Threshold scaling factor.
   5839  *      load_weight    - (IN) Weighting of load in determining member quality.
   5840  * Returns:
   5841  *      BCM_E_XXX
   5842  */
   5843 STATIC int
   5844 _bcm_tr3_ecmp_dlb_member_attr_set(int unit, int member_id, int nh_index,
   5845         int scaling_factor, int load_weight)
   5846 {
   5847     dlb_ecmp_quality_control_entry_t dlb_ecmp_quality_control_entry;
   5848     dlb_ecmp_member_attribute_entry_t dlb_ecmp_member_attr_entry;
   5849 
   5850     /* Set load weight */
   5851     BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_member_quality_map_set(unit,
   5852                     member_id, load_weight));
   5853 
   5854     /* Set scaling factor */
   5855     SOC_IF_ERROR_RETURN(READ_DLB_ECMP_QUALITY_CONTROLm(unit, MEM_BLOCK_ANY,
   5856                 member_id, &dlb_ecmp_quality_control_entry));
   5857     soc_DLB_ECMP_QUALITY_CONTROLm_field32_set(unit,
   5858             &dlb_ecmp_quality_control_entry, LOADING_SCALING_FACTORf,
   5859             scaling_factor);
   5860     soc_DLB_ECMP_QUALITY_CONTROLm_field32_set(unit,
   5861             &dlb_ecmp_quality_control_entry, QSIZE_SCALING_FACTORf,
   5862             scaling_factor);
   5863     SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_QUALITY_CONTROLm(unit, MEM_BLOCK_ALL,
   5864                 member_id, &dlb_ecmp_quality_control_entry));
   5865 
   5866     /* Set next hop index */
   5867     SOC_IF_ERROR_RETURN(READ_DLB_ECMP_MEMBER_ATTRIBUTEm(unit, MEM_BLOCK_ANY,
   5868                 member_id, &dlb_ecmp_member_attr_entry));
   5869     soc_DLB_ECMP_MEMBER_ATTRIBUTEm_field32_set(unit,
   5870             &dlb_ecmp_member_attr_entry, NEXT_HOP_INDEXf, nh_index);
   5871     SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_MEMBER_ATTRIBUTEm(unit, MEM_BLOCK_ALL,
   5872                 member_id, &dlb_ecmp_member_attr_entry));
   5873 
   5874     return BCM_E_NONE;
   5875 }
   5876 
   5877 /*
   5878  * Function:
   5879  *      _bcm_tr3_ecmp_dlb_member_attr_get
   5880  * Purpose:
   5881  *      Get ECMP dynamic load balancing attributes for a member.
   5882  * Parameters:
   5883  *      unit      - (IN) SOC unit number.
   5884  *      member_id - (IN) Member ID.
   5885  *      scaling_factor - (OUT) Threshold scaling factor.
   5886  *      load_weight    - (OUT) Weighting of load in determining member quality.
   5887  * Returns:
   5888  *      BCM_E_XXX
   5889  */
   5890 STATIC int
   5891 _bcm_tr3_ecmp_dlb_member_attr_get(int unit, int member_id, int *scaling_factor,
   5892         int *load_weight)
   5893 {
   5894     dlb_ecmp_quality_control_entry_t dlb_ecmp_quality_control_entry;
   5895     int profile_ptr;
   5896 
   5897     SOC_IF_ERROR_RETURN(READ_DLB_ECMP_QUALITY_CONTROLm(unit, MEM_BLOCK_ANY,
   5898                 member_id, &dlb_ecmp_quality_control_entry));
   5899 
   5900     /* Get load weight */
   5901     profile_ptr = soc_DLB_ECMP_QUALITY_CONTROLm_field32_get(unit,
   5902             &dlb_ecmp_quality_control_entry, PROFILE_PTRf);
   5903     *load_weight = ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[profile_ptr];
   5904 
   5905     /* Get scaling factor */
   5906     *scaling_factor = soc_DLB_ECMP_QUALITY_CONTROLm_field32_get(unit,
   5907             &dlb_ecmp_quality_control_entry, LOADING_SCALING_FACTORf);
   5908 
   5909     return BCM_E_NONE;
   5910 }
   5911 
   5912 /*
   5913  * Function:
   5914  *      bcm_tr3_l3_egress_dlb_attr_set
   5915  * Purpose:
   5916  *      Set ECMP dynamic load balancing attributes for a next hop index.
   5917  * Parameters:
   5918  *      unit     - (IN) SOC unit number.
   5919  *      nh_index - (IN) Next hop index.
   5920  *      egr      - (IN) L3 egress info.
   5921  * Returns:
   5922  *      BCM_E_XXX
   5923  */
   5924 int
   5925 bcm_tr3_l3_egress_dlb_attr_set(int unit, int nh_index, bcm_l3_egress_t *egr)
   5926 {
   5927     int rv = BCM_E_NONE;
   5928     int match, match_index;
   5929     int free_index_found, free_index;
   5930     int i;
   5931     _tr3_ecmp_dlb_nh_membership_t *membership, *current_ptr, *next_ptr;
   5932     int scaling_factor_invalid, load_weight_invalid;
   5933 
   5934     if (egr->dynamic_scaling_factor ==
   5935              BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID) {
   5936        scaling_factor_invalid = TRUE;
   5937     } else {
   5938        scaling_factor_invalid = FALSE;
   5939     }
   5940     if (egr->dynamic_load_weight ==
   5941              BCM_L3_ECMP_DYNAMIC_LOAD_WEIGHT_INVALID) {
   5942         load_weight_invalid = TRUE;
   5943     } else {
   5944         load_weight_invalid = FALSE;
   5945     }
   5946     if (scaling_factor_invalid != load_weight_invalid) {
   5947         /* The scaling factor and the load weight must be both invalid,
   5948          * or both valid.
   5949          */
   5950         return BCM_E_PARAM;
   5951     }
   5952 
   5953     /* Traverse ecmp_dlb_nh_info array to find the given nh_index */
   5954     match = FALSE;
   5955     match_index = 0;
   5956     free_index_found = FALSE;
   5957     free_index = 0;
   5958     for (i = 0; i < ECMP_DLB_INFO(unit)->ecmp_dlb_nh_info_size; i++) {
   5959         if (ECMP_DLB_NH_INFO(unit, i).valid) {
   5960             if (nh_index == ECMP_DLB_NH_INFO(unit, i).nh_index) {
   5961                 match = TRUE;
   5962                 match_index = i;
   5963             }
   5964         } else {
   5965             if (!free_index_found) {
   5966                 free_index_found = TRUE;
   5967                 free_index = i;
   5968             }
   5969         }
   5970     }
   5971 
   5972     if (match) {
   5973 
   5974         if ((egr->dynamic_scaling_factor ==
   5975                 BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID) &&
   5976             (egr->dynamic_load_weight ==
   5977                 BCM_L3_ECMP_DYNAMIC_LOAD_WEIGHT_INVALID)) {
   5978             /* Check that the given next hop index is currently not a member of
   5979              * any ECMP DLB group.
   5980              */
   5981             current_ptr = ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list;
   5982             while (NULL != current_ptr) {
   5983                 if (current_ptr->group != -1) {
   5984                     return BCM_E_BUSY;
   5985                 }
   5986                 current_ptr = current_ptr->next;
   5987             }
   5988 
   5989             /* Reset the DLB attributes, free member ID, free linked list */
   5990             current_ptr = ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list;
   5991             while (NULL != current_ptr) {
   5992                 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_member_attr_set(unit,
   5993                             current_ptr->member_id, 0, 0, 100));
   5994                 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_member_id_free(unit,
   5995                             current_ptr->member_id));
   5996                 next_ptr = current_ptr->next;
   5997                 sal_free(current_ptr);
   5998                 current_ptr = next_ptr;
   5999             }
   6000             ECMP_DLB_NH_INFO(unit, free_index).nh_membership_list = NULL;
   6001             ECMP_DLB_NH_INFO(unit, free_index).nh_index = 0;
   6002             ECMP_DLB_NH_INFO(unit, free_index).valid = 0;
   6003 
   6004         } else {
   6005             /* Traverse next hop index's linked list of DLB member IDs and
   6006              * update their DLB attributes.
   6007              */
   6008             current_ptr = ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list;
   6009             while (NULL != current_ptr) {
   6010                 BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_member_attr_set(unit,
   6011                             current_ptr->member_id, nh_index,
   6012                             egr->dynamic_scaling_factor,
   6013                             egr->dynamic_load_weight));
   6014                 current_ptr = current_ptr->next;
   6015             }
   6016         }
   6017 
   6018     } else { /* No match */
   6019 
   6020         if ((egr->dynamic_scaling_factor ==
   6021                  BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID) &&
   6022             (egr->dynamic_load_weight ==
   6023                  BCM_L3_ECMP_DYNAMIC_LOAD_WEIGHT_INVALID)) {
   6024             /* Nothing to do */
   6025             return BCM_E_NONE;
   6026         }
   6027 
   6028         if (!free_index_found) {
   6029             /* ecmp_dlb_nh_info array is full */
   6030             return BCM_E_FULL;
   6031         }
   6032 
   6033         /* Allocate a DLB member ID and set DLB attributes */
   6034         membership = sal_alloc(sizeof(_tr3_ecmp_dlb_nh_membership_t),
   6035                 "ecmp dlb nh membership");
   6036         if (NULL == membership) {
   6037             return BCM_E_MEMORY;
   6038         }
   6039         rv = _bcm_tr3_ecmp_dlb_member_id_alloc(unit, &membership->member_id);
   6040         if (BCM_FAILURE(rv)) {
   6041             sal_free(membership);
   6042             return rv;
   6043         }
   6044         rv = _bcm_tr3_ecmp_dlb_member_attr_set(unit, membership->member_id,
   6045                 nh_index, egr->dynamic_scaling_factor,
   6046                 egr->dynamic_load_weight);
   6047         if (BCM_FAILURE(rv)) {
   6048             sal_free(membership);
   6049             return rv;
   6050         }
   6051         membership->group = -1;
   6052         membership->next =
   6053             ECMP_DLB_NH_INFO(unit, free_index).nh_membership_list; 
   6054         ECMP_DLB_NH_INFO(unit, free_index).nh_membership_list = membership;
   6055         ECMP_DLB_NH_INFO(unit, free_index).nh_index = nh_index;
   6056         ECMP_DLB_NH_INFO(unit, free_index).valid = 1;
   6057     }
   6058 
   6059     return rv;
   6060 }
   6061 
   6062 /*
   6063  * Function:
   6064  *      bcm_tr3_l3_egress_dlb_attr_destroy
   6065  * Purpose:
   6066  *      Destroy ECMP dynamic load balancing attributes for a next hop index.
   6067  * Parameters:
   6068  *      unit     - (IN) SOC unit number.
   6069  *      nh_index - (IN) Next hop index.
   6070  * Returns:
   6071  *      BCM_E_XXX
   6072  */
   6073 int
   6074 bcm_tr3_l3_egress_dlb_attr_destroy(int unit, int nh_index)
   6075 {
   6076     int rv = BCM_E_NONE;
   6077     int match, match_index;
   6078     int i;
   6079     _tr3_ecmp_dlb_nh_membership_t *current_ptr, *next_ptr;
   6080 
   6081     /* Traverse ecmp_dlb_nh_info array to find the given nh_index */
   6082     match = FALSE;
   6083     match_index = 0;
   6084     for (i = 0; i < ECMP_DLB_INFO(unit)->ecmp_dlb_nh_info_size; i++) {
   6085         if (ECMP_DLB_NH_INFO(unit, i).valid) {
   6086             if (nh_index == ECMP_DLB_NH_INFO(unit, i).nh_index) {
   6087                 match = TRUE;
   6088                 match_index = i;
   6089                 break;
   6090             }
   6091         }
   6092     }
   6093 
   6094     if (match) {
   6095         /* Check that the given next hop index is currently not a member of
   6096          * any ECMP DLB group.
   6097          */
   6098         current_ptr = ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list;
   6099         while (NULL != current_ptr) {
   6100             if (current_ptr->group != -1) {
   6101                 return BCM_E_BUSY;
   6102             }
   6103             current_ptr = current_ptr->next;
   6104         }
   6105 
   6106         /* Reset the DLB attributes, free member ID, free linked list */
   6107         current_ptr = ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list;
   6108         while (NULL != current_ptr) {
   6109             BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_member_attr_set(unit,
   6110                         current_ptr->member_id, 0, 0, 100));
   6111             BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_member_id_free(unit,
   6112                         current_ptr->member_id));
   6113             next_ptr = current_ptr->next;
   6114             sal_free(current_ptr);
   6115             current_ptr = next_ptr;
   6116         }
   6117         ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list = NULL;
   6118         ECMP_DLB_NH_INFO(unit, match_index).nh_index = 0;
   6119         ECMP_DLB_NH_INFO(unit, match_index).valid = 0;
   6120     }
   6121 
   6122     return rv;
   6123 }
   6124 
   6125 /*
   6126  * Function:
   6127  *      bcm_tr3_l3_egress_dlb_attr_get
   6128  * Purpose:
   6129  *      Get ECMP dynamic load balancing attributes for a next hop index.
   6130  * Parameters:
   6131  *      unit     - (IN) SOC unit number.
   6132  *      nh_index - (IN) Next hop index.
   6133  *      egr      - (OUT) L3 egress info.
   6134  * Returns:
   6135  *      BCM_E_XXX
   6136  */
   6137 int
   6138 bcm_tr3_l3_egress_dlb_attr_get(int unit, int nh_index, bcm_l3_egress_t *egr)
   6139 {
   6140     int rv = BCM_E_NONE;
   6141     int match, match_index;
   6142     int i;
   6143     _tr3_ecmp_dlb_nh_membership_t *current_ptr;
   6144 
   6145     /* Traverse ecmp_dlb_nh_info array to find the given nh_index */
   6146     match = FALSE;
   6147     match_index = 0;
   6148     for (i = 0; i < ECMP_DLB_INFO(unit)->ecmp_dlb_nh_info_size; i++) {
   6149         if (ECMP_DLB_NH_INFO(unit, i).valid) {
   6150             if (nh_index == ECMP_DLB_NH_INFO(unit, i).nh_index) {
   6151                 match = TRUE;
   6152                 match_index = i;
   6153                 break;
   6154             }
   6155         }
   6156     }
   6157 
   6158     if (match) {
   6159         /* Get the DLB attributes */
   6160         current_ptr = ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list;
   6161         BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_member_attr_get(unit,
   6162                     current_ptr->member_id, &egr->dynamic_scaling_factor,
   6163                     &egr->dynamic_load_weight));
   6164     } else {
   6165         egr->dynamic_scaling_factor = BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID;
   6166         egr->dynamic_load_weight = BCM_L3_ECMP_DYNAMIC_LOAD_WEIGHT_INVALID;
   6167     }
   6168 
   6169     return rv;
   6170 }
   6171 
   6172 /*
   6173  * Function:
   6174  *      _bcm_tr3_ecmp_dlb_id_alloc
   6175  * Purpose:
   6176  *      Get a free ECMP DLB ID and mark it used.
   6177  * Parameters:
   6178  *      unit - (IN) SOC unit number.
   6179  *      dlb_id - (OUT) Allocated DLB ID.
   6180  * Returns:
   6181  *      BCM_E_xxx
   6182  */
   6183 STATIC int
   6184 _bcm_tr3_ecmp_dlb_id_alloc(int unit, int *dlb_id)
   6185 {
   6186     int i;
   6187 
   6188     for (i = 0; i < soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm); i++) {
   6189         if (!_BCM_ECMP_DLB_ID_USED_GET(unit, i)) {
   6190             _BCM_ECMP_DLB_ID_USED_SET(unit, i);
   6191             *dlb_id = i;
   6192             return BCM_E_NONE;
   6193         }
   6194     }
   6195 
   6196     return BCM_E_RESOURCE;
   6197 }
   6198 
   6199 /*
   6200  * Function:
   6201  *      _bcm_tr3_ecmp_dlb_id_free
   6202  * Purpose:
   6203  *      Free an ECMP DLB ID.
   6204  * Parameters:
   6205  *      unit - (IN) SOC unit number.
   6206  *      dlb_id - (IN) DLB ID to be freed.
   6207  * Returns:
   6208  *      BCM_E_xxx
   6209  */
   6210 STATIC int
   6211 _bcm_tr3_ecmp_dlb_id_free(int unit, int dlb_id)
   6212 {
   6213     if (dlb_id < 0 ||
   6214             dlb_id > soc_mem_index_max(unit, DLB_ECMP_GROUP_CONTROLm)) {
   6215         return BCM_E_PARAM;
   6216     }
   6217 
   6218     _BCM_ECMP_DLB_ID_USED_CLR(unit, dlb_id);
   6219 
   6220     return BCM_E_NONE;
   6221 }
   6222 
   6223 /*
   6224  * Function:
   6225  *      _bcm_tr3_ecmp_dlb_dynamic_size_encode
   6226  * Purpose:
   6227  *      Encode ECMP dynamic load balancing flow set size.
   6228  * Parameters:
   6229  *      dynamic_size - (IN) Number of flow sets.
   6230  *      encoded_value - (OUT) Encoded value.
   6231  * Returns:
   6232  *      BCM_E_xxx
   6233  */
   6234 STATIC int
   6235 _bcm_tr3_ecmp_dlb_dynamic_size_encode(int dynamic_size,
   6236         int *encoded_value)
   6237 {   
   6238     switch (dynamic_size) {
   6239         case 512:
   6240             *encoded_value = 1;
   6241             break;
   6242         case 1024:
   6243             *encoded_value = 2;
   6244             break;
   6245         case 2048:
   6246             *encoded_value = 3;
   6247             break;
   6248         case 4096:
   6249             *encoded_value = 4;
   6250             break;
   6251         case 8192:
   6252             *encoded_value = 5;
   6253             break;
   6254         case 16384:
   6255             *encoded_value = 6;
   6256             break;
   6257         case 32768:
   6258             *encoded_value = 7;
   6259             break;
   6260         default:
   6261             return BCM_E_PARAM;
   6262     }
   6263 
   6264     return BCM_E_NONE;
   6265 }
   6266 
   6267 /*
   6268  * Function:
   6269  *      _bcm_tr3_ecmp_dlb_dynamic_size_decode
   6270  * Purpose:
   6271  *      Decode ECMP dynamic load balancing flow set size.
   6272  * Parameters:
   6273  *      encoded_value - (IN) Encoded value.
   6274  *      dynamic_size - (OUT) Number of flow sets.
   6275  * Returns:
   6276  *      BCM_E_xxx
   6277  */
   6278 STATIC int
   6279 _bcm_tr3_ecmp_dlb_dynamic_size_decode(int encoded_value,
   6280         int *dynamic_size)
   6281 {   
   6282     switch (encoded_value) {
   6283         case 1:
   6284             *dynamic_size = 512;
   6285             break;
   6286         case 2:
   6287             *dynamic_size = 1024;
   6288             break;
   6289         case 3:
   6290             *dynamic_size = 2048;
   6291             break;
   6292         case 4:
   6293             *dynamic_size = 4096;
   6294             break;
   6295         case 5:
   6296             *dynamic_size = 8192;
   6297             break;
   6298         case 6:
   6299             *dynamic_size = 16384;
   6300             break;
   6301         case 7:
   6302             *dynamic_size = 32768;
   6303             break;
   6304         default:
   6305             return BCM_E_INTERNAL;
   6306     }
   6307 
   6308     return BCM_E_NONE;
   6309 }
   6310 
   6311 /*
   6312  * Function:
   6313  *      _bcm_tr3_ecmp_dlb_nh_membership_free_resource
   6314  * Purpose:
   6315  *      Free resources in ECMP DLB next hop membership.
   6316  * Parameters:
   6317  *      unit      - (IN) SOC unit number. 
   6318  *      nh_index  - (IN) Next hop index. 
   6319  *      member_id - (IN) ECMP DLB member ID. 
   6320  *      dlb_id    - (IN) ECMP DLB group ID. 
   6321  * Returns:
   6322  *      BCM_E_xxx
   6323  */
   6324 STATIC int
   6325 _bcm_tr3_ecmp_dlb_nh_membership_free_resource(int unit, int nh_index,
   6326         int member_id, int dlb_id)
   6327 {
   6328     int match, match_index;
   6329     int i;
   6330     int member_id_count;
   6331     _tr3_ecmp_dlb_nh_membership_t *current_ptr, *prev_ptr;
   6332     int member_match;
   6333 
   6334     /* Traverse ecmp_dlb_nh_info array to find the given nh_index */
   6335     match = FALSE;
   6336     match_index = 0;
   6337     for (i = 0; i < ECMP_DLB_INFO(unit)->ecmp_dlb_nh_info_size; i++) {
   6338         if (ECMP_DLB_NH_INFO(unit, i).valid) {
   6339             if (nh_index == ECMP_DLB_NH_INFO(unit, i).nh_index) {
   6340                 match = TRUE;
   6341                 match_index = i;
   6342                 break;
   6343             }
   6344         }
   6345     }
   6346     if (!match) {
   6347         return BCM_E_INTERNAL;
   6348     }
   6349 
   6350     /* Count the number of member IDs assigned to this next hop */
   6351     member_id_count = 0;
   6352     current_ptr = ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list;
   6353     while (NULL != current_ptr) {
   6354         member_id_count++;
   6355         current_ptr = current_ptr->next;
   6356     }
   6357 
   6358     if (0 == member_id_count) {
   6359         return BCM_E_INTERNAL;
   6360     }
   6361 
   6362     /* If there is only one member ID assigned to the next hop index,
   6363      * do not free the member ID, merely invalidate the group.
   6364      */
   6365     if (1 == member_id_count) {
   6366         current_ptr = ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list;
   6367         if ((current_ptr->member_id != member_id) ||
   6368             (current_ptr->group != dlb_id)) {
   6369            return BCM_E_INTERNAL;
   6370         } 
   6371         current_ptr->group = -1;
   6372         return BCM_E_NONE;
   6373     }
   6374 
   6375     /* If there are more than 1 member IDs assigned to the next hop index,
   6376      * free the given member ID.
   6377      */
   6378     prev_ptr = NULL;
   6379     current_ptr = ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list;
   6380     member_match = FALSE;
   6381     while (NULL != current_ptr) {
   6382         if ((current_ptr->member_id == member_id) &&
   6383                 (current_ptr->group == dlb_id)) {
   6384             if (NULL == prev_ptr) {
   6385                 ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list =
   6386                     current_ptr->next;
   6387             } else {
   6388                 prev_ptr->next = current_ptr->next;
   6389             }
   6390             sal_free(current_ptr);
   6391 
   6392             /* Reset member DLB attributes */
   6393             BCM_IF_ERROR_RETURN
   6394                 (_bcm_tr3_ecmp_dlb_member_attr_set(unit, member_id, 0, 0, 100));
   6395 
   6396             /* Free member ID */
   6397             BCM_IF_ERROR_RETURN
   6398                 (_bcm_tr3_ecmp_dlb_member_id_free(unit, member_id));
   6399 
   6400             member_match = TRUE;
   6401             break;
   6402         }
   6403         prev_ptr = current_ptr;
   6404         current_ptr = current_ptr->next;
   6405     }
   6406     if (!member_match) {
   6407         return BCM_E_INTERNAL;
   6408     }
   6409 
   6410     return BCM_E_NONE;
   6411 }
   6412 
   6413 /*
   6414  * Function:
   6415  *      _bcm_tr3_ecmp_dlb_free_resource
   6416  * Purpose:
   6417  *      Free resources for an ECMP dynamic load balancing group.
   6418  * Parameters:
   6419  *      unit   - (IN) SOC unit number. 
   6420  *      ecmp_group_idx - (IN) ECMP group index.
   6421  * Returns:
   6422  *      BCM_E_xxx
   6423  */
   6424 STATIC int
   6425 _bcm_tr3_ecmp_dlb_free_resource(int unit, int ecmp_group_idx)
   6426 {
   6427     int rv = BCM_E_NONE;
   6428     ecmp_count_entry_t ecmp_group_entry;
   6429     int dlb_enable;
   6430     int dlb_id;
   6431     dlb_ecmp_group_control_entry_t dlb_ecmp_group_control_entry;
   6432     int entry_base_ptr;
   6433     int flow_set_size;
   6434     int num_entries;
   6435     int block_base_ptr;
   6436     int num_blocks;
   6437     int vla;
   6438     dlb_ecmp_group_membership_entry_t dlb_ecmp_group_membership_entry;
   6439     int member_bitmap_width;
   6440     int alloc_size;
   6441     SHR_BITDCL *member_bitmap = NULL;
   6442     SHR_BITDCL *status_bitmap = NULL;
   6443     SHR_BITDCL *override_bitmap = NULL;
   6444     int i;
   6445     int reverse_map_index;
   6446     dlb_ecmp_member_attribute_entry_t dlb_ecmp_member_attribute_entry;
   6447     ing_l3_next_hop_entry_t ing_nh_entry;
   6448     int nh_index;
   6449     bcm_module_t mod;
   6450     bcm_port_t port;
   6451     int is_local;
   6452     dlb_ecmp_member_sw_state_entry_t dlb_ecmp_member_sw_state_entry;
   6453 
   6454     SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY,
   6455                 ecmp_group_idx, &ecmp_group_entry));
   6456     dlb_enable = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_group_entry,
   6457             GROUP_ENABLEf);
   6458     dlb_id = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_group_entry,
   6459             DLB_IDf);
   6460     if (!dlb_enable) {
   6461         return BCM_E_NONE;
   6462     }
   6463 
   6464     /* Clear DLB fields in ECMP group table */
   6465     soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_group_entry, GROUP_ENABLEf, 0);
   6466     soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_group_entry, DLB_IDf, 0);
   6467     SOC_IF_ERROR_RETURN(WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL,
   6468                 ecmp_group_idx, &ecmp_group_entry));
   6469 
   6470     /* Clear VLA quality measure control */
   6471     SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm(unit,
   6472                 MEM_BLOCK_ALL, dlb_id,
   6473                 soc_mem_entry_null(unit,
   6474                     DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm)));
   6475 
   6476     /* Free flow set table resources */
   6477     SOC_IF_ERROR_RETURN
   6478         (READ_DLB_ECMP_GROUP_CONTROLm(unit, MEM_BLOCK_ANY, dlb_id,
   6479                                      &dlb_ecmp_group_control_entry));
   6480     entry_base_ptr = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   6481             &dlb_ecmp_group_control_entry, FLOW_SET_BASEf);
   6482     flow_set_size = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   6483             &dlb_ecmp_group_control_entry, FLOW_SET_SIZEf);
   6484     BCM_IF_ERROR_RETURN
   6485         (_bcm_tr3_ecmp_dlb_dynamic_size_decode(flow_set_size, &num_entries));
   6486     block_base_ptr = entry_base_ptr >> 9;
   6487     num_blocks = num_entries >> 9; 
   6488     _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_CLR_RANGE(unit, block_base_ptr, num_blocks);
   6489 
   6490     /* Clear ECMP DLB group control */
   6491     SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_GROUP_CONTROLm(unit,
   6492                 MEM_BLOCK_ALL, dlb_id,
   6493                 soc_mem_entry_null(unit, DLB_ECMP_GROUP_CONTROLm)));
   6494 
   6495     /* Get member bitmap */
   6496     BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit,
   6497                 bcmSwitchEcmpDynamicAccountingSelect, &vla));
   6498     SOC_IF_ERROR_RETURN(READ_DLB_ECMP_GROUP_MEMBERSHIPm(unit, MEM_BLOCK_ANY,
   6499                 dlb_id, &dlb_ecmp_group_membership_entry));
   6500     member_bitmap_width = soc_mem_field_length(unit,
   6501             DLB_ECMP_GROUP_MEMBERSHIPm, MEMBER_BITMAPf);
   6502     alloc_size = SHR_BITALLOCSIZE(member_bitmap_width);
   6503     member_bitmap = sal_alloc(alloc_size, "DLB ECMP member bitmap"); 
   6504     if (NULL == member_bitmap) {
   6505         return BCM_E_MEMORY;
   6506     }
   6507     sal_memset(member_bitmap, 0, alloc_size);
   6508     soc_DLB_ECMP_GROUP_MEMBERSHIPm_field_get(unit,
   6509             &dlb_ecmp_group_membership_entry, MEMBER_BITMAPf, member_bitmap);
   6510 
   6511     /* Free Member IDs */
   6512     for (i = 0; i < member_bitmap_width; i++) {
   6513         if (SHR_BITGET(member_bitmap, i)) {
   6514 
   6515             /* Clear membership reverse map */
   6516             rv = READ_DLB_ECMP_MEMBER_ATTRIBUTEm(unit, MEM_BLOCK_ANY, i,
   6517                     &dlb_ecmp_member_attribute_entry); 
   6518             if (BCM_FAILURE(rv)) {
   6519                 goto error;
   6520             }
   6521             nh_index = soc_DLB_ECMP_MEMBER_ATTRIBUTEm_field32_get(unit,
   6522                     &dlb_ecmp_member_attribute_entry, NEXT_HOP_INDEXf);
   6523             if (vla) {
   6524                 reverse_map_index = i;
   6525             } else {
   6526                 rv = READ_ING_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY, nh_index,
   6527                         &ing_nh_entry);
   6528                 if (BCM_FAILURE(rv)) {
   6529                     goto error;
   6530                 }
   6531                 mod = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry,
   6532                         MODULE_IDf);
   6533                 port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry,
   6534                         PORT_NUMf);
   6535                 rv = _bcm_esw_modid_is_local(unit, mod, &is_local);
   6536                 if (BCM_FAILURE(rv)) {
   6537                     goto error;
   6538                 }
   6539                 if (!is_local) {
   6540                     rv = BCM_E_INTERNAL;
   6541                     goto error;
   6542                 }
   6543                 reverse_map_index = port;
   6544             }
   6545             rv = WRITE_DLB_ECMP_MEMBERSHIP_REVERSE_MAPm(unit, MEM_BLOCK_ALL,
   6546                     reverse_map_index, soc_mem_entry_null(unit,
   6547                         DLB_ECMP_MEMBERSHIP_REVERSE_MAPm));
   6548             if (BCM_FAILURE(rv)) {
   6549                 goto error;
   6550             }
   6551 
   6552             /* Free next hop membership resource */
   6553             rv = _bcm_tr3_ecmp_dlb_nh_membership_free_resource(unit, nh_index,
   6554                     i, dlb_id);
   6555             if (BCM_FAILURE(rv)) {
   6556                 goto error;
   6557             }
   6558         }
   6559     }
   6560 
   6561     rv = READ_DLB_ECMP_MEMBER_SW_STATEm(unit, MEM_BLOCK_ANY, 0,
   6562                 &dlb_ecmp_member_sw_state_entry);
   6563     if (BCM_FAILURE(rv)) {
   6564         goto error;
   6565     }
   6566 
   6567     /* Clear software status bitmap */
   6568     status_bitmap = sal_alloc(alloc_size, "DLB ECMP member status bitmap"); 
   6569     if (NULL == status_bitmap) {
   6570         rv = BCM_E_MEMORY;
   6571         goto error;
   6572     }
   6573     soc_DLB_ECMP_MEMBER_SW_STATEm_field_get(unit,
   6574             &dlb_ecmp_member_sw_state_entry, MEMBER_BITMAPf, status_bitmap);
   6575     SHR_BITREMOVE_RANGE(status_bitmap, member_bitmap, 0, member_bitmap_width,
   6576             status_bitmap);
   6577     soc_DLB_ECMP_MEMBER_SW_STATEm_field_set(unit,
   6578             &dlb_ecmp_member_sw_state_entry, MEMBER_BITMAPf, status_bitmap);
   6579 
   6580     /* Clear software override bitmap */
   6581     override_bitmap = sal_alloc(alloc_size, "DLB ECMP member override bitmap"); 
   6582     if (NULL == override_bitmap) {
   6583         rv = BCM_E_MEMORY;
   6584         goto error;
   6585     }
   6586     soc_DLB_ECMP_MEMBER_SW_STATEm_field_get(unit,
   6587             &dlb_ecmp_member_sw_state_entry, OVERRIDE_MEMBER_BITMAPf,
   6588             override_bitmap);
   6589     SHR_BITREMOVE_RANGE(override_bitmap, member_bitmap, 0, member_bitmap_width,
   6590             override_bitmap);
   6591     soc_DLB_ECMP_MEMBER_SW_STATEm_field_set(unit,
   6592             &dlb_ecmp_member_sw_state_entry, OVERRIDE_MEMBER_BITMAPf,
   6593             override_bitmap);
   6594     rv = WRITE_DLB_ECMP_MEMBER_SW_STATEm(unit, MEM_BLOCK_ALL, 0,
   6595                 &dlb_ecmp_member_sw_state_entry);
   6596     if (BCM_FAILURE(rv)) {
   6597         goto error;
   6598     }
   6599 
   6600     sal_free(member_bitmap);
   6601     sal_free(status_bitmap);
   6602     sal_free(override_bitmap);
   6603 
   6604     /* Clear group membership */
   6605     SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_GROUP_MEMBERSHIPm(unit,
   6606                 MEM_BLOCK_ALL, dlb_id,
   6607                 soc_mem_entry_null(unit, DLB_ECMP_GROUP_MEMBERSHIPm)));
   6608 
   6609     /* Free DLB ID */
   6610     BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_id_free(unit, dlb_id));
   6611 
   6612     return rv;
   6613 
   6614 error:
   6615     if (NULL != member_bitmap) {
   6616         sal_free(member_bitmap);
   6617     }
   6618     if (NULL != status_bitmap) {
   6619         sal_free(status_bitmap);
   6620     }
   6621     if (NULL != override_bitmap) {
   6622         sal_free(override_bitmap);
   6623     }
   6624     return rv;
   6625 }
   6626 
   6627 /*
   6628  * Function:
   6629  *      _bcm_tr3_ecmp_dlb_member_id_array_get
   6630  * Purpose:
   6631  *      Get member IDs for each ECMP member.
   6632  * Parameters:
   6633  *      unit   - (IN) SOC unit number. 
   6634  *      dlb_id - (IN) DLB group ID.
   6635  *      intf_count - (IN) Number of elements in intf_array.
   6636  *      intf_array - (IN) Array of Egress forwarding objects.
   6637  *      member_id_array - (OUT) Array of member IDs.
   6638  * Returns:
   6639  *      BCM_E_xxx
   6640  */
   6641 STATIC int
   6642 _bcm_tr3_ecmp_dlb_member_id_array_get(int unit, int dlb_id, int intf_count,
   6643         bcm_if_t *intf_array, int *member_id_array)
   6644 {
   6645     int rv = BCM_E_NONE;
   6646     int vla;
   6647     int i, j;
   6648     int nh_index;
   6649     int match, match_index;
   6650     _tr3_ecmp_dlb_nh_membership_t *current_ptr, *membership;
   6651     int existing_member_id;
   6652     dlb_ecmp_membership_reverse_map_entry_t member_reverse_map_entry;
   6653     ing_l3_next_hop_entry_t ing_nh_entry;
   6654     int mod, port;
   6655     int is_local;
   6656     port_tab_entry_t ptab;
   6657     int scaling_factor, load_weight;
   6658 
   6659     BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit,
   6660                         bcmSwitchEcmpDynamicAccountingSelect, &vla));
   6661 
   6662     for (i = 0; i < intf_count; i++) {
   6663         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf_array[i])) {
   6664             nh_index = intf_array[i] - BCM_XGS3_EGRESS_IDX_MIN(unit);
   6665         } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf_array[i])) {
   6666             nh_index = intf_array[i] - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   6667         } else {
   6668             return BCM_E_PARAM;
   6669         }
   6670 
   6671         /* Check if DLB attributes have been set for next hop index */
   6672         match = FALSE;
   6673         match_index = 0;
   6674         for (j = 0; j < ECMP_DLB_INFO(unit)->ecmp_dlb_nh_info_size; j++) {
   6675             if (ECMP_DLB_NH_INFO(unit, j).valid) {
   6676                 if (nh_index == ECMP_DLB_NH_INFO(unit, j).nh_index) {
   6677                     match = TRUE;
   6678                     match_index = j;
   6679                 }
   6680             }
   6681         }
   6682         if (!match) {
   6683             /* User did not configure DLB attributes for this next hop index */
   6684             return BCM_E_CONFIG;
   6685         }
   6686 
   6687         /* Look into next hop membership to see if a member ID has already
   6688          * been assigned that does not yet belong to any group.
   6689          */
   6690         current_ptr = ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list;
   6691         existing_member_id = -1;
   6692         while (NULL != current_ptr) {
   6693             if (-1 == current_ptr->group) {
   6694                 member_id_array[i] = current_ptr->member_id;
   6695                 current_ptr->group = dlb_id;
   6696                 break;
   6697             } else {
   6698                 if (-1 == existing_member_id) {
   6699                     existing_member_id = current_ptr->member_id;
   6700                 }
   6701             }
   6702             current_ptr = current_ptr->next;
   6703         }
   6704 
   6705         /* If no available member ID was found, allocate a new DLB member ID,
   6706          * set its DLB attributes, and insert it into next hop's linked list
   6707          * of member IDs.
   6708          */
   6709         if (NULL == current_ptr) {
   6710             membership = sal_alloc(sizeof(_tr3_ecmp_dlb_nh_membership_t),
   6711                     "ecmp dlb nh membership");
   6712             if (NULL == membership) {
   6713                 return BCM_E_MEMORY;
   6714             }
   6715             rv = _bcm_tr3_ecmp_dlb_member_id_alloc(unit, &membership->member_id);
   6716             if (BCM_FAILURE(rv)) {
   6717                 sal_free(membership);
   6718                 return rv;
   6719             }
   6720             rv = _bcm_tr3_ecmp_dlb_member_attr_get(unit, existing_member_id,
   6721                     &scaling_factor, &load_weight);
   6722             if (BCM_FAILURE(rv)) {
   6723                 sal_free(membership);
   6724                 return rv;
   6725             }
   6726             rv = _bcm_tr3_ecmp_dlb_member_attr_set(unit, membership->member_id,
   6727                     nh_index, scaling_factor, load_weight);
   6728             if (BCM_FAILURE(rv)) {
   6729                 sal_free(membership);
   6730                 return rv;
   6731             }
   6732             membership->group = dlb_id;
   6733             membership->next =
   6734                 ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list; 
   6735             ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list = membership;
   6736             ECMP_DLB_NH_INFO(unit, match_index).nh_index = nh_index;
   6737             ECMP_DLB_NH_INFO(unit, match_index).valid = 1;
   6738 
   6739             member_id_array[i] = membership->member_id;
   6740         }
   6741 
   6742         /* Set member reverse map */
   6743         sal_memset(&member_reverse_map_entry, 0,
   6744                 sizeof(dlb_ecmp_membership_reverse_map_entry_t));
   6745         if (vla) { /* Virtual link accounting */
   6746             soc_DLB_ECMP_MEMBERSHIP_REVERSE_MAPm_field32_set(unit,
   6747                     &member_reverse_map_entry, VALIDf, 1);
   6748             soc_DLB_ECMP_MEMBERSHIP_REVERSE_MAPm_field32_set(unit,
   6749                     &member_reverse_map_entry, GROUP_IDf, dlb_id);
   6750             soc_DLB_ECMP_MEMBERSHIP_REVERSE_MAPm_field32_set(unit,
   6751                     &member_reverse_map_entry, MEMBER_COUNTf,
   6752                     intf_count - 1);
   6753             SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_MEMBERSHIP_REVERSE_MAPm(unit,
   6754                     MEM_BLOCK_ALL, member_id_array[i],
   6755                     &member_reverse_map_entry));
   6756         } else { /* Physical link accounting */
   6757             SOC_IF_ERROR_RETURN(READ_ING_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY,
   6758                         nh_index, &ing_nh_entry));
   6759             if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, Tf)) {
   6760                 /* In physical link accounting mode, each next hop should
   6761                  * correspond to a single physical port.
   6762                  */
   6763                 return BCM_E_CONFIG;
   6764             }
   6765             mod = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry,
   6766                     MODULE_IDf);
   6767             port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry,
   6768                     PORT_NUMf);
   6769             BCM_IF_ERROR_RETURN(_bcm_esw_modid_is_local(unit, mod, &is_local));
   6770             if (!is_local) {
   6771                 /* In physical link accounting mode, ECMP members should be
   6772                  * local.
   6773                  */
   6774                 return BCM_E_PARAM;
   6775             }
   6776             soc_DLB_ECMP_MEMBERSHIP_REVERSE_MAPm_field32_set(unit,
   6777                     &member_reverse_map_entry, VALIDf, 1);
   6778             soc_DLB_ECMP_MEMBERSHIP_REVERSE_MAPm_field32_set(unit,
   6779                     &member_reverse_map_entry,
   6780                     MEMBER_IDf, member_id_array[i]);
   6781             SOC_IF_ERROR_RETURN
   6782                 (READ_PORT_TABm(unit, MEM_BLOCK_ANY, port, &ptab));
   6783             if (soc_PORT_TABm_field32_get(unit, &ptab, PORT_TYPEf) == 3) {
   6784                 /* Port is an embedded Higig port */
   6785                 soc_DLB_ECMP_MEMBERSHIP_REVERSE_MAPm_field32_set(unit,
   6786                         &member_reverse_map_entry, EMBEDDED_HGf, 1);
   6787             }
   6788             SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_MEMBERSHIP_REVERSE_MAPm(unit,
   6789                         MEM_BLOCK_ALL, port, &member_reverse_map_entry));
   6790         }
   6791     }
   6792 
   6793     return rv;
   6794 }
   6795 
   6796 /*
   6797  * Function:
   6798  *      _bcm_tr3_ecmp_dlb_set
   6799  * Purpose:
   6800  *      Configure an ECMP dynamic load balancing group.
   6801  * Parameters:
   6802  *      unit       - (IN) bcm device.
   6803  *      ecmp       - (IN) ECMP group info.
   6804  *      intf_count - (IN) Number of elements in intf_array.
   6805  *      intf_array - (IN) Array of Egress forwarding objects.
   6806  * Returns:
   6807  *      BCM_E_xxx
   6808  */
   6809 STATIC int
   6810 _bcm_tr3_ecmp_dlb_set(int unit, bcm_l3_egress_ecmp_t *ecmp,
   6811             int intf_count, bcm_if_t *intf_array)
   6812 {
   6813     int rv = BCM_E_NONE;
   6814     int dlb_id;
   6815     int *member_id_array = NULL;
   6816     soc_mem_t flowset_mem;
   6817     int flowset_entry_size;
   6818     dlb_ecmp_flowset_entry_t *flowset_entry;
   6819     int num_blocks;
   6820     int total_blocks;
   6821     int max_block_base_ptr;
   6822     int block_base_ptr;
   6823     SHR_BITDCL occupied;
   6824     int entry_base_ptr;
   6825     int num_entries_per_block;
   6826     int member_bitmap_width;
   6827     int alloc_size;
   6828     uint32 *block_ptr = NULL;
   6829     int i, k;
   6830     int index_min, index_max;
   6831     dlb_ecmp_group_control_entry_t dlb_ecmp_group_control_entry;
   6832     int flow_set_size;
   6833     int dlb_mode;
   6834     dlb_ecmp_group_membership_entry_t dlb_ecmp_group_membership_entry;
   6835     SHR_BITDCL *member_bitmap = NULL;
   6836     SHR_BITDCL *status_bitmap = NULL;
   6837     SHR_BITDCL *override_bitmap = NULL;
   6838     dlb_ecmp_member_sw_state_entry_t dlb_ecmp_member_sw_state_entry;
   6839     int vla;
   6840     dlb_ecmp_vla_quality_measure_control_entry_t vla_quality_measure_control_entry;
   6841     int ecmp_group_idx;
   6842     ecmp_count_entry_t ecmp_group_entry;
   6843 
   6844     /* Allocate a DLB ID */
   6845     BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_id_alloc(unit, &dlb_id));
   6846 
   6847     /* Allocate member IDs */
   6848     member_id_array = sal_alloc(sizeof(int) * intf_count,
   6849             "ECMP DLB Member IDs");
   6850     if (NULL == member_id_array) {
   6851         rv = BCM_E_MEMORY;
   6852         goto error;
   6853     }
   6854     rv = _bcm_tr3_ecmp_dlb_member_id_array_get(unit, dlb_id, intf_count,
   6855             intf_array, member_id_array);
   6856     if (BCM_FAILURE(rv)) {
   6857         goto error;
   6858     }
   6859 
   6860     /* Set group membership table */
   6861     member_bitmap_width = soc_mem_field_length(unit,
   6862             DLB_ECMP_GROUP_MEMBERSHIPm, MEMBER_BITMAPf);
   6863     alloc_size = SHR_BITALLOCSIZE(member_bitmap_width);
   6864     member_bitmap = sal_alloc(alloc_size, "DLB ECMP member bitmap"); 
   6865     if (NULL == member_bitmap) {
   6866         rv = BCM_E_MEMORY;
   6867         goto error;
   6868     }
   6869     sal_memset(member_bitmap, 0, alloc_size);
   6870     for (i = 0; i < intf_count; i++) {
   6871         SHR_BITSET(member_bitmap, member_id_array[i]);
   6872     }
   6873     sal_memset(&dlb_ecmp_group_membership_entry, 0,
   6874             sizeof(dlb_ecmp_group_membership_entry_t));
   6875     soc_DLB_ECMP_GROUP_MEMBERSHIPm_field_set(unit,
   6876             &dlb_ecmp_group_membership_entry, MEMBER_BITMAPf, member_bitmap);
   6877     rv = WRITE_DLB_ECMP_GROUP_MEMBERSHIPm(unit, MEM_BLOCK_ALL, dlb_id,
   6878             &dlb_ecmp_group_membership_entry);
   6879     if (SOC_FAILURE(rv)) {
   6880         goto error;
   6881     }
   6882 
   6883     /* Get software status bitmap */
   6884     rv = READ_DLB_ECMP_MEMBER_SW_STATEm(unit, MEM_BLOCK_ANY, 0,
   6885                 &dlb_ecmp_member_sw_state_entry);
   6886     if (BCM_FAILURE(rv)) {
   6887         goto error;
   6888     }
   6889     status_bitmap = sal_alloc(alloc_size, "DLB ECMP member status bitmap"); 
   6890     if (NULL == status_bitmap) {
   6891         rv = BCM_E_MEMORY;
   6892         goto error;
   6893     }
   6894     soc_DLB_ECMP_MEMBER_SW_STATEm_field_get(unit,
   6895             &dlb_ecmp_member_sw_state_entry, MEMBER_BITMAPf, status_bitmap);
   6896 
   6897     /* Set software status bitmap */
   6898     rv = bcm_esw_switch_control_get(unit,
   6899             bcmSwitchEcmpDynamicAccountingSelect, &vla);
   6900     if (SOC_FAILURE(rv)) {
   6901         goto error;
   6902     }
   6903     if (vla) {
   6904         SHR_BITOR_RANGE(status_bitmap, member_bitmap, 0, member_bitmap_width,
   6905                 status_bitmap);
   6906     } else {
   6907         SHR_BITREMOVE_RANGE(status_bitmap, member_bitmap, 0, member_bitmap_width,
   6908                 status_bitmap);
   6909     }
   6910     soc_DLB_ECMP_MEMBER_SW_STATEm_field_set(unit,
   6911             &dlb_ecmp_member_sw_state_entry, MEMBER_BITMAPf, status_bitmap);
   6912 
   6913     /* Set software override bitmap */
   6914     override_bitmap = sal_alloc(alloc_size, "DLB ECMP member override bitmap"); 
   6915     if (NULL == override_bitmap) {
   6916         rv = BCM_E_MEMORY;
   6917         goto error;
   6918     }
   6919     soc_DLB_ECMP_MEMBER_SW_STATEm_field_get(unit,
   6920             &dlb_ecmp_member_sw_state_entry, OVERRIDE_MEMBER_BITMAPf,
   6921             override_bitmap);
   6922     if (vla) {
   6923         SHR_BITOR_RANGE(override_bitmap, member_bitmap, 0, member_bitmap_width,
   6924                 override_bitmap);
   6925     } else {
   6926         SHR_BITREMOVE_RANGE(override_bitmap, member_bitmap, 0, member_bitmap_width,
   6927                 override_bitmap);
   6928     }
   6929     soc_DLB_ECMP_MEMBER_SW_STATEm_field_set(unit,
   6930             &dlb_ecmp_member_sw_state_entry, OVERRIDE_MEMBER_BITMAPf,
   6931             override_bitmap);
   6932     rv = WRITE_DLB_ECMP_MEMBER_SW_STATEm(unit, MEM_BLOCK_ALL, 0,
   6933                 &dlb_ecmp_member_sw_state_entry);
   6934     if (BCM_FAILURE(rv)) {
   6935         goto error;
   6936     }
   6937 
   6938     /* Find a contiguous region in flow set table */
   6939     flowset_mem = DLB_ECMP_FLOWSETm;
   6940     flowset_entry_size = sizeof(dlb_ecmp_flowset_entry_t);
   6941     num_blocks = ecmp->dynamic_size >> 9;
   6942     total_blocks = soc_mem_index_count(unit, flowset_mem) >> 9;
   6943     max_block_base_ptr = total_blocks - num_blocks;
   6944     for (block_base_ptr = 0;
   6945             block_base_ptr <= max_block_base_ptr;
   6946             block_base_ptr++) {
   6947         /* Check if the contiguous region of flow set table from
   6948          * block_base_ptr to (block_base_ptr + num_blocks - 1) is free. 
   6949          */
   6950         _BCM_ECMP_DLB_FLOWSET_BLOCK_TEST_RANGE(unit, block_base_ptr, num_blocks,
   6951                 occupied); 
   6952         if (!occupied) {
   6953             break;
   6954         }
   6955     }
   6956     if (block_base_ptr > max_block_base_ptr) {
   6957         /* A contiguous region of the desired size could not be found in
   6958          * flow set table.
   6959          */
   6960         rv = BCM_E_RESOURCE;
   6961         goto error;
   6962     }
   6963 
   6964     /* Set DLB flow set table */
   6965     entry_base_ptr = block_base_ptr << 9;
   6966     num_entries_per_block = 512;
   6967     alloc_size = num_entries_per_block * flowset_entry_size;
   6968     block_ptr = soc_cm_salloc(unit, alloc_size,
   6969             "Block of DLB_ECMP_FLOWSET entries");
   6970     if (NULL == block_ptr) {
   6971         rv = BCM_E_MEMORY;
   6972         goto error;
   6973     }
   6974     sal_memset(block_ptr, 0, alloc_size);
   6975     for (i = 0; i < num_blocks; i++) {
   6976         for (k = 0; k < num_entries_per_block; k++) {
   6977             flowset_entry = soc_mem_table_idx_to_pointer(unit,
   6978                     DLB_ECMP_FLOWSETm, dlb_ecmp_flowset_entry_t *,
   6979                     block_ptr, k);
   6980             if (intf_count > 0) {
   6981                 soc_DLB_ECMP_FLOWSETm_field32_set(unit, flowset_entry,
   6982                         VALIDf, 1);
   6983                 soc_DLB_ECMP_FLOWSETm_field32_set(unit, flowset_entry,
   6984                         MEMBER_IDf,
   6985                         member_id_array[(i * num_entries_per_block + k) %
   6986                         intf_count]);
   6987             } else {
   6988                 soc_DLB_ECMP_FLOWSETm_field32_set(unit, flowset_entry,
   6989                         VALIDf, 0);
   6990             }
   6991         }
   6992         index_min = entry_base_ptr + i * num_entries_per_block;
   6993         index_max = index_min + num_entries_per_block - 1;
   6994         rv = soc_mem_write_range(unit, flowset_mem, MEM_BLOCK_ALL,
   6995                 index_min, index_max, block_ptr);
   6996         if (SOC_FAILURE(rv)) {
   6997             goto error;
   6998         }
   6999     }
   7000     _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr, num_blocks);
   7001 
   7002     /* Set ECMP DLB group control table */
   7003     sal_memset(&dlb_ecmp_group_control_entry, 0,
   7004             sizeof(dlb_ecmp_group_control_entry_t));
   7005     soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry,
   7006             ENABLE_OPTIMAL_CANDIDATE_UPDATEf, 1);
   7007     soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry,
   7008             FLOW_SET_BASEf, entry_base_ptr);
   7009     rv = _bcm_tr3_ecmp_dlb_dynamic_size_encode(ecmp->dynamic_size,
   7010             &flow_set_size);
   7011     if (SOC_FAILURE(rv)) {
   7012         goto error;
   7013     }
   7014     soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry,
   7015             FLOW_SET_SIZEf, flow_set_size);
   7016     switch (ecmp->dynamic_mode) {
   7017         case BCM_L3_ECMP_DYNAMIC_MODE_NORMAL:
   7018             dlb_mode = 0;
   7019             break;
   7020         case BCM_L3_ECMP_DYNAMIC_MODE_ASSIGNED:
   7021             dlb_mode = 1;
   7022             break;
   7023         case BCM_L3_ECMP_DYNAMIC_MODE_OPTIMAL:
   7024             dlb_mode = 2;
   7025             break;
   7026         default:
   7027             rv = BCM_E_PARAM;
   7028             goto error;
   7029     }
   7030     soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry,
   7031             MEMBER_ASSIGNMENT_MODEf, dlb_mode);
   7032     soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry,
   7033             INACTIVITY_DURATIONf, ecmp->dynamic_age);
   7034     rv = WRITE_DLB_ECMP_GROUP_CONTROLm(unit, MEM_BLOCK_ALL, dlb_id,
   7035             &dlb_ecmp_group_control_entry);
   7036     if (SOC_FAILURE(rv)) {
   7037         goto error;
   7038     }
   7039 
   7040     /* Set VLA quality measure control */
   7041     if (vla) {
   7042         sal_memset(&vla_quality_measure_control_entry, 0,
   7043                 sizeof(dlb_ecmp_vla_quality_measure_control_entry_t));
   7044         soc_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm_field32_set(unit,
   7045                 &vla_quality_measure_control_entry,
   7046                 ENABLE_GROUP_AVG_CALCf, 1);
   7047         soc_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm_field32_set(unit,
   7048                 &vla_quality_measure_control_entry,
   7049                 VLA_WEIGHT_LOADINGf, ecmp->dynamic_load_exponent);
   7050         soc_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm_field32_set(unit,
   7051                 &vla_quality_measure_control_entry,
   7052                 VLA_WEIGHT_EXPECTED_LOADINGf,
   7053                 ecmp->dynamic_expected_load_exponent);
   7054         soc_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm_field32_set(unit,
   7055                 &vla_quality_measure_control_entry,
   7056                 VLA_CAP_LOADING_AVGf, (ecmp->ecmp_group_flags &
   7057                     BCM_L3_ECMP_DYNAMIC_LOAD_DECREASE_RESET) ? 1 : 0);
   7058         soc_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm_field32_set(unit,
   7059                 &vla_quality_measure_control_entry,
   7060                 VLA_CAP_EXPECTED_LOADINGf, (ecmp->ecmp_group_flags &
   7061                     BCM_L3_ECMP_DYNAMIC_EXPECTED_LOAD_DECREASE_RESET) ?
   7062                 1 : 0);
   7063         rv = WRITE_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm(unit, MEM_BLOCK_ALL,
   7064                 dlb_id, &vla_quality_measure_control_entry);
   7065         if (SOC_FAILURE(rv)) {
   7066             goto error;
   7067         }
   7068     }
   7069 
   7070     /* Update ECMP group table */
   7071     ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   7072     rv = READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group_idx,
   7073             &ecmp_group_entry);
   7074     if (SOC_FAILURE(rv)) {
   7075         goto error;
   7076     }
   7077     soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_group_entry, GROUP_ENABLEf, 1);
   7078     soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_group_entry, DLB_IDf, dlb_id);
   7079     rv = WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL, ecmp_group_idx,
   7080             &ecmp_group_entry);
   7081     if (SOC_FAILURE(rv)) {
   7082         goto error;
   7083     }
   7084 
   7085     sal_free(member_id_array);
   7086     soc_cm_sfree(unit, block_ptr);
   7087     sal_free(member_bitmap);
   7088     sal_free(status_bitmap);
   7089     sal_free(override_bitmap);
   7090 
   7091     return rv;
   7092 
   7093 error:
   7094     if (NULL != member_id_array) { 
   7095         sal_free(member_id_array);
   7096     }
   7097     if (NULL != block_ptr) { 
   7098         soc_cm_sfree(unit, block_ptr);
   7099     }
   7100     if (NULL != member_bitmap) { 
   7101         sal_free(member_bitmap);
   7102     }
   7103     if (NULL != status_bitmap) { 
   7104         sal_free(status_bitmap);
   7105     }
   7106     if (NULL != override_bitmap) { 
   7107         sal_free(override_bitmap);
   7108     }
   7109     return rv;
   7110 }
   7111 
   7112 /*
   7113  * Function:
   7114  *      bcm_tr3_l3_egress_ecmp_dlb_create 
   7115  * Purpose:
   7116  *      Create ECMP DLB group.
   7117  * Parameters:
   7118  *      unit       - (IN) bcm device.
   7119  *      ecmp       - (IN) ECMP group info.
   7120  *      intf_count - (IN) Number of elements in intf_array.
   7121  *      intf_array - (IN) Array of Egress forwarding objects.
   7122  * Returns:
   7123  *      BCM_E_XXX
   7124  */
   7125 int 
   7126 bcm_tr3_l3_egress_ecmp_dlb_create(int unit, bcm_l3_egress_ecmp_t *ecmp,
   7127         int intf_count, bcm_if_t *intf_array)
   7128 {
   7129     int dlb_enable;
   7130     int dynamic_size_encode;
   7131     int ecmp_group_idx;
   7132 
   7133     if ((ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_NORMAL) ||
   7134            (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_ASSIGNED) ||
   7135            (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_OPTIMAL)) {
   7136         dlb_enable = 1;
   7137     } else {
   7138         dlb_enable = 0;
   7139     }
   7140 
   7141     if (dlb_enable) {
   7142         /* Verify dynamic_size */
   7143         BCM_IF_ERROR_RETURN
   7144             (_bcm_tr3_ecmp_dlb_dynamic_size_encode(ecmp->dynamic_size,
   7145                                                    &dynamic_size_encode));
   7146 
   7147         /* Verify dynamic_age */
   7148         /* Error rate in calculating INACTIVITY_DURATION is higher
   7149            if it is allowed to be configured too low.
   7150            Minimum limit of 16 microseconds is required to reduce
   7151            the error rate in time duration calculation.*/
   7152         if ((ecmp->dynamic_age < 16) ||
   7153                 (ecmp->dynamic_age > 0x3ffff)) {
   7154             return BCM_E_PARAM;
   7155         }
   7156 
   7157         /* Verify dynamic exponents */
   7158         if (ecmp->dynamic_load_exponent > 0xf) {
   7159             return BCM_E_PARAM;
   7160         }
   7161         if (ecmp->dynamic_expected_load_exponent > 0xf) {
   7162             return BCM_E_PARAM;
   7163         }
   7164     }
   7165 
   7166     /* Free resources associated with old DLB group, if exists */
   7167     ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   7168     BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_free_resource(unit, ecmp_group_idx));
   7169 
   7170     /* Set new DLB group */
   7171     if (dlb_enable) {
   7172         BCM_IF_ERROR_RETURN
   7173             (_bcm_tr3_ecmp_dlb_set(unit, ecmp, intf_count, intf_array));
   7174     }
   7175 
   7176     return BCM_E_NONE;
   7177 }
   7178 
   7179 /*
   7180  * Function:
   7181  *      bcm_tr3_l3_egress_ecmp_dlb_destroy
   7182  * Purpose:
   7183  *      Destroy an ECMP DLB group.
   7184  * Parameters:
   7185  *      unit       - (IN) bcm device.
   7186  *      mpintf     - (IN) ECMP group info.
   7187  * Returns:
   7188  *      BCM_E_XXX
   7189  */
   7190 int 
   7191 bcm_tr3_l3_egress_ecmp_dlb_destroy(int unit, bcm_if_t mpintf)
   7192 {
   7193     int ecmp_group;
   7194 
   7195     /* Free resources associated with old DLB group, if exists */
   7196     if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, mpintf)) {
   7197         ecmp_group = mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   7198     } else {
   7199         return BCM_E_PARAM;
   7200     }
   7201     BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_free_resource(unit, ecmp_group));
   7202 
   7203     return BCM_E_NONE;
   7204 }
   7205 
   7206 /*
   7207  * Function:
   7208  *      bcm_tr3_l3_egress_ecmp_dlb_get
   7209  * Purpose:
   7210  *      Get info about an ECMP DLB group.
   7211  * Parameters:
   7212  *      unit       - (IN) bcm device.
   7213  *      ecmp       - (INOUT) ECMP group info.
   7214  * Returns:
   7215  *      BCM_E_XXX
   7216  */
   7217 int 
   7218 bcm_tr3_l3_egress_ecmp_dlb_get(int unit, bcm_l3_egress_ecmp_t *ecmp)
   7219 {
   7220     int ecmp_group_idx;
   7221     ecmp_count_entry_t ecmp_group_entry;
   7222     int group_enable, dlb_id;
   7223     dlb_ecmp_group_control_entry_t dlb_ecmp_group_control_entry;
   7224     int dlb_mode;
   7225     int flow_set_size;
   7226     dlb_ecmp_vla_quality_measure_control_entry_t vla_quality_measure_control_entry;
   7227 
   7228     /* Get DLB ID */
   7229     ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
   7230     SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY,
   7231                 ecmp_group_idx, &ecmp_group_entry));
   7232     group_enable = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_group_entry,
   7233             GROUP_ENABLEf);
   7234     if (!group_enable) {
   7235         ecmp->dynamic_mode = 0;
   7236         ecmp->dynamic_size = 0;
   7237         ecmp->dynamic_age = 0;
   7238         ecmp->dynamic_load_exponent = 0;
   7239         ecmp->dynamic_expected_load_exponent = 0;
   7240         return BCM_E_NONE;
   7241     }
   7242     dlb_id = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_group_entry, DLB_IDf);
   7243 
   7244     /* Get dynamic_mode */
   7245     SOC_IF_ERROR_RETURN(READ_DLB_ECMP_GROUP_CONTROLm(unit, MEM_BLOCK_ANY,
   7246                 dlb_id, &dlb_ecmp_group_control_entry));
   7247     dlb_mode = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   7248             &dlb_ecmp_group_control_entry, MEMBER_ASSIGNMENT_MODEf);
   7249     switch (dlb_mode) {
   7250         case 0:
   7251             ecmp->dynamic_mode = BCM_L3_ECMP_DYNAMIC_MODE_NORMAL;
   7252             break;
   7253         case 1:
   7254             ecmp->dynamic_mode = BCM_L3_ECMP_DYNAMIC_MODE_ASSIGNED;
   7255             break;
   7256         case 2:
   7257             ecmp->dynamic_mode = BCM_L3_ECMP_DYNAMIC_MODE_OPTIMAL;
   7258             break;
   7259         default:
   7260             return BCM_E_INTERNAL;
   7261     }
   7262 
   7263     /* Get dynamic_size */
   7264     flow_set_size = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   7265             &dlb_ecmp_group_control_entry, FLOW_SET_SIZEf);
   7266     BCM_IF_ERROR_RETURN
   7267         (_bcm_tr3_ecmp_dlb_dynamic_size_decode(flow_set_size,
   7268                                                (int *)&ecmp->dynamic_size));
   7269 
   7270     /* Get dynamic_age */
   7271     ecmp->dynamic_age = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
   7272             &dlb_ecmp_group_control_entry, INACTIVITY_DURATIONf);
   7273 
   7274     /* Get dynamic exponents and ecmp_group_flags */
   7275     SOC_IF_ERROR_RETURN(READ_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm(unit,
   7276                 MEM_BLOCK_ANY, dlb_id, &vla_quality_measure_control_entry));
   7277     ecmp->dynamic_load_exponent =
   7278         soc_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm_field32_get(unit,
   7279                 &vla_quality_measure_control_entry, VLA_WEIGHT_LOADINGf);
   7280     ecmp->dynamic_expected_load_exponent =
   7281         soc_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm_field32_get(unit,
   7282                 &vla_quality_measure_control_entry, VLA_WEIGHT_EXPECTED_LOADINGf);
   7283     if (soc_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm_field32_get(unit,
   7284                 &vla_quality_measure_control_entry, VLA_CAP_LOADING_AVGf)) {
   7285        ecmp->ecmp_group_flags |= BCM_L3_ECMP_DYNAMIC_LOAD_DECREASE_RESET;
   7286     } 
   7287     if (soc_DLB_ECMP_VLA_QUALITY_MEASURE_CONTROLm_field32_get(unit,
   7288                 &vla_quality_measure_control_entry,
   7289                 VLA_CAP_EXPECTED_LOADINGf)) {
   7290        ecmp->ecmp_group_flags |=
   7291            BCM_L3_ECMP_DYNAMIC_EXPECTED_LOAD_DECREASE_RESET;
   7292     } 
   7293 
   7294     return BCM_E_NONE;
   7295 }
   7296 
   7297 /*
   7298  * Function:
   7299  *      bcm_tr3_l3_egress_ecmp_member_status_set
   7300  * Purpose:
   7301  *      Set ECMP DLB member status.
   7302  * Parameters:
   7303  *      unit - (IN) SOC unit number.
   7304  *      intf - (IN) L3 Interface ID pointing to an Egress forwarding object.
   7305  *      status - (IN) ECMP member status.
   7306  * Returns:
   7307  *      BCM_E_xxx
   7308  */
   7309 int
   7310 bcm_tr3_l3_egress_ecmp_member_status_set(int unit, bcm_if_t intf, int status)
   7311 {
   7312     int nh_index;
   7313     dlb_ecmp_member_sw_state_entry_t sw_state_entry;
   7314     int member_bitmap_width, alloc_size;
   7315     SHR_BITDCL *status_bitmap = NULL;
   7316     SHR_BITDCL *override_bitmap = NULL;
   7317     int dlb_group_valid;
   7318     int i;
   7319     _tr3_ecmp_dlb_nh_membership_t *current_ptr;
   7320 
   7321     /* Derive next hop index */
   7322     if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) {
   7323         nh_index = intf - BCM_XGS3_EGRESS_IDX_MIN(unit);
   7324     } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) {
   7325         nh_index = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   7326     } else {
   7327         return BCM_E_PARAM;
   7328     }
   7329 
   7330     /* Get status bitmap */
   7331     SOC_IF_ERROR_RETURN(READ_DLB_ECMP_MEMBER_SW_STATEm(unit, MEM_BLOCK_ANY, 0,
   7332                 &sw_state_entry));
   7333     member_bitmap_width = soc_mem_field_length(unit, DLB_ECMP_MEMBER_SW_STATEm,
   7334             MEMBER_BITMAPf);
   7335     alloc_size = SHR_BITALLOCSIZE(member_bitmap_width);
   7336     status_bitmap = sal_alloc(alloc_size, "DLB ECMP member status bitmap"); 
   7337     if (NULL == status_bitmap) {
   7338         return BCM_E_MEMORY;
   7339     }
   7340     soc_DLB_ECMP_MEMBER_SW_STATEm_field_get(unit, &sw_state_entry,
   7341             MEMBER_BITMAPf, status_bitmap);
   7342 
   7343     /* Get override bitmap */
   7344     override_bitmap = sal_alloc(alloc_size, "DLB ECMP member override bitmap"); 
   7345     if (NULL == override_bitmap) {
   7346         sal_free(status_bitmap);
   7347         return BCM_E_MEMORY;
   7348     }
   7349     soc_DLB_ECMP_MEMBER_SW_STATEm_field_get(unit, &sw_state_entry,
   7350             OVERRIDE_MEMBER_BITMAPf, override_bitmap);
   7351 
   7352     /* Update status and override bitmaps for any of the next hop's DLB
   7353      * member IDs that belong to an ECMP DLB group.
   7354      */
   7355     dlb_group_valid = FALSE;
   7356     for (i = 0; i < ECMP_DLB_INFO(unit)->ecmp_dlb_nh_info_size; i++) {
   7357         if (ECMP_DLB_NH_INFO(unit, i).valid) {
   7358             if (nh_index == ECMP_DLB_NH_INFO(unit, i).nh_index) {
   7359                 current_ptr = ECMP_DLB_NH_INFO(unit, i).nh_membership_list;
   7360                 while (NULL != current_ptr) {
   7361                     if (current_ptr->group != -1) {
   7362                         dlb_group_valid = TRUE;
   7363                         switch (status) {
   7364                             case BCM_L3_ECMP_DYNAMIC_MEMBER_FORCE_DOWN:
   7365                                 SHR_BITSET(override_bitmap,
   7366                                         current_ptr->member_id);
   7367                                 SHR_BITCLR(status_bitmap,
   7368                                         current_ptr->member_id);
   7369                                 break;
   7370                             case BCM_L3_ECMP_DYNAMIC_MEMBER_FORCE_UP:
   7371                                 SHR_BITSET(override_bitmap,
   7372                                         current_ptr->member_id);
   7373                                 SHR_BITSET(status_bitmap,
   7374                                         current_ptr->member_id);
   7375                                 break;
   7376                             case BCM_L3_ECMP_DYNAMIC_MEMBER_HW:
   7377                                 SHR_BITCLR(override_bitmap,
   7378                                         current_ptr->member_id);
   7379                                 SHR_BITCLR(status_bitmap,
   7380                                         current_ptr->member_id);
   7381                                 break;
   7382                             default:
   7383                                 sal_free(status_bitmap);
   7384                                 sal_free(override_bitmap);
   7385                                 return BCM_E_PARAM;
   7386                         }
   7387                     }
   7388                     current_ptr = current_ptr->next;
   7389                 }
   7390                 break;
   7391             }
   7392         }
   7393     }
   7394     if (!dlb_group_valid) {
   7395         /* The given intf was not a member of any DLB group */
   7396         sal_free(status_bitmap);
   7397         sal_free(override_bitmap);
   7398         return BCM_E_NOT_FOUND;
   7399     }
   7400 
   7401     /* Write status and override bitmaps to hardware */
   7402     soc_DLB_ECMP_MEMBER_SW_STATEm_field_set(unit, &sw_state_entry,
   7403             MEMBER_BITMAPf, status_bitmap);
   7404     soc_DLB_ECMP_MEMBER_SW_STATEm_field_set(unit, &sw_state_entry,
   7405             OVERRIDE_MEMBER_BITMAPf, override_bitmap);
   7406     sal_free(status_bitmap);
   7407     sal_free(override_bitmap);
   7408     SOC_IF_ERROR_RETURN
   7409         (WRITE_DLB_ECMP_MEMBER_SW_STATEm(unit, MEM_BLOCK_ALL, 0,
   7410                                          &sw_state_entry));
   7411 
   7412     return BCM_E_NONE;
   7413 }
   7414 
   7415 /*
   7416  * Function:
   7417  *      bcm_tr3_l3_egress_ecmp_member_status_get
   7418  * Purpose:
   7419  *      Get ECMP DLB member status.
   7420  * Parameters:
   7421  *      unit - (IN) SOC unit number.
   7422  *      intf - (IN) L3 Interface ID pointing to an Egress forwarding object.
   7423  *      status - (OUT) ECMP member status.
   7424  * Returns:
   7425  *      BCM_E_xxx
   7426  */
   7427 int
   7428 bcm_tr3_l3_egress_ecmp_member_status_get(int unit, bcm_if_t intf, int *status)
   7429 {
   7430     int rv = BCM_E_NONE;
   7431     int nh_index;
   7432     int member_id;
   7433     int i;
   7434     _tr3_ecmp_dlb_nh_membership_t *current_ptr;
   7435     dlb_ecmp_member_sw_state_entry_t sw_state_entry;
   7436     int member_bitmap_width, alloc_size;
   7437     SHR_BITDCL *status_bitmap = NULL;
   7438     SHR_BITDCL *override_bitmap = NULL;
   7439     uint64 hw_state, hw_status_bitmap;
   7440     uint32 bitmap32;
   7441 
   7442     if (NULL == status) {
   7443         return BCM_E_PARAM;
   7444     }
   7445             
   7446     /* Derive next hop index */
   7447     if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) {
   7448         nh_index = intf - BCM_XGS3_EGRESS_IDX_MIN(unit);
   7449     } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) {
   7450         nh_index = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   7451     } else {
   7452         return BCM_E_PARAM;
   7453     }
   7454 
   7455     /* Find next hop's DLB member ID */
   7456     member_id = -1;
   7457     for (i = 0; i < ECMP_DLB_INFO(unit)->ecmp_dlb_nh_info_size; i++) {
   7458         if (ECMP_DLB_NH_INFO(unit, i).valid) {
   7459             if (nh_index == ECMP_DLB_NH_INFO(unit, i).nh_index) {
   7460                 current_ptr = ECMP_DLB_NH_INFO(unit, i).nh_membership_list;
   7461                 while (NULL != current_ptr) {
   7462                     if (current_ptr->group != -1) {
   7463                         member_id = current_ptr->member_id;
   7464                         break;
   7465                     }
   7466                     current_ptr = current_ptr->next;
   7467                 }
   7468                 break;
   7469             }
   7470         }
   7471     }
   7472     if (-1 == member_id) {
   7473         /* The given intf was not a member of any DLB group */
   7474         return BCM_E_NOT_FOUND;
   7475     }
   7476 
   7477     /* Get status bitmap */
   7478     SOC_IF_ERROR_RETURN(READ_DLB_ECMP_MEMBER_SW_STATEm(unit, MEM_BLOCK_ANY, 0,
   7479                 &sw_state_entry));
   7480     member_bitmap_width = soc_mem_field_length(unit, DLB_ECMP_MEMBER_SW_STATEm,
   7481             MEMBER_BITMAPf);
   7482     alloc_size = SHR_BITALLOCSIZE(member_bitmap_width);
   7483     status_bitmap = sal_alloc(alloc_size, "DLB ECMP member status bitmap"); 
   7484     if (NULL == status_bitmap) {
   7485         return BCM_E_MEMORY;
   7486     }
   7487     soc_DLB_ECMP_MEMBER_SW_STATEm_field_get(unit, &sw_state_entry,
   7488             MEMBER_BITMAPf, status_bitmap);
   7489 
   7490     /* Get override bitmap */
   7491     override_bitmap = sal_alloc(alloc_size, "DLB ECMP member override bitmap"); 
   7492     if (NULL == override_bitmap) {
   7493         sal_free(status_bitmap);
   7494         return BCM_E_MEMORY;
   7495     }
   7496     soc_DLB_ECMP_MEMBER_SW_STATEm_field_get(unit, &sw_state_entry,
   7497             OVERRIDE_MEMBER_BITMAPf, override_bitmap);
   7498 
   7499     /* Derive status from software override and status bitmaps or
   7500      * hardware state bitmap.
   7501      */
   7502     if (SHR_BITGET(override_bitmap, member_id)) {
   7503         if (SHR_BITGET(status_bitmap, member_id)) {
   7504             *status = BCM_L3_ECMP_DYNAMIC_MEMBER_FORCE_UP;
   7505         } else {
   7506             *status = BCM_L3_ECMP_DYNAMIC_MEMBER_FORCE_DOWN;
   7507         }
   7508     } else {
   7509         rv = READ_DLB_ECMP_MEMBER_HW_STATE_64r(unit, &hw_state); 
   7510         if (SOC_FAILURE(rv)) {
   7511             sal_free(status_bitmap);
   7512             sal_free(override_bitmap);
   7513             return rv;
   7514         }
   7515         hw_status_bitmap = soc_reg64_field_get(unit,
   7516                 DLB_ECMP_MEMBER_HW_STATE_64r, hw_state, BITMAPf);
   7517         if (member_id < 32) {
   7518             bitmap32 = COMPILER_64_LO(hw_status_bitmap);
   7519         } else {
   7520             bitmap32 = COMPILER_64_HI(hw_status_bitmap);
   7521             member_id -= 32;
   7522         }
   7523         if ((1 << member_id) & bitmap32) {
   7524             *status = BCM_L3_ECMP_DYNAMIC_MEMBER_HW_UP;
   7525         } else {
   7526             *status = BCM_L3_ECMP_DYNAMIC_MEMBER_HW_DOWN;
   7527         }
   7528     }
   7529 
   7530     /* Cleanup */
   7531     if (status_bitmap) {
   7532         sal_free(status_bitmap);
   7533     }
   7534 
   7535     if (override_bitmap) {
   7536         sal_free(override_bitmap);
   7537     }
   7538 
   7539     return rv;
   7540 }
   7541 /*
   7542  * Function:
   7543  *      bcm_tr3_l3_egress_ecmp_dlb_ethertype_set
   7544  * Purpose:
   7545  *      Set the Ethertypes that are eligible or ineligible for
   7546  *      ECMP dynamic load balancing.
   7547  * Parameters:
   7548  *      unit - (IN) Unit number.
   7549  *      flags - (IN) BCM_L3_ECMP_DYNAMIC_ETHERTYPE_xxx flags.
   7550  *      ethertype_count - (IN) Number of elements in ethertype_array.
   7551  *      ethertype_array - (IN) Array of Ethertypes.
   7552  * Returns:
   7553  *      BCM_E_XXX
   7554  */
   7555 int 
   7556 bcm_tr3_l3_egress_ecmp_dlb_ethertype_set(
   7557     int unit, 
   7558     uint32 flags, 
   7559     int ethertype_count, 
   7560     int *ethertype_array)
   7561 {
   7562     uint32 measure_control_reg;
   7563     int i, j;
   7564     dlb_ecmp_ethertype_eligibility_map_entry_t ethertype_entry;
   7565 
   7566     /* Input check */
   7567     if ((ethertype_count > 0) && (NULL == ethertype_array)) {
   7568         return BCM_E_PARAM;
   7569     }
   7570     if (ethertype_count > soc_mem_index_count(unit,
   7571                 DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm)) {
   7572         return BCM_E_RESOURCE;
   7573     }
   7574 
   7575     /* Update quality measure control register */
   7576     SOC_IF_ERROR_RETURN
   7577         (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   7578     soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   7579             &measure_control_reg, ETHERTYPE_ELIGIBILITY_CONFIGf,
   7580             flags & BCM_L3_ECMP_DYNAMIC_ETHERTYPE_ELIGIBLE ? 1 : 0);
   7581     soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   7582             &measure_control_reg, INNER_OUTER_ETHERTYPE_SELECTIONf,
   7583             flags & BCM_L3_ECMP_DYNAMIC_ETHERTYPE_INNER ? 1 : 0);
   7584     SOC_IF_ERROR_RETURN
   7585         (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg));
   7586 
   7587     /* Update Ethertype eligibility map table */
   7588     for (i = 0; i < ethertype_count; i++) {
   7589         sal_memset(&ethertype_entry, 0,
   7590                 sizeof(dlb_ecmp_ethertype_eligibility_map_entry_t));
   7591         soc_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_set(unit,
   7592                 &ethertype_entry, VALIDf, 1);
   7593         soc_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_set(unit,
   7594                 &ethertype_entry, ETHERTYPEf, ethertype_array[i]);
   7595         SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm(unit,
   7596                     MEM_BLOCK_ALL, i, &ethertype_entry));
   7597     }
   7598 
   7599     /* Zero out remaining entries of Ethertype eligibility map table */
   7600     for (j = i; j < soc_mem_index_count(unit,
   7601                 DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm); j++) {
   7602         SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm(unit,
   7603                     MEM_BLOCK_ALL, j, soc_mem_entry_null(unit,
   7604                         DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm)));
   7605     }
   7606 
   7607     return BCM_E_NONE;
   7608 }
   7609 
   7610 /*
   7611  * Function:
   7612  *      bcm_tr3_l3_egress_ecmp_dlb_ethertype_get
   7613  * Purpose:
   7614  *      Get the Ethertypes that are eligible or ineligible for
   7615  *      ECMP dynamic load balancing.
   7616  * Parameters:
   7617  *      unit - (IN) Unit number.
   7618  *      flags - (INOUT) BCM_L3_ECMP_DYNAMIC_ETHERTYPE_xxx flags.
   7619  *      ethertype_max - (IN) Number of elements in ethertype_array.
   7620  *      ethertype_array - (OUT) Array of Ethertypes.
   7621  *      ethertype_count - (OUT) Number of elements returned in ethertype_array.
   7622  * Returns:
   7623  *      BCM_E_XXX
   7624  */
   7625 int 
   7626 bcm_tr3_l3_egress_ecmp_dlb_ethertype_get(
   7627     int unit, 
   7628     uint32 *flags, 
   7629     int ethertype_max, 
   7630     int *ethertype_array, 
   7631     int *ethertype_count)
   7632 {
   7633     uint32 measure_control_reg;
   7634     int i;
   7635     int ethertype;
   7636     dlb_ecmp_ethertype_eligibility_map_entry_t ethertype_entry;
   7637 
   7638     /* Input check */
   7639     if (NULL == flags) {
   7640         return BCM_E_PARAM;
   7641     }
   7642     if ((ethertype_max > 0) && (NULL == ethertype_array)) {
   7643         return BCM_E_PARAM;
   7644     }
   7645     if (NULL == ethertype_count) {
   7646         return BCM_E_PARAM;
   7647     }
   7648 
   7649     *ethertype_count = 0;
   7650 
   7651     /* Get flags */
   7652     SOC_IF_ERROR_RETURN
   7653         (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   7654     if (soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   7655                 measure_control_reg, ETHERTYPE_ELIGIBILITY_CONFIGf)) {
   7656         *flags |= BCM_L3_ECMP_DYNAMIC_ETHERTYPE_ELIGIBLE;
   7657     }
   7658     if (soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   7659                 measure_control_reg, INNER_OUTER_ETHERTYPE_SELECTIONf)) {
   7660         *flags |= BCM_L3_ECMP_DYNAMIC_ETHERTYPE_INNER;
   7661     }
   7662 
   7663     /* Get Ethertypes */
   7664     for (i = 0; i < soc_mem_index_count(unit,
   7665                 DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm); i++) {
   7666         SOC_IF_ERROR_RETURN(READ_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm(unit,
   7667                     MEM_BLOCK_ANY, i, &ethertype_entry));
   7668         if (soc_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_get(unit,
   7669                     &ethertype_entry, VALIDf)) {
   7670             ethertype = soc_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_get(unit,
   7671                     &ethertype_entry, ETHERTYPEf);
   7672             if (NULL != ethertype_array) {
   7673                 ethertype_array[*ethertype_count] = ethertype;
   7674             }
   7675             (*ethertype_count)++;
   7676             if ((ethertype_max > 0) && (*ethertype_count == ethertype_max)) {
   7677                 break;
   7678             }
   7679         }
   7680     }
   7681 
   7682     return BCM_E_NONE;
   7683 }
   7684 
   7685 /*
   7686  * Function:
   7687  *      _bcm_tr3_ecmp_dlb_accounting_set
   7688  * Purpose:
   7689  *      Set ECMP DLB accounting mode.
   7690  * Parameters:
   7691  *      unit - (IN) SOC unit number.
   7692  *      accounting_mode - (IN) Accounting mode.
   7693  * Returns:
   7694  *      BCM_E_xxx
   7695  */
   7696 STATIC int
   7697 _bcm_tr3_ecmp_dlb_accounting_set(int unit, int accounting_mode)
   7698 {
   7699     uint32 measure_control_reg;
   7700     int old_accounting_mode;
   7701     SHR_BITDCL active;
   7702 
   7703     SOC_IF_ERROR_RETURN
   7704         (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   7705     old_accounting_mode = soc_reg_field_get(unit,
   7706             DLB_ECMP_QUALITY_MEASURE_CONTROLr, measure_control_reg,
   7707             ACCOUNTING_SELf);
   7708     if (old_accounting_mode == accounting_mode) {
   7709         return BCM_E_NONE;
   7710     }
   7711 
   7712     SHR_BITTEST_RANGE(ECMP_DLB_INFO(unit)->ecmp_dlb_id_used_bitmap,
   7713             0, soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm), active);
   7714     if (active) {
   7715         /* Accounting mode cannot be changed while there are active
   7716          * DLB groups.
   7717          */
   7718         return BCM_E_BUSY;
   7719     }
   7720 
   7721     soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   7722         &measure_control_reg, ACCOUNTING_SELf, accounting_mode);
   7723     if (accounting_mode) { /* virtual link accounting */
   7724         soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   7725                 &measure_control_reg, INST_METRIC_UPDATE_INTERVALf, 1);
   7726     } else { /* physical link accounting */
   7727         soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   7728                 &measure_control_reg, INST_METRIC_UPDATE_INTERVALf, 0);
   7729     }
   7730     SOC_IF_ERROR_RETURN
   7731         (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg));
   7732 
   7733     return BCM_E_NONE;
   7734 }
   7735 
   7736 /*
   7737  * Function:
   7738  *      _bcm_tr3_ecmp_dlb_accounting_get
   7739  * Purpose:
   7740  *      Get ECMP DLB accounting mode.
   7741  * Parameters:
   7742  *      unit - (IN) SOC unit number.
   7743  *      accounting_mode - (OUT) Accounting mode.
   7744  * Returns:
   7745  *      BCM_E_xxx
   7746  */
   7747 STATIC int
   7748 _bcm_tr3_ecmp_dlb_accounting_get(int unit, int *accounting_mode)
   7749 {
   7750     uint32 measure_control_reg;
   7751 
   7752     SOC_IF_ERROR_RETURN
   7753         (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   7754     *accounting_mode = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   7755         measure_control_reg, ACCOUNTING_SELf);
   7756 
   7757     return BCM_E_NONE;
   7758 }
   7759 
   7760 /*
   7761  * Function:
   7762  *      _bcm_tr3_ecmp_dlb_sample_rate_pla_thresholds_set
   7763  * Purpose:
   7764  *      Set ECMP DLB sample period and physical link accounting thresholds.
   7765  * Parameters:
   7766  *      unit - (IN) SOC unit number.
   7767  *      sample_rate - (IN) Number of samplings per second.
   7768  *      min_th      - (IN) Minimum port load threshold, in mbps.
   7769  *      max_th      - (IN) Maximum port load threshold, in mbps.
   7770  * Returns:
   7771  *      BCM_E_xxx
   7772  */
   7773 STATIC int
   7774 _bcm_tr3_ecmp_dlb_sample_rate_pla_thresholds_set(int unit, int sample_rate,
   7775         int min_th, int max_th)
   7776 {
   7777     int num_time_units;
   7778     uint32 measure_control_reg;
   7779     int max_th_bytes;
   7780     int th_increment;
   7781     dlb_ecmp_pla_quantize_threshold_entry_t quantize_threshold_entry;
   7782     int i;
   7783     int th_bytes[7];
   7784 
   7785     if (sample_rate <= 0 || min_th < 0 || max_th < 0) {
   7786         return BCM_E_PARAM;
   7787     }
   7788 
   7789     if (min_th > max_th) {
   7790         max_th = min_th;
   7791     }
   7792 
   7793     /* Compute sampling period in units of 1us:
   7794      *     number of 1us time units = 10^6 / sample_rate
   7795      */ 
   7796     num_time_units = 1000000 / sample_rate;
   7797     if (num_time_units < 1 || num_time_units > 0x3fff) {
   7798         /* Hardware limits the sampling period to 14 bits */ 
   7799         return BCM_E_PARAM;
   7800     }
   7801     SOC_IF_ERROR_RETURN
   7802         (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   7803     soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   7804             &measure_control_reg, HISTORICAL_SAMPLING_PERIODf, num_time_units);
   7805     SOC_IF_ERROR_RETURN
   7806         (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg));
   7807     ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate = sample_rate;
   7808 
   7809     /* Compute threshold in bytes per sampling period:
   7810      * bytes per 1us = (million bits per sec) * 10^6 / 8 * 10^(-6),
   7811      * bytes per sampling period = (bytes per 1us) * (number of 1us 
   7812      *                             time units in sampling period)
   7813      *                           = mbps * num_time_units / 8
   7814      */
   7815     max_th_bytes = max_th * num_time_units / 8;
   7816 
   7817     if (max_th_bytes > 0x3fffffff) {
   7818         /* Hardware limits port load threshold to 30 bits */
   7819         return BCM_E_PARAM;
   7820     }
   7821 
   7822     /* Use min threshold as threshold 0, and max threshold as threshold 6.
   7823      * Thresholds 1 to 5 will be evenly spread out between min and max
   7824      * thresholds.
   7825      */
   7826     th_increment = (max_th - min_th) / 6;
   7827     for (i = 0; i < 7; i++) {
   7828         SOC_IF_ERROR_RETURN
   7829             (READ_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm(unit, MEM_BLOCK_ANY, i,
   7830                                               &quantize_threshold_entry));
   7831         th_bytes[i] = (min_th + i * th_increment) * num_time_units / 8;
   7832         soc_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm_field32_set
   7833             (unit, &quantize_threshold_entry, THRESHOLD_HIST_LOADf,
   7834              th_bytes[i]);
   7835         SOC_IF_ERROR_RETURN
   7836             (WRITE_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm(unit, MEM_BLOCK_ALL, i,
   7837                                                &quantize_threshold_entry));
   7838     }
   7839 
   7840     ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th = min_th;
   7841     ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th = max_th;
   7842 
   7843     return BCM_E_NONE;
   7844 }
   7845 
   7846 /*
   7847  * Function:
   7848  *      _bcm_tr3_ecmp_dlb_sample_rate_vla_thresholds_set
   7849  * Purpose:
   7850  *      Set ECMP DLB sample period and virtual link accounting thresholds.
   7851  * Parameters:
   7852  *      unit - (IN) SOC unit number.
   7853  *      sample_rate - (IN) Number of samplings per second.
   7854  *      exp_load_min_th  - (IN) Minimum expected load threshold, in mbps.
   7855  *      exp_load_max_th  - (IN) Maximum expected load threshold, in mbps.
   7856  *      imbalance_min_th - (IN) Minimum member imbalance threshold,
   7857  *                              in percentage.
   7858  *      imbalance_max_th - (IN) Maximum member imbalance threshold.
   7859  *                              in percentage.
   7860  * Returns:
   7861  *      BCM_E_xxx
   7862  */
   7863 STATIC int
   7864 _bcm_tr3_ecmp_dlb_sample_rate_vla_thresholds_set(int unit, int sample_rate,
   7865         int exp_load_min_th, int exp_load_max_th,
   7866         int imbalance_min_th, int imbalance_max_th)
   7867 {
   7868     int num_time_units;
   7869     uint32 measure_control_reg;
   7870     int exp_load_max_th_kbytes;
   7871     int num_exp_load_th;
   7872     int exp_load_th_increment;
   7873     dlb_ecmp_vla_expected_loading_threshold_entry_t exp_load_threshold_entry;
   7874     int exp_load_th_kbytes;
   7875     int num_imbalance_th;
   7876     int imbalance_th_increment;
   7877     int imbalance_max_th_kbytes;
   7878     int imbalance_th_kbytes;
   7879     dlb_ecmp_vla_member_imbalance_threshold_entry_t imbalance_threshold_entry;
   7880     int i, j;
   7881     int imbalance_th_fields[7] = {THRESHOLD_0f, THRESHOLD_1f, THRESHOLD_2f,
   7882                                   THRESHOLD_3f, THRESHOLD_4f, THRESHOLD_5f,
   7883                                   THRESHOLD_6f};
   7884 
   7885     if (sample_rate <= 0 || exp_load_min_th < 0 || exp_load_max_th < 0) {
   7886         return BCM_E_PARAM;
   7887     }
   7888 
   7889     if (exp_load_min_th > exp_load_max_th) {
   7890         exp_load_max_th = exp_load_min_th;
   7891     }
   7892 
   7893     if (imbalance_min_th > imbalance_max_th) {
   7894         imbalance_max_th = imbalance_min_th;
   7895     }
   7896 
   7897     /* Compute sampling period in units of 1us:
   7898      *     number of 1us time units = 10^6 / sample_rate
   7899      */ 
   7900     num_time_units = 1000000 / sample_rate;
   7901     if (num_time_units < 1 || num_time_units > 0x3fff) {
   7902         /* Hardware limits the sampling period to 14 bits */ 
   7903         return BCM_E_PARAM;
   7904     }
   7905     SOC_IF_ERROR_RETURN
   7906         (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   7907     soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   7908             &measure_control_reg, HISTORICAL_SAMPLING_PERIODf, num_time_units);
   7909     SOC_IF_ERROR_RETURN
   7910         (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg));
   7911     ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate = sample_rate;
   7912 
   7913     /* Compute expected loading threshold in kbytes per sampling period:
   7914      * bytes per 1us = (million bits per sec) * 10^6 / 8 * 10^(-6)
   7915      *               = mbps / 8.
   7916      * bytes per sampling period = (bytes per 1us) * (number of 1us 
   7917      *                             time units in sampling period)
   7918      *                           = mbps * num_time_units / 8.
   7919      * kbytes per sampling period =  mbps * num_times_units / 8000.
   7920      */
   7921     exp_load_max_th_kbytes = exp_load_max_th * num_time_units / 8000;
   7922     if (exp_load_max_th_kbytes > 0xfffff) {
   7923         /* Hardware limits expected loading threshold in kbytes to 20 bits */
   7924         return BCM_E_PARAM;
   7925     }
   7926 
   7927     /* Use expected load min threshold as threshold 0, and max threshold as
   7928      * threshold 14. Thresholds 1 to 13 will be evenly spread out between them.
   7929      */
   7930     num_exp_load_th = soc_mem_index_count(unit,
   7931             DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLDm);
   7932     exp_load_th_increment = (exp_load_max_th - exp_load_min_th) /
   7933                             (num_exp_load_th - 1);
   7934     for (i = 0; i < num_exp_load_th; i++) {
   7935         SOC_IF_ERROR_RETURN(READ_DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLDm(unit,
   7936                     MEM_BLOCK_ANY, i, &exp_load_threshold_entry));
   7937         exp_load_th_kbytes = (exp_load_min_th + i * exp_load_th_increment) *
   7938                              num_time_units / 8000;
   7939         soc_DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLDm_field32_set
   7940             (unit, &exp_load_threshold_entry, THRESHOLDf, exp_load_th_kbytes);
   7941         SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLDm(unit,
   7942                     MEM_BLOCK_ALL, i, &exp_load_threshold_entry));
   7943     }
   7944 
   7945     ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_min_th = exp_load_min_th;
   7946     ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_max_th = exp_load_max_th;
   7947 
   7948     /* Use member imbalance min threshold as threshold 0, and max threshold as
   7949      * threshold 6. Thresholds 1 to 5 will be evenly spread out between them.
   7950      */
   7951     num_imbalance_th = 7;
   7952     imbalance_th_increment = (imbalance_max_th - imbalance_min_th) /
   7953         (num_imbalance_th - 1);
   7954     for (i = 0;
   7955          i < soc_mem_index_count(unit,
   7956              DLB_ECMP_VLA_MEMBER_IMBALANCE_THRESHOLDm);
   7957          i++) {
   7958         /* There are 16 sets of member imbalance thresholds.
   7959          * For sets 0 to 14, use expected loading thresholds 0 to 14 from
   7960          * DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLD table as the
   7961          * expected load. For set 15, extrapolate the expected load.
   7962          */
   7963         if (i < num_exp_load_th) {
   7964             SOC_IF_ERROR_RETURN
   7965                 (READ_DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLDm(unit,
   7966                         MEM_BLOCK_ANY, i, &exp_load_threshold_entry));
   7967             exp_load_th_kbytes =
   7968                 soc_DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLDm_field32_get(unit,
   7969                         &exp_load_threshold_entry, THRESHOLDf);
   7970         } else {
   7971             exp_load_th_kbytes =
   7972                 (exp_load_min_th + num_exp_load_th * exp_load_th_increment) *
   7973                 num_time_units / 8000;
   7974         }
   7975 
   7976         /* Compute member imbalance thresholds */
   7977         imbalance_max_th_kbytes = exp_load_th_kbytes * imbalance_max_th / 100;
   7978         if (imbalance_max_th_kbytes > 0xfffff) {
   7979             /* Hardware limits imbalance threshold in kbytes to 1 sign bit
   7980              * plus 20 bits.
   7981              */
   7982             return BCM_E_PARAM;
   7983         }
   7984         SOC_IF_ERROR_RETURN(READ_DLB_ECMP_VLA_MEMBER_IMBALANCE_THRESHOLDm(unit,
   7985                     MEM_BLOCK_ANY, i, &imbalance_threshold_entry));
   7986         for (j = 0; j < num_imbalance_th; j++) {
   7987             imbalance_th_kbytes = exp_load_th_kbytes *
   7988                 (imbalance_min_th + j * imbalance_th_increment) / 100;
   7989             if (imbalance_th_kbytes < 0) {
   7990                 /* Convert to two's complement representation */
   7991                 imbalance_th_kbytes = -1 * imbalance_th_kbytes;
   7992                 imbalance_th_kbytes = (~imbalance_th_kbytes) + 1;
   7993             } 
   7994             soc_DLB_ECMP_VLA_MEMBER_IMBALANCE_THRESHOLDm_field32_set(unit,
   7995                     &imbalance_threshold_entry, imbalance_th_fields[j],
   7996                     imbalance_th_kbytes & 0x1fffff);
   7997         }
   7998         SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_VLA_MEMBER_IMBALANCE_THRESHOLDm(unit,
   7999                     MEM_BLOCK_ALL, i, &imbalance_threshold_entry));
   8000     }
   8001 
   8002     ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th = imbalance_min_th;
   8003     ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th = imbalance_max_th;
   8004 
   8005     return BCM_E_NONE;
   8006 }
   8007 
   8008 /*
   8009  * Function:
   8010  *      _bcm_tr3_ecmp_dlb_sample_rate_set
   8011  * Purpose:
   8012  *      Set ECMP dynamic load balancing sample rate.
   8013  * Parameters:
   8014  *      unit - (IN) SOC unit number.
   8015  *      sample_rate - (IN) Number of samplings per second.
   8016  * Returns:
   8017  *      BCM_E_xxx
   8018  */
   8019 STATIC int
   8020 _bcm_tr3_ecmp_dlb_sample_rate_set(int unit, int sample_rate)
   8021 {
   8022     BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_sample_rate_pla_thresholds_set(unit,
   8023                 sample_rate, ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th,
   8024                 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th));
   8025 
   8026     BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_sample_rate_vla_thresholds_set(unit,
   8027                 sample_rate, ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_min_th,
   8028                 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_max_th,
   8029                 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th,
   8030                 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th));
   8031 
   8032     return BCM_E_NONE;
   8033 }
   8034 
   8035 /*
   8036  * Function:
   8037  *      _bcm_tr3_ecmp_dlb_tx_load_min_th_set
   8038  * Purpose:
   8039  *      Set ECMP DLB port load minimum threshold.
   8040  * Parameters:
   8041  *      unit - (IN) SOC unit number.
   8042  *      min_th - (IN) Minimum port loading threshold.
   8043  * Returns:
   8044  *      BCM_E_xxx
   8045  */
   8046 STATIC int
   8047 _bcm_tr3_ecmp_dlb_tx_load_min_th_set(int unit, int min_th)
   8048 {
   8049     BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_sample_rate_pla_thresholds_set(unit,
   8050                 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate, min_th,
   8051                 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th));
   8052     return BCM_E_NONE;
   8053 }
   8054 
   8055 /*
   8056  * Function:
   8057  *      _bcm_trident_ecmp_dlb_tx_load_max_th_set
   8058  * Purpose:
   8059  *      Set LAG DLB port load maximum threshold.
   8060  * Parameters:
   8061  *      unit - (IN) SOC unit number.
   8062  *      max_th - (IN) Maximum port loading threshold.
   8063  * Returns:
   8064  *      BCM_E_xxx
   8065  */
   8066 STATIC int
   8067 _bcm_tr3_ecmp_dlb_tx_load_max_th_set(int unit, int max_th)
   8068 {
   8069     BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_sample_rate_pla_thresholds_set(unit,
   8070                 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate,
   8071                 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th,
   8072                 max_th));
   8073     return BCM_E_NONE;
   8074 }
   8075 
   8076 /*
   8077  * Function:
   8078  *      _bcm_tr3_ecmp_dlb_exp_load_min_th_set
   8079  * Purpose:
   8080  *      Set ECMP DLB expected load minimum threshold.
   8081  * Parameters:
   8082  *      unit - (IN) SOC unit number.
   8083  *      min_th - (IN) Minimum expected load threshold.
   8084  * Returns:
   8085  *      BCM_E_xxx
   8086  */
   8087 STATIC int
   8088 _bcm_tr3_ecmp_dlb_exp_load_min_th_set(int unit, int min_th)
   8089 {
   8090     BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_sample_rate_vla_thresholds_set(unit,
   8091                 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate,
   8092                 min_th,
   8093                 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_max_th,
   8094                 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th,
   8095                 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th));
   8096     return BCM_E_NONE;
   8097 }
   8098 
   8099 /*
   8100  * Function:
   8101  *      _bcm_tr3_ecmp_dlb_exp_load_max_th_set
   8102  * Purpose:
   8103  *      Set ECMP DLB expected load maximum threshold.
   8104  * Parameters:
   8105  *      unit - (IN) SOC unit number.
   8106  *      max_th - (IN) Maximum expected load threshold.
   8107  * Returns:
   8108  *      BCM_E_xxx
   8109  */
   8110 STATIC int
   8111 _bcm_tr3_ecmp_dlb_exp_load_max_th_set(int unit, int max_th)
   8112 {
   8113     BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_sample_rate_vla_thresholds_set(unit,
   8114                 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate,
   8115                 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_min_th,
   8116                 max_th,
   8117                 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th,
   8118                 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th));
   8119     return BCM_E_NONE;
   8120 }
   8121 
   8122 /*
   8123  * Function:
   8124  *      _bcm_tr3_ecmp_dlb_imbalance_min_th_set
   8125  * Purpose:
   8126  *      Set ECMP DLB member imbalance minimum threshold.
   8127  * Parameters:
   8128  *      unit - (IN) SOC unit number.
   8129  *      min_th - (IN) Minimum member imbalance threshold.
   8130  * Returns:
   8131  *      BCM_E_xxx
   8132  */
   8133 STATIC int
   8134 _bcm_tr3_ecmp_dlb_imbalance_min_th_set(int unit, int min_th)
   8135 {
   8136     BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_sample_rate_vla_thresholds_set(unit,
   8137                 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate,
   8138                 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_min_th,
   8139                 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_max_th,
   8140                 min_th,
   8141                 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th));
   8142     return BCM_E_NONE;
   8143 }
   8144 
   8145 /*
   8146  * Function:
   8147  *      _bcm_tr3_ecmp_dlb_imbalance_max_th_set
   8148  * Purpose:
   8149  *      Set ECMP DLB member imbalance maximum threshold.
   8150  * Parameters:
   8151  *      unit - (IN) SOC unit number.
   8152  *      max_th - (IN) Maximum member imbalance threshold.
   8153  * Returns:
   8154  *      BCM_E_xxx
   8155  */
   8156 STATIC int
   8157 _bcm_tr3_ecmp_dlb_imbalance_max_th_set(int unit, int max_th)
   8158 {
   8159     BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_sample_rate_vla_thresholds_set(unit,
   8160                 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate,
   8161                 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_min_th,
   8162                 ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_max_th,
   8163                 ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th,
   8164                 max_th));
   8165     return BCM_E_NONE;
   8166 }
   8167 
   8168 /*
   8169  * Function:
   8170  *      _bcm_tr3_ecmp_dlb_qsize_thresholds_set
   8171  * Purpose:
   8172  *      Set LAG DLB queue size thresholds.
   8173  * Parameters:
   8174  *      unit - (IN) SOC unit number.
   8175  *      min_th - (IN) Minimum queue size threshold, in bytes.
   8176  *      max_th - (IN) Maximum queue size threshold, in bytes.
   8177  * Returns:
   8178  *      BCM_E_xxx
   8179  */
   8180 STATIC int
   8181 _bcm_tr3_ecmp_dlb_qsize_thresholds_set(int unit, int min_th, int max_th)
   8182 {
   8183     int max_th_cells;
   8184     int th_increment;
   8185     dlb_ecmp_pla_quantize_threshold_entry_t quantize_threshold_entry;
   8186     int i;
   8187     int th_cells[7];
   8188 
   8189     if (min_th < 0 || max_th < 0) {
   8190         return BCM_E_PARAM;
   8191     }
   8192 
   8193     if (min_th > max_th) {
   8194         max_th = min_th;
   8195     }
   8196 
   8197     /* Convert threshold to number of cells */
   8198     max_th_cells = max_th / 208;
   8199     if (max_th_cells > 0xffff) {
   8200         /* Hardware limits queue size threshold to 16 bits */
   8201         return BCM_E_PARAM;
   8202     }
   8203 
   8204     /* Use min threshold as threshold 0, and max threshold as threshold 6.
   8205      * Thresholds 1 to 5 will be evenly spread out between min and max
   8206      * thresholds.
   8207      */
   8208     th_increment = (max_th - min_th) / 6;
   8209     for (i = 0; i < 7; i++) {
   8210         SOC_IF_ERROR_RETURN
   8211             (READ_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm(unit, MEM_BLOCK_ANY, i,
   8212                                               &quantize_threshold_entry));
   8213         th_cells[i] = (min_th + i * th_increment) / 208;
   8214         soc_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm_field32_set
   8215             (unit, &quantize_threshold_entry, THRESHOLD_HIST_QSIZEf,
   8216              th_cells[i]);
   8217         SOC_IF_ERROR_RETURN
   8218             (WRITE_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm(unit, MEM_BLOCK_ALL, i,
   8219                                                &quantize_threshold_entry));
   8220     }
   8221 
   8222     ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th = min_th;
   8223     ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th = max_th;
   8224 
   8225     return BCM_E_NONE;
   8226 }
   8227 
   8228 /*
   8229  * Function:
   8230  *      _bcm_tr3_ecmp_dlb_qsize_min_th_set
   8231  * Purpose:
   8232  *      Set LAG DLB queue size minimum threshold.
   8233  * Parameters:
   8234  *      unit - (IN) SOC unit number.
   8235  *      min_th - (IN) Minimum queue size threshold, in bytes.
   8236  * Returns:
   8237  *      BCM_E_xxx
   8238  */
   8239 STATIC int
   8240 _bcm_tr3_ecmp_dlb_qsize_min_th_set(int unit, int min_th)
   8241 {
   8242     BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_qsize_thresholds_set(unit,
   8243                 min_th, ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th));
   8244 
   8245     return BCM_E_NONE;
   8246 }
   8247 
   8248 /*
   8249  * Function:
   8250  *      _bcm_tr3_ecmp_dlb_qsize_max_th_set
   8251  * Purpose:
   8252  *      Set LAG DLB queue size maximum threshold.
   8253  * Parameters:
   8254  *      unit - (IN) SOC unit number.
   8255  *      max_th - (IN) Maximum queue size threshold, in bytes.
   8256  * Returns:
   8257  *      BCM_E_xxx
   8258  */
   8259 STATIC int
   8260 _bcm_tr3_ecmp_dlb_qsize_max_th_set(int unit, int max_th)
   8261 {
   8262     BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_qsize_thresholds_set(unit,
   8263                 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th, max_th));
   8264 
   8265     return BCM_E_NONE;
   8266 }
   8267 
   8268 /*
   8269  * Function:
   8270  *      _bcm_tr3_ecmp_dlb_tx_load_weight_set
   8271  * Purpose:
   8272  *      Set LAG DLB port load weight.
   8273  * Parameters:
   8274  *      unit - (IN) SOC unit number.
   8275  *      weight - (IN) Port load weight.
   8276  * Returns:
   8277  *      BCM_E_xxx
   8278  */
   8279 STATIC int
   8280 _bcm_tr3_ecmp_dlb_tx_load_weight_set(int unit, int weight)
   8281 {
   8282     uint32 measure_control_reg;
   8283 
   8284     if (weight < 0 || 
   8285         weight > 0xf) {
   8286         /* Hardware limits port load weight to 4 bits */
   8287         return BCM_E_PARAM;
   8288     }
   8289 
   8290     SOC_IF_ERROR_RETURN
   8291         (READ_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   8292     soc_reg_field_set(unit, DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr,
   8293         &measure_control_reg, PLA_WEIGHT_LOADINGf, weight);
   8294     SOC_IF_ERROR_RETURN
   8295         (WRITE_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg));
   8296     return BCM_E_NONE;
   8297 }
   8298 
   8299 /*
   8300  * Function:
   8301  *      _bcm_tr3_ecmp_dlb_tx_load_weight_get
   8302  * Purpose:
   8303  *      Get LAG DLB port load weight.
   8304  * Parameters:
   8305  *      unit - (IN) SOC unit number.
   8306  *      weight - (OUT) Port load weight.
   8307  * Returns:
   8308  *      BCM_E_xxx
   8309  */
   8310 STATIC int
   8311 _bcm_tr3_ecmp_dlb_tx_load_weight_get(int unit, int *weight)
   8312 {
   8313     uint32 measure_control_reg;
   8314 
   8315     SOC_IF_ERROR_RETURN
   8316         (READ_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   8317     *weight = soc_reg_field_get(unit, DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr,
   8318         measure_control_reg, PLA_WEIGHT_LOADINGf);
   8319 
   8320     return BCM_E_NONE;
   8321 }
   8322 
   8323 /*
   8324  * Function:
   8325  *      _bcm_tr3_ecmp_dlb_qsize_weight_set
   8326  * Purpose:
   8327  *      Set LAG DLB qsize weight.
   8328  * Parameters:
   8329  *      unit - (IN) SOC unit number.
   8330  *      weight - (IN) Qsize weight.
   8331  * Returns:
   8332  *      BCM_E_xxx
   8333  */
   8334 STATIC int
   8335 _bcm_tr3_ecmp_dlb_qsize_weight_set(int unit, int weight)
   8336 {
   8337     uint32 measure_control_reg;
   8338 
   8339     if (weight < 0 || 
   8340         weight > 0xf) {
   8341         /* Hardware limits qsize weight to 4 bits */
   8342         return BCM_E_PARAM;
   8343     }
   8344 
   8345     SOC_IF_ERROR_RETURN
   8346         (READ_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   8347     soc_reg_field_set(unit, DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr,
   8348         &measure_control_reg, PLA_WEIGHT_QSIZEf, weight);
   8349     SOC_IF_ERROR_RETURN
   8350         (WRITE_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg));
   8351     return BCM_E_NONE;
   8352 }
   8353 
   8354 /*
   8355  * Function:
   8356  *      _bcm_tr3_ecmp_dlb_qsize_weight_get
   8357  * Purpose:
   8358  *      Get LAG DLB qsize weight.
   8359  * Parameters:
   8360  *      unit - (IN) SOC unit number.
   8361  *      weight - (OUT) Qsize weight.
   8362  * Returns:
   8363  *      BCM_E_xxx
   8364  */
   8365 STATIC int
   8366 _bcm_tr3_ecmp_dlb_qsize_weight_get(int unit, int *weight)
   8367 {
   8368     uint32 measure_control_reg;
   8369 
   8370     SOC_IF_ERROR_RETURN
   8371         (READ_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   8372     *weight = soc_reg_field_get(unit, DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr,
   8373         measure_control_reg, PLA_WEIGHT_QSIZEf);
   8374 
   8375     return BCM_E_NONE;
   8376 }
   8377 
   8378 /*
   8379  * Function:
   8380  *      _bcm_tr3_ecmp_dlb_tx_load_cap_set
   8381  * Purpose:
   8382  *      Set LAG DLB port load cap control.
   8383  * Parameters:
   8384  *      unit - (IN) SOC unit number.
   8385  *      cap - (IN) Port load cap control.
   8386  * Returns:
   8387  *      BCM_E_xxx
   8388  */
   8389 STATIC int
   8390 _bcm_tr3_ecmp_dlb_tx_load_cap_set(int unit, int cap)
   8391 {
   8392     uint32 measure_control_reg;
   8393 
   8394     if (cap < 0 || 
   8395         cap > 1) {
   8396         /* Hardware limits port load cap control to 1 bit */
   8397         return BCM_E_PARAM;
   8398     }
   8399 
   8400     SOC_IF_ERROR_RETURN
   8401         (READ_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   8402     soc_reg_field_set(unit, DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr,
   8403         &measure_control_reg, PLA_CAP_LOADING_AVGf, cap);
   8404     SOC_IF_ERROR_RETURN
   8405         (WRITE_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg));
   8406     return BCM_E_NONE;
   8407 }
   8408 
   8409 /*
   8410  * Function:
   8411  *      _bcm_tr3_ecmp_dlb_tx_load_cap_get
   8412  * Purpose:
   8413  *      Get LAG DLB port load cap control.
   8414  * Parameters:
   8415  *      unit - (IN) SOC unit number.
   8416  *      cap - (OUT) Cap control.
   8417  * Returns:
   8418  *      BCM_E_xxx
   8419  */
   8420 STATIC int
   8421 _bcm_tr3_ecmp_dlb_tx_load_cap_get(int unit, int *cap)
   8422 {
   8423     uint32 measure_control_reg;
   8424 
   8425     SOC_IF_ERROR_RETURN
   8426         (READ_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   8427     *cap= soc_reg_field_get(unit, DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr,
   8428         measure_control_reg, PLA_CAP_LOADING_AVGf);
   8429 
   8430     return BCM_E_NONE;
   8431 }
   8432 /*
   8433  * Function:
   8434  *      _bcm_tr3_ecmp_dlb_qsize_cap_set
   8435  * Purpose:
   8436  *      Set LAG DLB queue size cap control.
   8437  * Parameters:
   8438  *      unit - (IN) SOC unit number.
   8439  *      cap - (IN) Queue size cap control.
   8440  * Returns:
   8441  *      BCM_E_xxx
   8442  */
   8443 STATIC int
   8444 _bcm_tr3_ecmp_dlb_qsize_cap_set(int unit, int cap)
   8445 {
   8446     uint32 measure_control_reg;
   8447 
   8448     if (cap < 0 || 
   8449         cap > 1) {
   8450         /* Hardware limits port load cap control to 1 bit */
   8451         return BCM_E_PARAM;
   8452     }
   8453 
   8454     SOC_IF_ERROR_RETURN
   8455         (READ_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   8456     soc_reg_field_set(unit, DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr,
   8457         &measure_control_reg, PLA_CAP_QSIZE_AVGf, cap);
   8458     SOC_IF_ERROR_RETURN
   8459         (WRITE_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg));
   8460     return BCM_E_NONE;
   8461 }
   8462 
   8463 /*
   8464  * Function:
   8465  *      _bcm_tr3_ecmp_dlb_qsize_cap_get
   8466  * Purpose:
   8467  *      Get LAG DLB queue size cap control.
   8468  * Parameters:
   8469  *      unit - (IN) SOC unit number.
   8470  *      cap - (OUT) Cap control.
   8471  * Returns:
   8472  *      BCM_E_xxx
   8473  */
   8474 STATIC int
   8475 _bcm_tr3_ecmp_dlb_qsize_cap_get(int unit, int *cap)
   8476 {
   8477     uint32 measure_control_reg;
   8478 
   8479     SOC_IF_ERROR_RETURN
   8480         (READ_DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg));
   8481     *cap= soc_reg_field_get(unit, DLB_ECMP_PLA_QUALITY_MEASURE_CONTROLr,
   8482         measure_control_reg, PLA_CAP_QSIZE_AVGf);
   8483 
   8484     return BCM_E_NONE;
   8485 }
   8486 
   8487 /*
   8488  * Function:
   8489  *      _bcm_tr3_ecmp_dlb_config_set
   8490  * Purpose:
   8491  *      Set per-chip LAG dynamic load balancing configuration parameters.
   8492  * Parameters:
   8493  *      unit - (IN) SOC unit number.
   8494  *      type - (IN) Configuration parameter type.
   8495  *      arg  - (IN) Configuration paramter value.
   8496  * Returns:
   8497  *      BCM_E_xxx
   8498  */
   8499 int
   8500 _bcm_tr3_ecmp_dlb_config_set(int unit, bcm_switch_control_t type, int arg)
   8501 {
   8502     switch (type) {
   8503         case bcmSwitchEcmpDynamicSampleRate:
   8504             return _bcm_tr3_ecmp_dlb_sample_rate_set(unit, arg);
   8505 
   8506         case bcmSwitchEcmpDynamicAccountingSelect:
   8507             return _bcm_tr3_ecmp_dlb_accounting_set(unit, arg);
   8508 
   8509         case bcmSwitchEcmpDynamicEgressBytesExponent:
   8510             return _bcm_tr3_ecmp_dlb_tx_load_weight_set(unit, arg);
   8511 
   8512         case bcmSwitchEcmpDynamicQueuedBytesExponent:
   8513             return _bcm_tr3_ecmp_dlb_qsize_weight_set(unit, arg);
   8514 
   8515         case bcmSwitchEcmpDynamicEgressBytesDecreaseReset:
   8516             return _bcm_tr3_ecmp_dlb_tx_load_cap_set(unit, arg);
   8517 
   8518         case bcmSwitchEcmpDynamicQueuedBytesDecreaseReset:
   8519             return _bcm_tr3_ecmp_dlb_qsize_cap_set(unit, arg);
   8520 
   8521         case bcmSwitchEcmpDynamicEgressBytesMinThreshold:
   8522             return _bcm_tr3_ecmp_dlb_tx_load_min_th_set(unit, arg);
   8523 
   8524         case bcmSwitchEcmpDynamicEgressBytesMaxThreshold:
   8525             return _bcm_tr3_ecmp_dlb_tx_load_max_th_set(unit, arg);
   8526 
   8527         case bcmSwitchEcmpDynamicQueuedBytesMinThreshold:
   8528             return _bcm_tr3_ecmp_dlb_qsize_min_th_set(unit, arg);
   8529 
   8530         case bcmSwitchEcmpDynamicQueuedBytesMaxThreshold:
   8531             return _bcm_tr3_ecmp_dlb_qsize_max_th_set(unit, arg);
   8532 
   8533         case bcmSwitchEcmpDynamicExpectedLoadMinThreshold:
   8534             return _bcm_tr3_ecmp_dlb_exp_load_min_th_set(unit, arg);
   8535 
   8536         case bcmSwitchEcmpDynamicExpectedLoadMaxThreshold:
   8537             return _bcm_tr3_ecmp_dlb_exp_load_max_th_set(unit, arg);
   8538 
   8539         case bcmSwitchEcmpDynamicImbalanceMinThreshold:
   8540             return _bcm_tr3_ecmp_dlb_imbalance_min_th_set(unit, arg);
   8541 
   8542         case bcmSwitchEcmpDynamicImbalanceMaxThreshold:
   8543             return _bcm_tr3_ecmp_dlb_imbalance_max_th_set(unit, arg);
   8544 
   8545         default:
   8546             return BCM_E_PARAM;
   8547     }
   8548 }
   8549 
   8550 /*
   8551  * Function:
   8552  *      _bcm_tr3_ecmp_dlb_config_get
   8553  * Purpose:
   8554  *      Get per-chip LAG dynamic load balancing configuration parameters.
   8555  * Parameters:
   8556  *      unit - (IN) SOC unit number.
   8557  *      type - (IN) Configuration parameter type.
   8558  *      arg  - (OUT) Configuration paramter value.
   8559  * Returns:
   8560  *      BCM_E_xxx
   8561  */
   8562 int
   8563 _bcm_tr3_ecmp_dlb_config_get(int unit, bcm_switch_control_t type, int *arg)
   8564 {
   8565     switch (type) {
   8566         case bcmSwitchEcmpDynamicSampleRate:
   8567             *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate;
   8568             break;
   8569 
   8570         case bcmSwitchEcmpDynamicAccountingSelect:
   8571             return _bcm_tr3_ecmp_dlb_accounting_get(unit, arg);
   8572             break;
   8573 
   8574         case bcmSwitchEcmpDynamicEgressBytesExponent:
   8575             return _bcm_tr3_ecmp_dlb_tx_load_weight_get(unit, arg);
   8576 
   8577         case bcmSwitchEcmpDynamicQueuedBytesExponent:
   8578             return _bcm_tr3_ecmp_dlb_qsize_weight_get(unit, arg);
   8579 
   8580         case bcmSwitchEcmpDynamicEgressBytesDecreaseReset:
   8581             return _bcm_tr3_ecmp_dlb_tx_load_cap_get(unit, arg);
   8582 
   8583         case bcmSwitchEcmpDynamicQueuedBytesDecreaseReset:
   8584             return _bcm_tr3_ecmp_dlb_qsize_cap_get(unit, arg);
   8585 
   8586         case bcmSwitchEcmpDynamicEgressBytesMinThreshold:
   8587             *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th;
   8588             break;
   8589 
   8590         case bcmSwitchEcmpDynamicEgressBytesMaxThreshold:
   8591             *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th;
   8592             break;
   8593 
   8594         case bcmSwitchEcmpDynamicQueuedBytesMinThreshold:
   8595             *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th;
   8596             break;
   8597 
   8598         case bcmSwitchEcmpDynamicQueuedBytesMaxThreshold:
   8599             *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th;
   8600             break;
   8601 
   8602         case bcmSwitchEcmpDynamicExpectedLoadMinThreshold:
   8603             *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_min_th;
   8604             break;
   8605 
   8606         case bcmSwitchEcmpDynamicExpectedLoadMaxThreshold:
   8607             *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_max_th;
   8608             break;
   8609 
   8610         case bcmSwitchEcmpDynamicImbalanceMinThreshold:
   8611             *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th;
   8612             break;
   8613 
   8614         case bcmSwitchEcmpDynamicImbalanceMaxThreshold:
   8615             *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th;
   8616             break;
   8617 
   8618         default:
   8619             return BCM_E_PARAM;
   8620     }
   8621 
   8622     return BCM_E_NONE;
   8623 }
   8624 
   8625 /*
   8626  * Function:
   8627  *      _bcm_tr3_ecmp_dlb_quality_map_profile_init
   8628  * Purpose:
   8629  *      Initialize ECMP DLB quality mapping profile.
   8630  * Parameters:
   8631  *      unit - (IN)SOC unit number. 
   8632  * Returns:
   8633  *      BCM_X_XXX
   8634  */
   8635 STATIC int 
   8636 _bcm_tr3_ecmp_dlb_quality_map_profile_init(int unit) 
   8637 {
   8638     soc_profile_mem_t *profile;
   8639     soc_mem_t mem;
   8640     int entry_words;
   8641     int entries_per_profile;
   8642     int tx_load_percent;
   8643     int alloc_size;
   8644     uint32 *entry_arr;
   8645     int rv = BCM_E_NONE;
   8646     void *entries;
   8647     uint32 base_index;
   8648     int i;
   8649     int member_id;
   8650     dlb_ecmp_quality_control_entry_t quality_control_entry;
   8651 
   8652     if (NULL == _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile) {
   8653         _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile =
   8654             sal_alloc(sizeof(soc_profile_mem_t),
   8655                       "ECMP DLB Quality Map Profile Mem");
   8656         if (NULL == _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile) {
   8657             return BCM_E_MEMORY;
   8658         }
   8659     } else {
   8660         soc_profile_mem_destroy(unit,
   8661                 _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile);
   8662     }
   8663     profile = _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile;
   8664     soc_profile_mem_t_init(profile);
   8665 
   8666     mem = DLB_ECMP_QUALITY_MAPPINGm;
   8667     entry_words = sizeof(dlb_ecmp_quality_mapping_entry_t) / sizeof(uint32);
   8668     SOC_IF_ERROR_RETURN
   8669         (soc_profile_mem_create(unit, &mem, &entry_words, 1, profile));
   8670 
   8671     entries_per_profile = 64;
   8672     if (!SOC_WARM_BOOT(unit)) {
   8673         alloc_size = entries_per_profile * entry_words * sizeof(uint32);
   8674         entry_arr = sal_alloc(alloc_size, "ECMP DLB Quality Map entries");
   8675         if (entry_arr == NULL) {
   8676             return BCM_E_MEMORY;
   8677         }
   8678         sal_memset(entry_arr, 0, alloc_size);
   8679 
   8680         /* Assign quality in the entry array, with 100% weight for port load,
   8681          * 0% for queue size.
   8682          */
   8683         tx_load_percent = 100;
   8684         rv = _bcm_tr3_ecmp_dlb_quality_assign(unit, tx_load_percent,
   8685                 entry_arr);
   8686         if (BCM_FAILURE(rv)) {
   8687             sal_free(entry_arr);
   8688             return rv;
   8689         }
   8690 
   8691         entries = entry_arr;
   8692         rv = soc_profile_mem_add(unit, profile, &entries, entries_per_profile,
   8693                 &base_index);
   8694         sal_free(entry_arr);
   8695         if (SOC_FAILURE(rv)) {
   8696             return rv;
   8697         }
   8698 
   8699         for (member_id = 0;
   8700                 member_id < soc_mem_index_count(unit,
   8701                     DLB_ECMP_QUALITY_CONTROLm);
   8702                 member_id++) {
   8703             BCM_IF_ERROR_RETURN
   8704                 (READ_DLB_ECMP_QUALITY_CONTROLm(unit, MEM_BLOCK_ANY,
   8705                                                member_id,
   8706                                                &quality_control_entry));
   8707             soc_DLB_ECMP_QUALITY_CONTROLm_field32_set(unit,
   8708                     &quality_control_entry, PROFILE_PTRf,
   8709                     base_index / entries_per_profile);
   8710             BCM_IF_ERROR_RETURN
   8711                 (WRITE_DLB_ECMP_QUALITY_CONTROLm(unit, MEM_BLOCK_ALL,
   8712                                                 member_id,
   8713                                                 &quality_control_entry));
   8714         }  
   8715 
   8716         for (i = 0; i < entries_per_profile; i++) {
   8717             SOC_PROFILE_MEM_REFERENCE(unit, profile, base_index + i,
   8718                     member_id - 1);
   8719         }
   8720 
   8721         ECMP_DLB_INFO(unit)->
   8722             ecmp_dlb_load_weight[base_index/entries_per_profile] = 
   8723                 tx_load_percent;
   8724 
   8725     } else { /* Warm boot, recover reference counts and entries_per_set */
   8726 
   8727         for (member_id = 0;
   8728                 member_id < soc_mem_index_count(unit,
   8729                     DLB_ECMP_QUALITY_CONTROLm);
   8730                 member_id++) {
   8731             BCM_IF_ERROR_RETURN
   8732                 (READ_DLB_ECMP_QUALITY_CONTROLm(unit, MEM_BLOCK_ANY,
   8733                                                member_id,
   8734                                                &quality_control_entry));
   8735             base_index = soc_DLB_ECMP_QUALITY_CONTROLm_field32_get(unit,
   8736                     &quality_control_entry, PROFILE_PTRf);
   8737             base_index *= entries_per_profile;
   8738             for (i = 0; i < entries_per_profile; i++) {
   8739                 SOC_PROFILE_MEM_REFERENCE(unit, profile, base_index + i, 1);
   8740                 SOC_PROFILE_MEM_ENTRIES_PER_SET(unit, profile,
   8741                         base_index + i, entries_per_profile);
   8742             }
   8743         }  
   8744     }
   8745 
   8746     return BCM_E_NONE;
   8747 }
   8748 
   8749 /*
   8750  * Function:
   8751  *      _bcm_tr3_ecmp_dlb_deinit
   8752  * Purpose:
   8753  *      Deallocate _tr3_ecmp_dlb_bk
   8754  * Parameters:
   8755  *      unit - (IN)SOC unit number. 
   8756  * Returns:
   8757  *      None
   8758  */
   8759 void
   8760 _bcm_tr3_ecmp_dlb_deinit(int unit) 
   8761 {
   8762     int rv;
   8763     uint32 rsel2_hw_control_reg;
   8764 
   8765     if (_tr3_ecmp_dlb_bk[unit]) {
   8766         if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_nh_info) {
   8767             sal_free(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_nh_info);
   8768             _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_nh_info = NULL;
   8769         }
   8770         if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap) {
   8771             sal_free(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap);
   8772             _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap = NULL;
   8773         }
   8774         if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap) {
   8775             sal_free(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap);
   8776             _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap = NULL;
   8777         }
   8778         if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_member_id_used_bitmap) {
   8779             sal_free(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_member_id_used_bitmap);
   8780             _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_member_id_used_bitmap = NULL;
   8781         }
   8782         if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight) {
   8783             sal_free(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight);
   8784             _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight = NULL;
   8785         }
   8786         if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile) {
   8787             soc_profile_mem_destroy(unit,
   8788                     _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile);
   8789             sal_free(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile);
   8790             _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile = NULL;
   8791         }
   8792 
   8793         sal_free(_tr3_ecmp_dlb_bk[unit]);
   8794         _tr3_ecmp_dlb_bk[unit] = NULL;
   8795     }
   8796 
   8797     rv = READ_RSEL2_HW_CONTROLr(unit, &rsel2_hw_control_reg);
   8798     if (SOC_SUCCESS(rv)) {
   8799         soc_reg_field_set(unit, RSEL2_HW_CONTROLr, &rsel2_hw_control_reg,
   8800                 ENABLE_ECMP_DLBf, 0);
   8801         (void)WRITE_RSEL2_HW_CONTROLr(unit, rsel2_hw_control_reg);
   8802     }
   8803 }
   8804 
   8805 /*
   8806  * Function:
   8807  *      _bcm_tr3_ecmp_dlb_init
   8808  * Purpose:
   8809  *      Allocate and initialize _tr3_ecmp_dlb_bk
   8810  * Parameters:
   8811  *      unit - (IN)SOC unit number. 
   8812  * Returns:
   8813  *      BCM_X_XXX
   8814  */
   8815 int 
   8816 _bcm_tr3_ecmp_dlb_init(int unit) 
   8817 {
   8818     int rv = BCM_E_NONE;
   8819     int num_ecmp_dlb_id;
   8820     int flowset_tbl_size;
   8821     int total_num_blocks;
   8822     int num_ecmp_dlb_member_id;
   8823     int num_quality_map_profiles;
   8824     int member_id;
   8825     dlb_ecmp_quality_control_entry_t quality_control_entry;
   8826     uint32 rsel2_hw_control_reg;
   8827     uint32 measure_control_reg;
   8828     int max_ecmp_dlb_next_hops;
   8829     int sample_rate;
   8830 
   8831     _bcm_tr3_ecmp_dlb_deinit(unit);
   8832 
   8833     if (_tr3_ecmp_dlb_bk[unit] == NULL) {
   8834         _tr3_ecmp_dlb_bk[unit] = sal_alloc(
   8835                 sizeof(_tr3_ecmp_dlb_bookkeeping_t), "_tr3_ecmp_dlb_bk");
   8836         if (_tr3_ecmp_dlb_bk[unit] == NULL) {
   8837             return BCM_E_MEMORY;
   8838         }
   8839     }
   8840     sal_memset(_tr3_ecmp_dlb_bk[unit], 0, sizeof(_tr3_ecmp_dlb_bookkeeping_t));
   8841 
   8842     max_ecmp_dlb_next_hops = soc_mem_index_count(unit,
   8843             DLB_ECMP_MEMBER_ATTRIBUTEm);
   8844     if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_nh_info == NULL) {
   8845         _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_nh_info = 
   8846             sal_alloc(sizeof(_tr3_ecmp_dlb_nh_info_t) * max_ecmp_dlb_next_hops,
   8847                     "ecmp_dlb_nh_info");
   8848         if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_nh_info == NULL) {
   8849             _bcm_tr3_ecmp_dlb_deinit(unit);
   8850             return BCM_E_MEMORY;
   8851         }
   8852     }
   8853     sal_memset(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_nh_info, 0,
   8854             sizeof(_tr3_ecmp_dlb_nh_info_t) * max_ecmp_dlb_next_hops);
   8855     _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_nh_info_size = max_ecmp_dlb_next_hops;
   8856 
   8857     num_ecmp_dlb_id = soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm);
   8858     if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap == NULL) {
   8859         _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap = 
   8860             sal_alloc(SHR_BITALLOCSIZE(num_ecmp_dlb_id),
   8861                     "ecmp_dlb_id_used_bitmap");
   8862         if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap == NULL) {
   8863             _bcm_tr3_ecmp_dlb_deinit(unit);
   8864             return BCM_E_MEMORY;
   8865         }
   8866     }
   8867     sal_memset(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap, 0,
   8868             SHR_BITALLOCSIZE(num_ecmp_dlb_id));
   8869 
   8870     flowset_tbl_size = soc_mem_index_count(unit, DLB_ECMP_FLOWSETm);
   8871     /* Each bit in ecmp_dlb_flowset_block_bitmap corresponds to a block of 512
   8872      * flow set table entries.
   8873      */
   8874     total_num_blocks = flowset_tbl_size / 512;
   8875     if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap == NULL) {
   8876         _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap = 
   8877             sal_alloc(SHR_BITALLOCSIZE(total_num_blocks),
   8878                     "ecmp_dlb_flowset_block_bitmap");
   8879         if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap == NULL) {
   8880             _bcm_tr3_ecmp_dlb_deinit(unit);
   8881             return BCM_E_MEMORY;
   8882         }
   8883     }
   8884     sal_memset(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap, 0,
   8885             SHR_BITALLOCSIZE(total_num_blocks));
   8886 
   8887     num_ecmp_dlb_member_id = soc_mem_index_count(unit,
   8888             DLB_ECMP_MEMBER_ATTRIBUTEm);
   8889     if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_member_id_used_bitmap == NULL) {
   8890         _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_member_id_used_bitmap = 
   8891             sal_alloc(SHR_BITALLOCSIZE(num_ecmp_dlb_member_id),
   8892                     "ecmp_dlb_member_id_used_bitmap");
   8893         if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_member_id_used_bitmap == NULL) {
   8894             _bcm_tr3_ecmp_dlb_deinit(unit);
   8895             return BCM_E_MEMORY;
   8896         }
   8897     }
   8898     sal_memset(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_member_id_used_bitmap, 0,
   8899                 SHR_BITALLOCSIZE(num_ecmp_dlb_member_id));
   8900 
   8901     num_quality_map_profiles = 1 << soc_mem_field_length(unit,
   8902             DLB_ECMP_QUALITY_CONTROLm, PROFILE_PTRf);
   8903     if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight == NULL) {
   8904         _tr3_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight = 
   8905             sal_alloc(num_quality_map_profiles * sizeof(uint8),
   8906                     "ecmp_dlb_load_weight");
   8907         if (_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight == NULL) {
   8908             _bcm_tr3_ecmp_dlb_deinit(unit);
   8909             return BCM_E_MEMORY;
   8910         }
   8911     }
   8912     sal_memset(_tr3_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight, 0,
   8913             num_quality_map_profiles * sizeof(uint8));
   8914 
   8915     /* Initialize port quality mapping profile */
   8916     rv = _bcm_tr3_ecmp_dlb_quality_map_profile_init(unit);
   8917     if (BCM_FAILURE(rv)) {
   8918         _bcm_tr3_ecmp_dlb_deinit(unit);
   8919         return rv;
   8920     }
   8921 
   8922     if (!SOC_WARM_BOOT(unit)) {
   8923 
   8924         /* Configure accounting mode to physical link accounting */
   8925         rv = _bcm_tr3_ecmp_dlb_config_set(unit,
   8926                 bcmSwitchEcmpDynamicAccountingSelect, 0);
   8927         if (BCM_FAILURE(rv)) {
   8928             _bcm_tr3_ecmp_dlb_deinit(unit);
   8929             return rv;
   8930         }
   8931 
   8932         /* Set DLB sampling period and thresholds */
   8933         sample_rate = 1000;
   8934         rv = _bcm_tr3_ecmp_dlb_sample_rate_pla_thresholds_set(unit, sample_rate,
   8935                 125, 875);
   8936         if (BCM_FAILURE(rv)) {
   8937             _bcm_tr3_ecmp_dlb_deinit(unit);
   8938             return rv;
   8939         }
   8940         rv = _bcm_tr3_ecmp_dlb_sample_rate_vla_thresholds_set(unit, sample_rate,
   8941                 125, 875, -75, 75);
   8942         if (BCM_FAILURE(rv)) {
   8943             _bcm_tr3_ecmp_dlb_deinit(unit);
   8944             return rv;
   8945         }
   8946 
   8947         /* Configure LAG DLB load EWMA weight */
   8948         rv = _bcm_tr3_ecmp_dlb_config_set(unit,
   8949                 bcmSwitchEcmpDynamicEgressBytesExponent, 0);
   8950         if (BCM_FAILURE(rv)) {
   8951             _bcm_tr3_ecmp_dlb_deinit(unit);
   8952             return rv;
   8953         }
   8954 
   8955         /* Configure LAG DLB queue size EWMA weight */
   8956         rv = _bcm_tr3_ecmp_dlb_config_set(unit,
   8957                 bcmSwitchEcmpDynamicQueuedBytesExponent, 0);
   8958         if (BCM_FAILURE(rv)) {
   8959             _bcm_tr3_ecmp_dlb_deinit(unit);
   8960             return rv;
   8961         }
   8962 
   8963         /* Configure LAG DLB load cap control */
   8964         rv = _bcm_tr3_ecmp_dlb_config_set(unit,
   8965                 bcmSwitchEcmpDynamicEgressBytesDecreaseReset, 0);
   8966         if (BCM_FAILURE(rv)) {
   8967             _bcm_tr3_ecmp_dlb_deinit(unit);
   8968             return rv;
   8969         }
   8970 
   8971         /* Configure LAG DLB queue size cap control */
   8972         rv = _bcm_tr3_ecmp_dlb_config_set(unit,
   8973                 bcmSwitchEcmpDynamicQueuedBytesDecreaseReset, 0);
   8974         if (BCM_FAILURE(rv)) {
   8975             _bcm_tr3_ecmp_dlb_deinit(unit);
   8976             return rv;
   8977         }
   8978 
   8979         /* Configure LAG DLB queue size thresholds */
   8980         rv = _bcm_tr3_ecmp_dlb_qsize_thresholds_set(unit, 0, 0);
   8981         if (BCM_FAILURE(rv)) {
   8982             _bcm_tr3_ecmp_dlb_deinit(unit);
   8983             return rv;
   8984         }
   8985 
   8986         /* Disable link status override by software */
   8987         rv = soc_mem_clear(unit, DLB_ECMP_MEMBER_SW_STATEm, MEM_BLOCK_ALL, 0);
   8988         if (BCM_FAILURE(rv)) {
   8989             _bcm_tr3_ecmp_dlb_deinit(unit);
   8990             return rv;
   8991         }
   8992 
   8993         /* Clear group membership */
   8994         rv = soc_mem_clear(unit, DLB_ECMP_GROUP_MEMBERSHIPm, MEM_BLOCK_ALL, 0);
   8995         if (BCM_FAILURE(rv)) {
   8996             _bcm_tr3_ecmp_dlb_deinit(unit);
   8997             return rv;
   8998         }
   8999 
   9000         /* Clear port<->member mapping tables */
   9001         rv = soc_mem_clear(unit, DLB_ECMP_MEMBERSHIP_REVERSE_MAPm,
   9002                 MEM_BLOCK_ALL, 0);
   9003         if (BCM_FAILURE(rv)) {
   9004             _bcm_tr3_ecmp_dlb_deinit(unit);
   9005             return rv;
   9006         }
   9007         rv = soc_mem_clear(unit, DLB_ECMP_MEMBER_ATTRIBUTEm, MEM_BLOCK_ALL, 0);
   9008         if (BCM_FAILURE(rv)) {
   9009             _bcm_tr3_ecmp_dlb_deinit(unit);
   9010             return rv;
   9011         }
   9012 
   9013         /* Configure per member threshold scaling factor and 
   9014          * quality measure update control.
   9015          */
   9016         for (member_id = 0;
   9017                 member_id < soc_mem_index_count(unit,
   9018                     DLB_ECMP_QUALITY_CONTROLm);
   9019                 member_id++) {
   9020             rv = READ_DLB_ECMP_QUALITY_CONTROLm(unit, MEM_BLOCK_ANY,
   9021                     member_id, &quality_control_entry);
   9022             if (SOC_FAILURE(rv)) {
   9023                 _bcm_tr3_ecmp_dlb_deinit(unit);
   9024                 return rv;
   9025             }
   9026             soc_DLB_ECMP_QUALITY_CONTROLm_field32_set(unit,
   9027                     &quality_control_entry, ENABLE_AVG_CALCf, 1);
   9028             soc_DLB_ECMP_QUALITY_CONTROLm_field32_set(unit,
   9029                     &quality_control_entry, ENABLE_QUALITY_UPDATEf, 1);
   9030             soc_DLB_ECMP_QUALITY_CONTROLm_field32_set(unit,
   9031                     &quality_control_entry, ENABLE_CREDIT_COLLECTIONf, 1);
   9032             soc_DLB_ECMP_QUALITY_CONTROLm_field32_set(unit,
   9033                     &quality_control_entry, LOADING_SCALING_FACTORf, 1);
   9034             soc_DLB_ECMP_QUALITY_CONTROLm_field32_set(unit,
   9035                     &quality_control_entry, QSIZE_SCALING_FACTORf, 1);
   9036             rv = WRITE_DLB_ECMP_QUALITY_CONTROLm(unit, MEM_BLOCK_ALL,
   9037                     member_id, &quality_control_entry);
   9038             if (SOC_FAILURE(rv)) {
   9039                 _bcm_tr3_ecmp_dlb_deinit(unit);
   9040                 return rv;
   9041             }
   9042         }
   9043 
   9044         /* Enable DLB HGT refresh */
   9045         rv = READ_RSEL2_HW_CONTROLr(unit, &rsel2_hw_control_reg);
   9046         if (BCM_SUCCESS(rv)) {
   9047             soc_reg_field_set(unit, RSEL2_HW_CONTROLr, &rsel2_hw_control_reg,
   9048                     ENABLE_ECMP_DLBf, 1);
   9049             rv = WRITE_RSEL2_HW_CONTROLr(unit, rsel2_hw_control_reg);
   9050         }
   9051         if (BCM_FAILURE(rv)) {
   9052             _bcm_tr3_ecmp_dlb_deinit(unit);
   9053             return rv;
   9054         }
   9055 
   9056         /* Configure Ethertype eligibility */
   9057         rv = soc_mem_clear(unit, DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm,
   9058                 MEM_BLOCK_ALL, 0);
   9059         if (BCM_FAILURE(rv)) {
   9060             _bcm_tr3_ecmp_dlb_deinit(unit);
   9061             return rv;
   9062         }
   9063         rv = READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit,
   9064                 &measure_control_reg);
   9065         if (SOC_SUCCESS(rv)) {
   9066             soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   9067                     &measure_control_reg,
   9068                     ETHERTYPE_ELIGIBILITY_CONFIGf, 0);
   9069             soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
   9070                     &measure_control_reg,
   9071                     INNER_OUTER_ETHERTYPE_SELECTIONf, 0);
   9072             rv = WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit,
   9073                     measure_control_reg);
   9074         }
   9075         if (BCM_FAILURE(rv)) {
   9076             _bcm_tr3_ecmp_dlb_deinit(unit);
   9077             return rv;
   9078         }
   9079 
   9080     }
   9081 
   9082     return rv;
   9083 }
   9084 
   9085 /*
   9086  * Function:
   9087  *      _bcm_tr3_l3_host_stat_attach
   9088  * Description:
   9089  *      Attach counters entries to the given L3 host entry
   9090  *
   9091  * Parameters:
   9092  *      unit             - (IN) unit number
   9093  *      info             - (IN) L3 host description  
   9094  *      stat_counter_id  - (IN) Stat Counter ID.
   9095  *
   9096  * Return Value:
   9097  *      BCM_E_XXX
   9098  * Notes:
   9099  *      On BCM56640, the L3 host tables (ISM tables L3_ENTRY_2 and L3_ENTRY_4, 
   9100  *      ESM table EXT_L3_UCAST_DATA_WIDE) may contain a flex stat pointer when 
   9101  *      entry has a dereference next hop (no NEXT_HOP pointer, but the NH info 
   9102  *      instead).  This counter is analogous to what would be in the egress 
   9103  *      object, but is implemented in the ingress and so requires an ingress 
   9104  *      counter pool allocated.
   9105  */
   9106 bcm_error_t
   9107 _bcm_tr3_l3_host_stat_attach(
   9108             int unit,
   9109             bcm_l3_host_t *info,
   9110             uint32 stat_counter_id)
   9111 {
   9112     soc_mem_t                 table[4]={0};
   9113     uint32                    flex_table_index=0;
   9114     bcm_stat_flex_direction_t direction=bcmStatFlexDirectionIngress;
   9115     uint32                    pool_number=0;
   9116     uint32                    base_index=0;
   9117     bcm_stat_flex_mode_t      offset_mode=0;
   9118     bcm_stat_object_t         object=bcmStatObjectIngPort;
   9119     bcm_stat_group_mode_t     group_mode= bcmStatGroupModeSingle;
   9120     uint32                    count=0;
   9121     uint32                     actual_num_tables=0;
   9122     uint32                     num_of_tables=0;
   9123     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   9124 
   9125     _bcm_esw_stat_get_counter_id_info(
   9126                   unit, stat_counter_id,
   9127                   &group_mode,&object,&offset_mode,&pool_number,&base_index);
   9128 
   9129     BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_object(unit,object,&direction));
   9130     BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_group(unit,group_mode));
   9131 
   9132     BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_get_table_info(
   9133                         unit,object,4,&actual_num_tables,&table[0],&direction));
   9134 
   9135     BCM_IF_ERROR_RETURN(_bcm_tr3_l3_host_stat_get_table_info(
   9136                    unit, info,&num_of_tables,&table_info[0]));
   9137     for (count=0; count < num_of_tables ; count++) {
   9138          for (flex_table_index=0; 
   9139               flex_table_index < actual_num_tables ; 
   9140               flex_table_index++) {
   9141               if ((table_info[count].direction == direction) &&
   9142                   (table_info[count].table == table[flex_table_index]) ) {
   9143                   if (direction == bcmStatFlexDirectionIngress) {
   9144                       return _bcm_esw_stat_flex_attach_ingress_table_counters(
   9145                              unit,
   9146                              table_info[count].table,
   9147                              table_info[count].index,
   9148                              offset_mode,
   9149                              base_index,
   9150                              pool_number);
   9151                   } else {
   9152                       return _bcm_esw_stat_flex_attach_egress_table_counters(
   9153                              unit,
   9154                              table_info[count].table,
   9155                              table_info[count].index,
   9156                              0,
   9157                              offset_mode,
   9158                              base_index,
   9159                              pool_number);
   9160                   }
   9161               }
   9162          }
   9163     }
   9164     return BCM_E_NOT_FOUND;
   9165 }
   9166 
   9167 /*
   9168  * Function:
   9169  *      _bcm_tr3_l3_host_stat_detach
   9170  * Description:
   9171  *      Detach counters entries to the given L3 host entry
   9172  *
   9173  * Parameters:
   9174  *      unit             - (IN) unit number
   9175  *      info		 - (IN) L3 host description
   9176  *
   9177  * Return Value:
   9178  *      BCM_E_XXX
   9179  * Notes:
   9180  */
   9181 bcm_error_t
   9182 _bcm_tr3_l3_host_stat_detach(
   9183             int unit,
   9184             bcm_l3_host_t *info)
   9185 {
   9186     uint32                     count=0;
   9187     uint32                     num_of_tables=0;
   9188     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   9189     bcm_error_t                rv = BCM_E_NONE;
   9190     bcm_error_t                err_code[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION] = {BCM_E_NONE};
   9191 
   9192     BCM_IF_ERROR_RETURN(_bcm_tr3_l3_host_stat_get_table_info(
   9193                    unit, info,&num_of_tables,&table_info[0]));
   9194 
   9195     for (count=0; count < num_of_tables ; count++) {
   9196       if (table_info[count].direction == bcmStatFlexDirectionIngress) {
   9197            rv = _bcm_esw_stat_flex_detach_ingress_table_counters(
   9198                          unit,
   9199                          table_info[count].table,
   9200                          table_info[count].index);
   9201            if (BCM_E_NONE != rv &&
   9202                 BCM_E_NONE == err_code[bcmStatFlexDirectionIngress]) {
   9203                 err_code[bcmStatFlexDirectionIngress] = rv;
   9204            }
   9205       } else {
   9206            rv =  _bcm_esw_stat_flex_detach_egress_table_counters(
   9207                           unit,
   9208                           0,
   9209                           table_info[count].table,
   9210                           table_info[count].index);
   9211            if (BCM_E_NONE != rv &&
   9212                 BCM_E_NONE == err_code[bcmStatFlexDirectionEgress]) {
   9213                 err_code[bcmStatFlexDirectionEgress] = rv;
   9214            }
   9215       }
   9216     }
   9217 
   9218     BCM_STAT_FLEX_DETACH_RETURN(err_code)
   9219 }
   9220 
   9221 /*
   9222  * Function:
   9223  *      _bcm_tr3_l3_host_stat_counter_get
   9224  * Description:
   9225  *      Get counter statistic values for specific L3 host entry
   9226  *      if sync_mode is set, sync the sw accumulated count
   9227  *      with hw count value first, else return sw count.  
   9228  *
   9229  * Parameters:
   9230  *      unit             - (IN) unit number
   9231  *      sync_mode        - (IN) hwcount is to be synced to sw count 
   9232  *      info             - (IN) L3 host description
   9233  *      stat             - (IN) Type of the counter to retrieve
   9234  *                              I.e. ingress/egress byte/packet)
   9235  *      num_entries      - (IN) Number of counter Entries
   9236  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   9237  *      counter_values   - (OUT) Pointer to counter values
   9238  *
   9239  * Return Value:
   9240  *      BCM_E_XXX
   9241  * Notes:
   9242  */
   9243 bcm_error_t 
   9244 _bcm_tr3_l3_host_stat_counter_get(int unit,
   9245                                   int sync_mode,
   9246                                   bcm_l3_host_t *info,
   9247                                   bcm_l3_stat_t stat,
   9248                                   uint32 num_entries,
   9249                                   uint32 *counter_indexes,
   9250                                   bcm_stat_value_t *counter_values)
   9251 {
   9252     uint32                          table_count=0;
   9253     uint32                          index_count=0;
   9254     uint32                          num_of_tables=0;
   9255     bcm_stat_flex_direction_t       direction=bcmStatFlexDirectionIngress;
   9256     uint32                          byte_flag=0;
   9257     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   9258 
   9259     if ((stat == bcmL3StatInPackets) ||
   9260         (stat == bcmL3StatInBytes)) {
   9261          direction = bcmStatFlexDirectionIngress;
   9262     } else {
   9263          /* direction = bcmStatFlexDirectionEgress; */
   9264          return BCM_E_PARAM;
   9265     }
   9266     if (stat == bcmL3StatInPackets) {
   9267         byte_flag=0;
   9268     } else {
   9269         byte_flag=1; 
   9270     }
   9271 
   9272     BCM_IF_ERROR_RETURN(_bcm_tr3_l3_host_stat_get_table_info(
   9273                    unit, info,&num_of_tables,&table_info[0]));
   9274 
   9275     for (table_count=0; table_count < num_of_tables ; table_count++) {
   9276       if (table_info[table_count].direction == direction) {
   9277           for (index_count=0; index_count < num_entries ; index_count++) {
   9278                /*ctr_offset_info.offset_index = counter_indexes[index_count];*/
   9279             BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_get(
   9280                          unit, sync_mode,
   9281                          table_info[table_count].index,
   9282                          table_info[table_count].table,
   9283                          0,
   9284                          byte_flag,
   9285                          counter_indexes[index_count],
   9286                          &counter_values[index_count]));
   9287           }
   9288       }
   9289     }
   9290     return BCM_E_NONE;
   9291 }
   9292 
   9293 /*
   9294  * Function:
   9295  *      _bcm_tr3_l3_host_stat_counter_set
   9296  * Description:
   9297  *      Set counter statistic values for specific L3 host entry
   9298  *
   9299  * Parameters:
   9300  *      unit             - (IN) unit number
   9301  *      info             - (IN) L3 host description
   9302  *      stat             - (IN) Type of the counter to retrieve
   9303  *                              I.e. ingress/egress byte/packet)
   9304  *      num_entries      - (IN) Number of counter Entries
   9305  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   9306  *      counter_values   - (IN) Pointer to counter values
   9307  *
   9308  * Return Value:
   9309  *      BCM_E_XXX
   9310  * Notes:
   9311  */
   9312 bcm_error_t 
   9313 _bcm_tr3_l3_host_stat_counter_set(
   9314             int unit,
   9315             bcm_l3_host_t *info,
   9316             bcm_l3_stat_t stat,
   9317             uint32 num_entries,
   9318             uint32 *counter_indexes,
   9319             bcm_stat_value_t *counter_values)
   9320 {
   9321     uint32                          table_count=0;
   9322     uint32                          index_count=0;
   9323     uint32                          num_of_tables=0;
   9324     bcm_stat_flex_direction_t       direction=bcmStatFlexDirectionIngress;
   9325     uint32                          byte_flag=0;
   9326     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   9327     if ((stat == bcmL3StatInPackets) ||
   9328         (stat == bcmL3StatInBytes)) {
   9329          direction = bcmStatFlexDirectionIngress;
   9330     } else {
   9331          /* direction = bcmStatFlexDirectionEgress; */
   9332          return BCM_E_PARAM;
   9333     }
   9334     if (stat == bcmL3StatInPackets) {
   9335         byte_flag=0;
   9336     } else {
   9337         byte_flag=1; 
   9338     }
   9339 
   9340     BCM_IF_ERROR_RETURN(_bcm_tr3_l3_host_stat_get_table_info(
   9341                    unit, info,&num_of_tables,&table_info[0]));
   9342 
   9343     for (table_count=0; table_count < num_of_tables ; table_count++) {
   9344       if (table_info[table_count].direction == direction) {
   9345           for (index_count=0; index_count < num_entries ; index_count++) {
   9346             BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_set(
   9347                                 unit,
   9348                                 table_info[table_count].index,
   9349                                 table_info[table_count].table,
   9350                                 0,
   9351                                 byte_flag,
   9352                                 counter_indexes[index_count],
   9353                                 &counter_values[index_count]));
   9354           }
   9355       }
   9356     }
   9357     return BCM_E_NONE;
   9358 }
   9359 
   9360 /*
   9361  * Function:
   9362  *      _bcm_tr3_l3_host_stat_id_get
   9363  * Description:
   9364  *      Get stat counter id associated with given L3 host entry
   9365  *
   9366  * Parameters:
   9367  *      unit             - (IN) unit number
   9368  *      info             - (IN) L3 host description
   9369  *      stat             - (IN) Type of the counter to retrieve
   9370  *                              I.e. ingress/egress byte/packet)
   9371  *      Stat_counter_id  - (OUT) Stat Counter ID
   9372  * Return Value:
   9373  *      BCM_E_XXX
   9374  * Notes:
   9375  */
   9376 bcm_error_t 
   9377 _bcm_tr3_l3_host_stat_id_get(
   9378             int unit,
   9379             bcm_l3_host_t *info,
   9380             bcm_l3_stat_t stat,
   9381             uint32 *stat_counter_id)
   9382 {
   9383     bcm_stat_flex_direction_t  direction=bcmStatFlexDirectionIngress;
   9384     uint32                     num_of_tables=0;
   9385     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   9386     uint32                     index=0;
   9387     uint32                     num_stat_counter_ids=0;
   9388 
   9389     if ((stat == bcmL3StatInPackets) ||
   9390         (stat == bcmL3StatInBytes)) {
   9391          direction = bcmStatFlexDirectionIngress;
   9392     } else {
   9393          /* direction = bcmStatFlexDirectionEgress; */
   9394          return BCM_E_PARAM;
   9395     }
   9396 
   9397     BCM_IF_ERROR_RETURN(_bcm_tr3_l3_host_stat_get_table_info(
   9398                         unit,info,&num_of_tables,&table_info[0]));
   9399     for (index=0; index < num_of_tables ; index++) {
   9400          if (table_info[index].direction == direction)
   9401              return _bcm_esw_stat_flex_get_counter_id(
   9402                                   unit, 1, &table_info[index],
   9403                                   &num_stat_counter_ids,stat_counter_id);
   9404     }
   9405     return BCM_E_NOT_FOUND;
   9406 }
   9407 
   9408 /*
   9409  * Function:
   9410  *      _bcm_tr3_l3_multicast_nh_add
   9411  * Purpose:
   9412  *      Set L3 multicast next hop entry.
   9413  * Parameters:
   9414  *      unit - (IN) SOC unit number. 
   9415  *      nh_index - (IN) Next hop index. 
   9416  *      l3_egress - (IN) L3 egress structure. 
   9417  * Returns:
   9418  *      BCM_X_XXX
   9419  */
   9420 int 
   9421 _bcm_tr3_l3_ipmc_nh_add(int unit, int nh_index,
   9422         bcm_l3_egress_t *l3_egress) 
   9423 {
   9424     int rv = BCM_E_NONE;
   9425     int nh_index_out;
   9426     ing_l3_next_hop_entry_t ing_nh;
   9427     initial_ing_l3_next_hop_entry_t initial_ing_nh;
   9428     egr_l3_next_hop_entry_t egr_nh;
   9429 #ifdef BCM_TOMAHAWK3_SUPPORT
   9430     egr_l3_next_hop_2_entry_t egr_nh_2;
   9431 #endif
   9432 #if defined(BCM_TRIDENT3_SUPPORT)
   9433     int large_scale_nat_profile_mac = 0;
   9434 #endif
   9435     int i;
   9436     int flag_set;
   9437     int macda_index = -1, use_configured_mac = 0;
   9438 #ifdef BCM_RIOT_SUPPORT
   9439     uint32 nh_dest = 0;
   9440     int vp;
   9441 #endif
   9442     uint32 flag_array[] = {
   9443         BCM_L3_MULTICAST_L2_DEST_PRESERVE,
   9444         BCM_L3_MULTICAST_L2_SRC_PRESERVE,
   9445         BCM_L3_MULTICAST_L2_VLAN_PRESERVE,
   9446         BCM_L3_MULTICAST_TTL_PRESERVE,
   9447         BCM_L3_MULTICAST_DEST_PRESERVE,
   9448         BCM_L3_MULTICAST_SRC_PRESERVE,
   9449         BCM_L3_MULTICAST_VLAN_PRESERVE,
   9450         BCM_L3_MULTICAST_L3_DROP,
   9451         BCM_L3_MULTICAST_L2_DROP
   9452     };
   9453     soc_field_t field_array[] = {
   9454         L3MC__L2_MC_DA_DISABLEf,
   9455         L3MC__L2_MC_SA_DISABLEf,
   9456         L3MC__L2_MC_VLAN_DISABLEf,
   9457         L3MC__L3_MC_TTL_DISABLEf,
   9458         L3MC__L3_MC_DA_DISABLEf,
   9459         L3MC__L3_MC_SA_DISABLEf,
   9460         L3MC__L3_MC_VLAN_DISABLEf,
   9461         L3MC__L3_DROPf,
   9462         L3MC__L2_DROPf
   9463     };
   9464 #if defined(INCLUDE_XFLOW_MACSEC)
   9465     soc_field_t field = INVALIDf, field2 = INVALIDf;
   9466 #endif
   9467 
   9468     if (l3_egress->encap_id == 0) {
   9469         /* encap_id does not contain a VP or a L2 egress object ID. Hence,
   9470          * a L3 egress object is being created on a physical port.
   9471          */
   9472 #if defined(BCM_TOMAHAWK_SUPPORT)
   9473         if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
   9474             rv = _bcm_th_ipmc_l3_intf_next_hop_get(unit, l3_egress->intf,
   9475                                                    &nh_index_out);
   9476         } else
   9477 #endif /* BCM_TOMAHAWK_SUPPORT */
   9478         {
   9479             rv = bcm_tr3_ipmc_l3_intf_next_hop_get(unit, l3_egress->intf,
   9480                                                    &nh_index_out);
   9481         }
   9482         if (rv == BCM_E_NONE) {
   9483             /* IPMC module had already silently allocated a next hop index for the
   9484              * L3 interface, as a result of user adding the L3 interface to an IPMC
   9485              * group directly. Creating a L3 egress object based on such an L3
   9486              * interface is not allowed.
   9487              */
   9488             return BCM_E_CONFIG;
   9489         } else if (rv == BCM_E_NOT_FOUND) {
   9490             /* IPMC module has not silently allocated a next hop index for the L3
   9491              * interface. Inform the IPMC module that a next hop index has been
   9492              * allocated for the L3 interface by the bcm_l3_egress_create API.
   9493              * This is to prevent IPMC module from silently allocating another
   9494              * next hop index when user attempts to add the same L3 interface
   9495              * directly to an IPMC group. Such an attempt will result in BCM_E_CONFIG.
   9496              */
   9497 #if defined(BCM_TOMAHAWK_SUPPORT)
   9498             if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
   9499                 BCM_IF_ERROR_RETURN
   9500                     (_bcm_th_ipmc_l3_intf_next_hop_l3_egress_set(unit,
   9501                                                                  l3_egress->intf));
   9502             } else 
   9503 #endif /* BCM_TOMAHAWK_SUPPORT */
   9504             {
   9505                 BCM_IF_ERROR_RETURN
   9506                     (bcm_tr3_ipmc_l3_intf_next_hop_l3_egress_set(unit, 
   9507                                                                  l3_egress->intf));
   9508             }
   9509         } else {
   9510             return rv;
   9511         }
   9512     }
   9513 
   9514     /* Configure the ingress next hop entry. Although ingress next hop entry
   9515      * is not used by IPMC packet flow, storing port and vlan info in it
   9516      * allows retrieval by bcm_l3_egress_get function.
   9517      */
   9518     SOC_IF_ERROR_RETURN(soc_mem_read(unit, ING_L3_NEXT_HOPm,
   9519                 MEM_BLOCK_ANY, nh_index, &ing_nh));
   9520     soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh,
   9521             VLAN_IDf, l3_egress->vlan);
   9522 
   9523 #ifdef BCM_RIOT_SUPPORT
   9524     /*
   9525     * TD2+ has a separate encoding values for different destinations.
   9526     * If Riot in not enabled then we may need to change this to
   9527     * modid + port combination.
   9528     */
   9529     if (soc_feature(unit, soc_feature_ing_l3_next_hop_encoded_dest)) {
   9530         BCM_IF_ERROR_RETURN(
   9531             bcmi_l3_nh_dest_set(unit, l3_egress, &nh_dest));
   9532             soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, DESTINATIONf,
   9533                 nh_dest);
   9534     } else
   9535 #ifdef BCM_TRIDENT3_SUPPORT
   9536     if (soc_feature(unit, soc_feature_generic_dest)) {
   9537         /* This can handle non-RIOT cases as well */
   9538         bcmi_td3_l3_nh_dest_set(unit, l3_egress, &nh_dest);
   9539         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, DESTINATIONf,
   9540             nh_dest);
   9541     } else
   9542 #endif /* BCM_TRIDENT3_SUPPORT */
   9543 #endif /* BCM_RIOT_SUPPORT */
   9544     {
   9545         /* Set module id. */
   9546         if (l3_egress->flags & BCM_L3_TGID) {
   9547             soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, Tf, 1);
   9548             soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, TGIDf,
   9549                 l3_egress->port);
   9550         } else {
   9551             soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, Tf, 0);
   9552             if (SOC_MEM_FIELD_VALID(unit, ING_L3_NEXT_HOPm, MODULE_IDf)) {
   9553                 soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, MODULE_IDf,
   9554                     l3_egress->module);
   9555             }
   9556             soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, PORT_NUMf,
   9557                 l3_egress->port);
   9558         }
   9559     }
   9560 
   9561     SOC_IF_ERROR_RETURN(soc_mem_write(unit, ING_L3_NEXT_HOPm,
   9562             MEM_BLOCK_ALL, nh_index, &ing_nh));
   9563 
   9564     /* Keep initial ingress next hop entry consistent with
   9565      * ingress next hop entry */
   9566     if (SOC_MEM_IS_VALID(unit, INITIAL_ING_L3_NEXT_HOPm)) {
   9567         SOC_IF_ERROR_RETURN(soc_mem_read(unit, INITIAL_ING_L3_NEXT_HOPm,
   9568                 MEM_BLOCK_ANY, nh_index, &initial_ing_nh));
   9569     }
   9570 
   9571 #ifdef BCM_RIOT_SUPPORT
   9572    /*
   9573     * TD2+ has a separate encoding values for different destinations.
   9574     * If Riot in not enabled then we may need to change this to
   9575     * modid + port combination.
   9576     */
   9577     if (soc_feature(unit, soc_feature_ing_l3_next_hop_encoded_dest)) {
   9578         BCM_IF_ERROR_RETURN(
   9579             bcmi_l3_nh_dest_set(unit, l3_egress, &nh_dest));
   9580             soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm, &ing_nh, DESTINATIONf,
   9581                 nh_dest);
   9582     } else
   9583 #ifdef BCM_TRIDENT3_SUPPORT
   9584     if (soc_feature(unit, soc_feature_generic_dest)) {
   9585         bcmi_td3_l3_nh_dest_set(unit, l3_egress, &nh_dest);
   9586         soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm, &ing_nh, DESTINATIONf,
   9587             nh_dest);
   9588     } else
   9589 #endif  /* BCM_TRIDENT3_SUPPORT */
   9590 #endif  /* BCM_RIOT_SUPPORT */
   9591     if (SOC_MEM_IS_VALID(unit, INITIAL_ING_L3_NEXT_HOPm)) {
   9592         if (l3_egress->flags & BCM_L3_TGID) {
   9593             soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm, &initial_ing_nh,
   9594                 Tf, 1);
   9595             soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm, &initial_ing_nh,
   9596                 TGIDf, l3_egress->port);
   9597         } else {
   9598             soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm, &initial_ing_nh,
   9599                 Tf, 0);
   9600             soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm, &initial_ing_nh,
   9601                 MODULE_IDf, l3_egress->module);
   9602             soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm, &initial_ing_nh,
   9603                 PORT_NUMf, l3_egress->port);
   9604         }
   9605     }
   9606 
   9607     if (SOC_MEM_IS_VALID(unit, INITIAL_ING_L3_NEXT_HOPm)) {
   9608         SOC_IF_ERROR_RETURN(soc_mem_write(unit, INITIAL_ING_L3_NEXT_HOPm,
   9609                     MEM_BLOCK_ALL, nh_index, &initial_ing_nh));
   9610     }
   9611 
   9612 #ifdef BCM_TRIDENT3_SUPPORT
   9613     if (soc_feature(unit, soc_feature_flex_flow) &&
   9614         (l3_egress->flow_handle != 0)) {
   9615 
   9616         return _bcm_td3_l3_flex_nh_add(unit, nh_index, l3_egress, (uint32 *)&egr_nh, 1);
   9617     }
   9618 #endif
   9619     /* Configure the egress next hop entry */
   9620     SOC_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm,
   9621                 MEM_BLOCK_ANY, nh_index, &egr_nh));
   9622 #if defined(BCM_TRIDENT3_SUPPORT)
   9623     if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm, DATA_TYPEf)) {
   9624         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, DATA_TYPEf, 7);
   9625     } else
   9626 #endif
   9627     {
   9628 #ifdef BCM_TOMAHAWK3_SUPPORT
   9629         if (SOC_IS_TOMAHAWK3(unit)) {
   9630             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, ENTRY_TYPEf, 3);
   9631             SOC_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOP_2m,
   9632                         MEM_BLOCK_ANY, nh_index, &egr_nh_2));
   9633         } else
   9634 #endif
   9635         {
   9636             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, ENTRY_TYPEf, 7);
   9637         }
   9638     }
   9639 #ifdef BCM_TOMAHAWK3_SUPPORT
   9640     if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) {
   9641         soc_mem_field32_set(unit, EGR_L3_NEXT_HOP_2m, &egr_nh_2,
   9642                 INTF_NUMf, l3_egress->intf);
   9643     } else
   9644 #endif
   9645     {
   9646         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9647                 L3MC__INTF_NUMf, l3_egress->intf);
   9648     }
   9649 
   9650     for (i = 0; i < COUNTOF(flag_array); i++) {
   9651         if (l3_egress->multicast_flags & flag_array[i]) {
   9652             flag_set = 1;
   9653         } else {
   9654             flag_set = 0;
   9655         }
   9656         if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, field_array[i])) {
   9657             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9658                     field_array[i], flag_set);
   9659         } else {
   9660             if (flag_set) {
   9661                 return BCM_E_PARAM;
   9662             }
   9663         }
   9664     }
   9665 
   9666 #ifdef BCM_TRIDENT2_SUPPORT
   9667     if (soc_feature(unit, soc_feature_virtual_port_routing)) {
   9668         int vp;
   9669         bcm_niv_port_t niv_port;
   9670         int count;
   9671         bcm_niv_egress_t niv_egress;
   9672         int multicast_flag;
   9673         int virtual_interface_id;
   9674         bcm_extender_port_t eport;
   9675         int l2_egr_nh_index;
   9676         egr_l3_next_hop_entry_t l2_egr_nh;
   9677         int etag_dot1p_mapping_ptr = 0;
   9678         bcm_extender_egress_t extender_egress;
   9679         uint16 extended_port_vid;
   9680         uint8 pcp, de;
   9681         uint32 pcp_de_select;
   9682         int qos_map_id;
   9683 
   9684         if (l3_egress->encap_id > 0 &&
   9685                 l3_egress->encap_id < BCM_XGS3_EGRESS_IDX_MIN(unit)) {
   9686             vp = l3_egress->encap_id;
   9687 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   9688             if (soc_feature(unit, soc_feature_egr_l3_next_hop_next_ptr)) {
   9689                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9690                         L3MC__NEXT_PTR_TYPEf, 1);
   9691             } else 
   9692 #endif
   9693             {
   9694                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9695                         L3MC__DVP_VALIDf, 1);
   9696             }
   9697             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9698                     L3MC__DVPf, vp);
   9699             if (_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   9700                 bcm_niv_port_t_init(&niv_port);
   9701                 BCM_GPORT_NIV_PORT_ID_SET(niv_port.niv_port_id, vp);
   9702                 BCM_IF_ERROR_RETURN
   9703                     (bcm_esw_niv_port_get(unit, &niv_port));
   9704                 if (niv_port.flags & BCM_NIV_PORT_MATCH_NONE) {
   9705                     BCM_IF_ERROR_RETURN(bcm_esw_niv_egress_get(unit,
   9706                                 niv_port.niv_port_id, 1, &niv_egress, &count));
   9707                     if (count == 0) {
   9708                         /* No NIV egress object has been added to VP yet. */
   9709                         return BCM_E_CONFIG;
   9710                     }
   9711                     multicast_flag = (niv_egress.flags & BCM_NIV_EGRESS_MULTICAST) ? 1 : 0;
   9712                     if (multicast_flag) {
   9713                         /* Multiple multicast NIV egress object can be
   9714                          * overloaded onto the same VP. In such cases,
   9715                          * L3 egress object should be created on individual
   9716                          * NIV egress object, not the overloaded NIV VP.
   9717                          */
   9718                         return BCM_E_PARAM;
   9719                     }
   9720                     virtual_interface_id = niv_egress.virtual_interface_id;
   9721                 } else {
   9722                     multicast_flag = (niv_port.flags & BCM_NIV_PORT_MULTICAST) ? 1 : 0;
   9723                     virtual_interface_id = niv_port.virtual_interface_id;
   9724                 }
   9725                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9726                         L3MC__VNTAG_ACTIONSf, 1); /* Add or replace VNTAG */
   9727                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9728                         L3MC__VNTAG_DST_VIFf, virtual_interface_id);
   9729                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9730                         L3MC__VNTAG_Pf, multicast_flag);
   9731                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9732                         L3MC__VNTAG_FORCE_Lf, 0);
   9733             } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeExtender)) {
   9734                 bcm_extender_port_t_init(&eport);
   9735                 BCM_GPORT_EXTENDER_PORT_ID_SET(eport.extender_port_id, vp);
   9736                 BCM_IF_ERROR_RETURN
   9737                     (bcm_esw_extender_port_get(unit, &eport));
   9738                 if (eport.flags & BCM_EXTENDER_PORT_MATCH_NONE) {
   9739                     bcm_extender_egress_t_init(&extender_egress);
   9740                     BCM_IF_ERROR_RETURN(bcm_esw_extender_egress_get_all(unit,
   9741                                 eport.extender_port_id, 1, &extender_egress, &count));
   9742                     if (count == 0) {
   9743                         /* No Extender egress object has been added to VP yet. */
   9744                         return BCM_E_CONFIG;
   9745                     }
   9746                     if (extender_egress.flags & BCM_EXTENDER_EGRESS_MULTICAST) {
   9747                         return BCM_E_PARAM;
   9748                     }
   9749                     qos_map_id        = extender_egress.qos_map_id;
   9750                     extended_port_vid = extender_egress.extended_port_vid;
   9751                     pcp_de_select     = extender_egress.pcp_de_select;
   9752                     pcp               = extender_egress.pcp;
   9753                     de                = extender_egress.de;
   9754                 } else {
   9755                     qos_map_id        = eport.qos_map_id;
   9756                     extended_port_vid = eport.extended_port_vid;
   9757                     pcp_de_select     = eport.pcp_de_select;
   9758                     pcp               = eport.pcp;
   9759                     de                = eport.de;
   9760                 }
   9761 
   9762                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9763                         L3MC__VNTAG_ACTIONSf, 2); /* Add or replace ETAG */
   9764                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9765                         L3MC__VNTAG_DST_VIFf, extended_port_vid);
   9766                 if (pcp_de_select == BCM_EXTENDER_PCP_DE_SELECT_DEFAULT) {
   9767                     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9768                             L3MC__ETAG_PCP_DE_SOURCEf, 2);
   9769                     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9770                             L3MC__ETAG_PCPf, pcp);
   9771                     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9772                             L3MC__ETAG_DEf, de);
   9773                 } else if (pcp_de_select == BCM_EXTENDER_PCP_DE_SELECT_PHB) {
   9774                     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9775                             L3MC__ETAG_PCP_DE_SOURCEf, 3);
   9776                     bcm_td2_qos_egr_etag_id2profile(unit, qos_map_id,
   9777                                                     &etag_dot1p_mapping_ptr);
   9778                     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9779                             L3MC__ETAG_DOT1P_MAPPING_PTRf, etag_dot1p_mapping_ptr);
   9780                 }
   9781             } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) {
   9782                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9783                         L3MC__VNTAG_ACTIONSf, 0); /* NOOP */
   9784             } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeFlow)) {
   9785             } else {
   9786                 return BCM_E_PARAM;
   9787             }
   9788         } else if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, l3_egress->encap_id)) {
   9789             uint32 entry_type;
   9790             /* Creating a L3 egress objet on a L2 egress objet */
   9791             l2_egr_nh_index = l3_egress->encap_id - BCM_XGS3_EGRESS_IDX_MIN(unit);
   9792             SOC_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm,
   9793                         MEM_BLOCK_ANY, l2_egr_nh_index, &l2_egr_nh));
   9794 #if defined(BCM_TRIDENT3_SUPPORT)
   9795             if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm, DATA_TYPEf)) {
   9796                 entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &l2_egr_nh,
   9797                                                               DATA_TYPEf);
   9798             } else
   9799 #endif
   9800             {
   9801                 entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &l2_egr_nh,
   9802                                                               ENTRY_TYPEf);
   9803             }
   9804             if (2 != entry_type) {
   9805                 return BCM_E_PARAM;
   9806             }
   9807             vp = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &l2_egr_nh,
   9808                     SD_TAG__DVPf);
   9809             if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   9810                 return BCM_E_PARAM;
   9811             }
   9812             multicast_flag = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
   9813                     &l2_egr_nh, SD_TAG__VNTAG_Pf);
   9814             if (!multicast_flag) {
   9815                 return BCM_E_PARAM;
   9816             }
   9817             virtual_interface_id = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
   9818                     &l2_egr_nh, SD_TAG__VNTAG_DST_VIFf);
   9819 
   9820 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   9821             if (soc_feature(unit, soc_feature_egr_l3_next_hop_next_ptr)) {
   9822                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9823                         L3MC__NEXT_PTR_TYPEf, 1);
   9824             } else 
   9825 #endif
   9826             {
   9827                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9828                         L3MC__DVP_VALIDf, 1);
   9829             }
   9830             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9831                     L3MC__DVPf, vp);
   9832             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9833                     L3MC__VNTAG_ACTIONSf, 1); /* Add or replace VNTAG */
   9834             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9835                     L3MC__VNTAG_DST_VIFf, virtual_interface_id);
   9836             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9837                     L3MC__VNTAG_Pf, multicast_flag);
   9838             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9839                     L3MC__VNTAG_FORCE_Lf, 0);
   9840         } else {
   9841 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   9842             if (soc_feature(unit, soc_feature_egr_l3_next_hop_next_ptr)) {
   9843                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9844                         L3MC__NEXT_PTR_TYPEf, 0);
   9845             } else 
   9846 #endif
   9847             {
   9848                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9849                         L3MC__DVP_VALIDf, 0);
   9850             }
   9851             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9852                     L3MC__VNTAG_ACTIONSf, 0); /* NOOP */
   9853         }
   9854     }
   9855 #endif /* BCM_TRIDENT2_SUPPORT */
   9856 
   9857 #ifdef BCM_RIOT_SUPPORT
   9858     /*
   9859      * TD2Plus and TD3 have multi layer routing.
   9860      * The multicast packet can be routed in the overlay
   9861      * layer and then underlay encapsulation is performed.
   9862      * To achieve this, there will be overlay egr nexthop association
   9863      * with undelray egress next hop.
   9864      * the overlay egr nexthop will point to underlay next hop.
   9865      */
   9866     if (BCMI_RIOT_IS_ENABLED(unit) &&
   9867         _bcm_vp_vfi_type_vp_get(unit, l3_egress->port, &vp)) {
   9868         /* This is a overlay NH case */
   9869         ing_dvp_table_entry_t dvp;
   9870         int vp_nh_index;
   9871         /* Get the vp */
   9872         SOC_IF_ERROR_RETURN
   9873                 (READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp));
   9874 
   9875         /* read vp to get next hop */
   9876         vp_nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp,
   9877                 NEXT_HOP_INDEXf);
   9878 
   9879         /*
   9880          * check if nh-nh association is needed.
   9881          * else set up nh-dvp association
   9882          * NH-NH association will be done for all the
   9883          * nhs other than SDTAG which does not modify any packets field.
   9884          * e.g. on access ports, it may be needed to change a vlan/tpid,
   9885          * in that case, we may have to set nh-nh association else we may
   9886          * setup vlan/tpid from DVP.
   9887          */
   9888          if (bcmi_l3_nh_assoc_ol_ul_link_is_required(unit, vp_nh_index)) {
   9889              soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9890                  L3MC__NEXT_PTR_TYPEf, BCMI_L3_NH_EGR_NEXT_PTR_TYPE_NH);
   9891              soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9892                  L3MC__NEXT_PTRf, vp_nh_index);
   9893              /* Set up the association of NHs in sw */
   9894              BCM_IF_ERROR_RETURN(
   9895                  bcmi_l3_nh_assoc_ol_ul_link_sw_add(unit, nh_index,
   9896                  vp_nh_index));
   9897          } else {
   9898              soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9899                  L3MC__NEXT_PTR_TYPEf, BCMI_L3_NH_EGR_NEXT_PTR_TYPE_DVP);
   9900              soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9901                  L3MC__NEXT_PTRf, vp);
   9902          }
   9903     }
   9904 #endif
   9905 
   9906 #if defined(BCM_TRIDENT3_SUPPORT)
   9907     if (soc_feature(unit, soc_feature_large_scale_nat) &&
   9908         l3_egress->replication_id != 0 &&
   9909         soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3MC__EH_QUEUE_TAGf) &&
   9910         soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3MC__MAC_DA_PROFILE_INDEXf) &&
   9911         soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3MC__USE_MAC_DA_PROFILEf)) {
   9912         /* large scale MC nat uses EH_QUEUE_TAGf with MAC_DA_PROFILE_INDEXf */
   9913         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9914             L3MC__EH_QUEUE_TAGf, l3_egress->replication_id);
   9915         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9916             L3MC__EH_TAG_TYPEf, 0x1);
   9917         large_scale_nat_profile_mac = 1;
   9918     }
   9919 #endif /* BCM_TRIDENT3_SUPPORT */
   9920 
   9921 #if defined(INCLUDE_XFLOW_MACSEC)
   9922     if (soc_feature(unit, soc_feature_xflow_macsec) &&
   9923         ((l3_egress->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_ENCRYPT) ||
   9924         (l3_egress->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_DECRYPT))) {
   9925         uint32 entry_type;
   9926         egr_mac_da_profile_entry_t macda;
   9927         void *entries[1] = { NULL };
   9928 
   9929         if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm, DATA_TYPEf)) {
   9930             entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh,
   9931                                                           DATA_TYPEf);
   9932         } else
   9933         {
   9934             entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh,
   9935                                                           ENTRY_TYPEf);
   9936         }
   9937         switch (entry_type) {
   9938             case 7:
   9939                 field = L3MC__MACSEC_ENCRYPTf;
   9940                 field2 = L3MC__MACSEC_DECRYPTf;
   9941                 break;
   9942             default:
   9943                 break;
   9944         }
   9945         if ((field != INVALIDf) && (field2 != INVALIDf)) {
   9946             if (l3_egress->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_ENCRYPT) {
   9947                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, field, 1);
   9948             } else {
   9949                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, field, 0);
   9950             }
   9951 
   9952             if (l3_egress->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_DECRYPT) {
   9953                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, field2, 1);
   9954             } else {
   9955                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, field2, 0);
   9956             }
   9957             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9958                                 L3MC__HG_MC_DST_MODIDf, l3_egress->module);
   9959             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9960                                 L3MC__HG_MC_DST_PORT_NUMf, l3_egress->port);
   9961 
   9962             sal_memset(&macda, 0, sizeof(egr_mac_da_profile_entry_t));
   9963             soc_mem_mac_addr_set(unit, EGR_MAC_DA_PROFILEm, 
   9964                                  &macda, MAC_ADDRESSf, l3_egress->mac_addr);
   9965             entries[0] = &macda;
   9966             rv = _bcm_mac_da_profile_entry_add(unit, entries, 1,
   9967                                                (uint32 *)&macda_index);
   9968             if (BCM_FAILURE(rv)) {
   9969                 goto cleanup;
   9970             }
   9971             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9972                                 L3MC__MAC_DA_PROFILE_INDEXf, macda_index);
   9973 
   9974             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9975                                 L3MC__USE_MAC_DA_PROFILEf, 1);
   9976             use_configured_mac = 1;
   9977         }
   9978     } else
   9979 #endif
   9980     /*
   9981      * TD2Plus has a overlaid  mac_address.
   9982      * This mac_address field may be overlaid by some other fields
   9983      * used for CoE/HG feature. Meanwhile a mac_da_profile_index
   9984      * is present for the actual mac_address.
   9985      * This index points to EGR_MAC_DA_PROFILE, which is managed in
   9986      * Profile mechanism.
   9987      */
   9988 #ifdef BCM_HGPROXY_COE_SUPPORT
   9989     if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm,
   9990                             L3MC__MAC_DA_PROFILE_INDEXf) &&
   9991         _bcm_xgs5_subport_coe_mod_port_local(unit, l3_egress->module,
   9992                                              l3_egress->port)) {
   9993         egr_mac_da_profile_entry_t macda;
   9994         void *entries[1] = { NULL };
   9995 
   9996         if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm,
   9997                                 L3MC__USE_MAC_DA_PROFILEf)) {
   9998             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   9999                                 L3MC__USE_MAC_DA_PROFILEf, 1);
  10000         }
  10001         if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm,
  10002                                 L3MC__HG_MC_DST_MODIDf)) {
  10003             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
  10004                                 L3MC__HG_MC_DST_MODIDf, l3_egress->module);
  10005         }
  10006         if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm,
  10007                                 L3MC__HG_MC_DST_PORT_NUMf)) {
  10008             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
  10009                                 L3MC__HG_MC_DST_PORT_NUMf, l3_egress->port);
  10010         }
  10011 
  10012         sal_memset(&macda, 0, sizeof(egr_mac_da_profile_entry_t));
  10013         soc_mem_mac_addr_set(unit, EGR_MAC_DA_PROFILEm, 
  10014                              &macda, MAC_ADDRESSf, l3_egress->mac_addr);
  10015         entries[0] = &macda;
  10016         rv = _bcm_mac_da_profile_entry_add(unit, entries, 1,
  10017                                            (uint32 *)&macda_index);
  10018         if (BCM_FAILURE(rv)) {
  10019             goto cleanup;
  10020         }
  10021         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
  10022                             L3MC__MAC_DA_PROFILE_INDEXf, macda_index);
  10023         use_configured_mac = 1;
  10024             
  10025     } else
  10026 #endif
  10027 #if defined(BCM_TRIDENT3_SUPPORT)
  10028     if (large_scale_nat_profile_mac == 1) {
  10029         egr_mac_da_profile_entry_t macda;
  10030         void *entries[1] = { NULL };
  10031 
  10032         sal_memset(&macda, 0, sizeof(egr_mac_da_profile_entry_t));
  10033         soc_mem_mac_addr_set(unit, EGR_MAC_DA_PROFILEm,
  10034             &macda, MAC_ADDRESSf, l3_egress->mac_addr);
  10035         entries[0] = &macda;
  10036         rv = _bcm_mac_da_profile_entry_add(unit, entries, 1,
  10037             (uint32 *)&macda_index);
  10038 
  10039         if (BCM_FAILURE(rv)) {
  10040             goto cleanup;
  10041         }
  10042         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
  10043             L3MC__MAC_DA_PROFILE_INDEXf, macda_index);
  10044         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
  10045             L3MC__USE_MAC_DA_PROFILEf, 1);
  10046         use_configured_mac = 1;
  10047     } else
  10048 #endif /* BCM_TRIDENT3_SUPPORT */
  10049     if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3MC__MAC_ADDRESSf)) {
  10050         soc_mem_mac_addr_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
  10051                 L3MC__MAC_ADDRESSf, l3_egress->mac_addr);
  10052         use_configured_mac = 1;
  10053     } else {    
  10054         if (!BCM_MAC_IS_ZERO(l3_egress->mac_addr)) {
  10055             return BCM_E_PARAM;
  10056         }
  10057     }
  10058     if (use_configured_mac) {
  10059         if (BCM_MAC_IS_ZERO(l3_egress->mac_addr)) {
  10060             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
  10061                                 L3MC__L3MC_USE_CONFIGURED_MACf, 0);
  10062         } else {
  10063             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
  10064                                 L3MC__L3MC_USE_CONFIGURED_MACf, 1);
  10065         }
  10066     }
  10067 
  10068     rv = soc_mem_write(unit, EGR_L3_NEXT_HOPm,
  10069                        MEM_BLOCK_ALL, nh_index, &egr_nh);
  10070 #ifdef BCM_TOMAHAWK3_SUPPORT
  10071     if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOP_2m)) {
  10072         rv = soc_mem_write(unit, EGR_L3_NEXT_HOP_2m,
  10073                            MEM_BLOCK_ALL, nh_index, &egr_nh_2);
  10074     }
  10075 #endif
  10076     if (BCM_FAILURE(rv)) {
  10077         goto cleanup;
  10078     }
  10079     return BCM_E_NONE;
  10080 
  10081 cleanup:
  10082     if (macda_index != -1) {
  10083         (void) _bcm_mac_da_profile_entry_delete(unit, macda_index);
  10084     }
  10085     return rv;
  10086 }
  10087 
  10088 /*
  10089  * Function:
  10090  *      _bcm_tr3_l3_ipmc_nh_entry_parse
  10091  * Purpose:
  10092  *      Parse L3 multicast next hop entry.
  10093  * Parameters:
  10094  *      unit      - (IN) SOC unit number.
  10095  *      ing_nh    - (IN) Ingress next hop table entry. 
  10096  *      egr_nh    - (IN) Egress next hop table entry. 
  10097  *      l3_egress - (OUT) L3 egress structure. 
  10098  * Returns:
  10099  *      BCM_E_XXX
  10100  */
  10101 int
  10102 _bcm_tr3_l3_ipmc_nh_entry_parse(int unit, uint32 *ing_nh, 
  10103         uint32 *egr_nh, uint32 *egr_nh_2, bcm_l3_egress_t *l3_egress)
  10104 {
  10105     bcm_module_t module = 0, module_out = 0;
  10106     bcm_port_t port = 0, port_out = 0;
  10107     int i;
  10108     uint32 flag_array[] = {
  10109         BCM_L3_MULTICAST_L2_DEST_PRESERVE,
  10110         BCM_L3_MULTICAST_L2_SRC_PRESERVE,
  10111         BCM_L3_MULTICAST_L2_VLAN_PRESERVE,
  10112         BCM_L3_MULTICAST_TTL_PRESERVE,
  10113         BCM_L3_MULTICAST_DEST_PRESERVE,
  10114         BCM_L3_MULTICAST_SRC_PRESERVE,
  10115         BCM_L3_MULTICAST_VLAN_PRESERVE,
  10116         BCM_L3_MULTICAST_L3_DROP,
  10117         BCM_L3_MULTICAST_L2_DROP
  10118     };
  10119     soc_field_t field_array[] = {
  10120         L3MC__L2_MC_DA_DISABLEf,
  10121         L3MC__L2_MC_SA_DISABLEf,
  10122         L3MC__L2_MC_VLAN_DISABLEf,
  10123         L3MC__L3_MC_TTL_DISABLEf,
  10124         L3MC__L3_MC_DA_DISABLEf,
  10125         L3MC__L3_MC_SA_DISABLEf,
  10126         L3MC__L3_MC_VLAN_DISABLEf,
  10127         L3MC__L3_DROPf,
  10128         L3MC__L2_DROPf
  10129     };
  10130 
  10131 
  10132 #ifdef BCM_RIOT_SUPPORT
  10133     if (soc_feature(unit, soc_feature_ing_l3_next_hop_encoded_dest)) {
  10134         uint32 nh_dest = 0;
  10135         nh_dest = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm,
  10136                                       ing_nh, DESTINATIONf);
  10137         bcmi_get_port_from_destination(unit, nh_dest, l3_egress);
  10138         if (l3_egress->flags == BCM_L3_TGID) {
  10139             l3_egress->trunk = l3_egress->port;
  10140         }
  10141     } else
  10142 #endif
  10143     {
  10144         /* Get trunk or module and port */
  10145 #if defined(BCM_TRIDENT3_SUPPORT)
  10146         if (soc_feature(unit, soc_feature_generic_dest)) {
  10147             uint32 dest_val = 0, dest_type = 0;
  10148             int dvp_gport = 0;
  10149             dest_val = soc_mem_field32_dest_get(unit, ING_L3_NEXT_HOPm, ing_nh,
  10150                                                 DESTINATIONf, &dest_type);
  10151             if (dest_type == SOC_MEM_FIF_DEST_LAG) {
  10152                 l3_egress->flags |= BCM_L3_TGID;
  10153                 l3_egress->trunk = dest_val & SOC_MEM_FIF_DGPP_TGID_MASK;
  10154             } else if (dest_type == SOC_MEM_FIF_DEST_DGPP) {
  10155                 port = (dest_val & SOC_MEM_FIF_DGPP_PORT_MASK);
  10156                 module = (dest_val & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >>
  10157                             SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS;
  10158                 BCM_IF_ERROR_RETURN(_bcm_esw_stk_modmap_map(unit,
  10159                     BCM_STK_MODMAP_GET, module, port, &module_out, &port_out));
  10160                 l3_egress->module = module_out;
  10161                 l3_egress->port = port_out;
  10162             } else if (dest_type == SOC_MEM_FIF_DEST_DVP) {
  10163                 _bcm_vp_encode_gport(unit, dest_val, &dvp_gport);
  10164                 l3_egress->port = dvp_gport;
  10165             }
  10166         } else
  10167 #endif /* BCM_TRIDENT3_SUPPORT */
  10168         {
  10169             if (soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, ing_nh, Tf)) {
  10170                 l3_egress->flags |= BCM_L3_TGID;
  10171                 l3_egress->trunk = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm,
  10172                                                        ing_nh, TGIDf);
  10173             } else {
  10174                 port = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, ing_nh,
  10175                                            PORT_NUMf);
  10176                 if (!SOC_IS_TOMAHAWK3(unit)) {
  10177                     module = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, ing_nh,
  10178                                                  MODULE_IDf);
  10179 
  10180                     BCM_IF_ERROR_RETURN(_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
  10181                                     module, port, &module_out, &port_out));
  10182                 } else {
  10183                     module_out = 0;
  10184                     port_out = port;
  10185                 }
  10186                 l3_egress->module = module_out;
  10187                 l3_egress->port = port_out;
  10188             }
  10189         }
  10190     }
  10191 
  10192     /* Get VLAN */
  10193     l3_egress->vlan = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, ing_nh,
  10194             VLAN_IDf);
  10195 
  10196     /* Get L3 interface */
  10197     if (SOC_IS_TOMAHAWK3(unit)) {
  10198         l3_egress->intf = soc_mem_field32_get(unit, EGR_L3_NEXT_HOP_2m, egr_nh_2,
  10199                 INTF_NUMf);
  10200     } else {
  10201         l3_egress->intf = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh,
  10202                 L3MC__INTF_NUMf);
  10203     }
  10204 
  10205     /* Get L3 multicast flags */
  10206     for (i = 0; i < COUNTOF(field_array); i++) {
  10207         if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, field_array[i])) {
  10208             if (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh,
  10209                         field_array[i])) {
  10210                 l3_egress->multicast_flags |= flag_array[i];
  10211             }
  10212         }
  10213     }
  10214 
  10215     /* Get MAC address */
  10216 #ifdef BCM_TRIDENT3_SUPPORT
  10217     if (soc_feature(unit, soc_feature_large_scale_nat) &&
  10218         soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3MC__MAC_DA_PROFILE_INDEXf) &&
  10219         soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3MC__USE_MAC_DA_PROFILEf) &&
  10220         soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh, L3MC__USE_MAC_DA_PROFILEf)) {
  10221         egr_mac_da_profile_entry_t macda;
  10222         int macda_index = -1;
  10223 
  10224         macda_index = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh,
  10225                             L3MC__MAC_DA_PROFILE_INDEXf);
  10226 
  10227         /* Read entry from MAC-DA-PROFILEm */
  10228         BCM_IF_ERROR_RETURN (soc_mem_read(unit, EGR_MAC_DA_PROFILEm,
  10229             MEM_BLOCK_ANY, macda_index, &macda));
  10230 
  10231         /* Get mac address from EGR_MACDA_PROFILE. */
  10232         soc_mem_mac_addr_get(unit, EGR_MAC_DA_PROFILEm, &macda,
  10233             MAC_ADDRESSf, l3_egress->mac_addr);
  10234     } else
  10235 #endif /* BCM_TRIDENT3_SUPPORT */
  10236     if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3MC__MAC_ADDRESSf)) {
  10237         soc_mem_mac_addr_get(unit, EGR_L3_NEXT_HOPm, egr_nh,
  10238                 L3MC__MAC_ADDRESSf, l3_egress->mac_addr);
  10239     }
  10240 
  10241 #if defined(BCM_TRIDENT3_SUPPORT)
  10242     if (soc_feature(unit, soc_feature_large_scale_nat) &&
  10243         soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3MC__EH_QUEUE_TAGf)) {
  10244         l3_egress->replication_id = soc_mem_field32_get(unit,
  10245              EGR_L3_NEXT_HOPm, egr_nh, L3MC__EH_QUEUE_TAGf);
  10246     }
  10247 #endif
  10248 #ifdef BCM_TRIDENT2_SUPPORT
  10249     if (soc_feature(unit, soc_feature_virtual_port_routing)) {
  10250         int vp;
  10251         int multicast_flag;
  10252         int virtual_interface_id;
  10253         bcm_niv_port_t niv_port;
  10254         int count;
  10255         bcm_niv_egress_t *niv_egress_array;
  10256         int rv;
  10257         int dvp_valid = 0;
  10258 
  10259 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
  10260         if (soc_feature(unit, soc_feature_egr_l3_next_hop_next_ptr)) {
  10261             dvp_valid = (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh,
  10262                     L3MC__NEXT_PTR_TYPEf) & 0x1);
  10263         } else 
  10264 #endif
  10265         {
  10266             dvp_valid = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh,
  10267                     L3MC__DVP_VALIDf);
  10268         }
  10269         if (dvp_valid) {
  10270             vp = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh,
  10271                     L3MC__DVPf);
  10272             l3_egress->encap_id = vp;
  10273             if (_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
  10274                 /* If the VP is of NIV type, need to determine if a NIV
  10275                  * egress object ID needs to be returned in encap_id.
  10276                  */
  10277                 multicast_flag = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
  10278                         egr_nh, L3MC__VNTAG_Pf);
  10279                 virtual_interface_id = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
  10280                         egr_nh, L3MC__VNTAG_DST_VIFf);
  10281                 if (multicast_flag) {
  10282                     bcm_niv_port_t_init(&niv_port);
  10283                     BCM_GPORT_NIV_PORT_ID_SET(niv_port.niv_port_id, vp);
  10284                     BCM_IF_ERROR_RETURN(bcm_esw_niv_port_get(unit, &niv_port));
  10285                     if (niv_port.flags & BCM_NIV_PORT_MATCH_NONE) {
  10286                         BCM_IF_ERROR_RETURN(bcm_esw_niv_egress_get(unit,
  10287                                     niv_port.niv_port_id, 0, NULL, &count));
  10288                         if (count > 0) {
  10289                             niv_egress_array = sal_alloc
  10290                                 (count * sizeof(bcm_niv_egress_t),
  10291                                  "niv_egress_array");
  10292                             if (NULL == niv_egress_array) {
  10293                                 return BCM_E_MEMORY;
  10294                             }
  10295                             rv = bcm_esw_niv_egress_get(unit, niv_port.niv_port_id,
  10296                                     count, niv_egress_array, &count);
  10297                             if (BCM_FAILURE(rv)) {
  10298                                 sal_free(niv_egress_array);
  10299                                 return rv;
  10300                             }
  10301                             for (i = 0; i < count; i++) {
  10302                                 if (virtual_interface_id ==
  10303                                     niv_egress_array[i].virtual_interface_id) {
  10304                                     break;
  10305                                 }
  10306                             }
  10307                             if (i == count) {
  10308                                 sal_free(niv_egress_array);
  10309                                 return BCM_E_NOT_FOUND;
  10310                             }
  10311                             l3_egress->encap_id = niv_egress_array[i].egress_if;
  10312                             sal_free(niv_egress_array);
  10313                         } else {
  10314                             return BCM_E_INTERNAL;
  10315                         }
  10316                     }
  10317                 }
  10318             } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeVxlan)) {
  10319                 if (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh,
  10320                                         L3MC__L3_DROPf)) {
  10321                     l3_egress->multicast_flags |= BCM_L3_MULTICAST_L3_DROP;
  10322                 }
  10323                 if (l3_egress->port == 0) {
  10324                     l3_egress->flags2 |= BCM_L3_FLAGS2_UNDERLAY;
  10325                 }
  10326             }
  10327         }
  10328     }
  10329 #endif /* BCM_TRIDENT2_SUPPORT */
  10330 
  10331     /* Set IPMC flag */
  10332     l3_egress->flags |= BCM_L3_IPMC;
  10333 
  10334 #if defined(INCLUDE_XFLOW_MACSEC)
  10335     if (soc_feature(unit, soc_feature_xflow_macsec)) {
  10336         if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm, L3MC__MACSEC_ENCRYPTf) &&
  10337             (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh,
  10338                 L3MC__MACSEC_ENCRYPTf))) {
  10339             l3_egress->flags2 |= BCM_L3_FLAGS2_XFLOW_MACSEC_ENCRYPT;
  10340         }
  10341         if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm, L3MC__MACSEC_DECRYPTf) &&
  10342             (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh,
  10343                 L3MC__MACSEC_DECRYPTf))) {
  10344             l3_egress->flags2 |= BCM_L3_FLAGS2_XFLOW_MACSEC_DECRYPT;
  10345         }
  10346     }
  10347 #endif
  10348     return BCM_E_NONE;
  10349 }
  10350 
  10351 
  10352 #ifdef BCM_WARM_BOOT_SUPPORT
  10353 
  10354 /*
  10355  * Function:
  10356  *      bcm_tr3_ecmp_dlb_wb_alloc_size_get
  10357  * Purpose:
  10358  *      Get level 2 warm boot scache size for ECMP DLB.
  10359  * Parameters:
  10360  *      unit - (IN) SOC unit number.
  10361  *      size - (OUT) Allocation size.
  10362  * Returns:
  10363  *      BCM_E_XXX
  10364  */
  10365 int
  10366 bcm_tr3_ecmp_dlb_wb_alloc_size_get(int unit, int *size) 
  10367 {
  10368     int alloc_size = 0;
  10369     int num_elements;
  10370 
  10371     /* Allocate size for the following ECMP DLB parameters: 
  10372      * int ecmp_dlb_sample_rate;
  10373      * int ecmp_dlb_tx_load_min_th;
  10374      * int ecmp_dlb_tx_load_max_th;
  10375      * int ecmp_dlb_qsize_min_th;
  10376      * int ecmp_dlb_qsize_max_th;
  10377      * int ecmp_dlb_exp_load_min_th;
  10378      * int ecmp_dlb_exp_load_max_th;
  10379      * int ecmp_dlb_imbalance_min_th;
  10380      * int ecmp_dlb_imbalance_max_th;
  10381      */
  10382     alloc_size += sizeof(int) * 9;
  10383 
  10384     /* Allocate size of ecmp_dlb_load_weight array */
  10385     num_elements = 1 << soc_mem_field_length(unit,
  10386             DLB_ECMP_QUALITY_CONTROLm, PROFILE_PTRf);
  10387     alloc_size += sizeof(uint8) * num_elements;
  10388 
  10389     *size = alloc_size;
  10390 
  10391     return BCM_E_NONE;
  10392 }
  10393 
  10394 /*
  10395  * Function:
  10396  *      bcm_tr3_ecmp_dlb_sync
  10397  * Purpose:
  10398  *      Store ECMP DLB parameters into scache.
  10399  * Parameters:
  10400  *      unit - (IN) SOC unit number.
  10401  *      scache_ptr - (IN/OUT) Scache pointer
  10402  * Returns:
  10403  *      BCM_E_XXX
  10404  */
  10405 int
  10406 bcm_tr3_ecmp_dlb_sync(int unit, uint8 **scache_ptr) 
  10407 {
  10408     int value;
  10409     int num_elements;
  10410     int i;
  10411     uint8 load_weight;
  10412 
  10413     /* Store the following ECMP DLB parameters: 
  10414      * int ecmp_dlb_sample_rate;
  10415      * int ecmp_dlb_tx_load_min_th;
  10416      * int ecmp_dlb_tx_load_max_th;
  10417      * int ecmp_dlb_qsize_min_th;
  10418      * int ecmp_dlb_qsize_max_th;
  10419      * int ecmp_dlb_exp_load_min_th;
  10420      * int ecmp_dlb_exp_load_max_th;
  10421      * int ecmp_dlb_imbalance_min_th;
  10422      * int ecmp_dlb_imbalance_max_th;
  10423      */
  10424     value = ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate;
  10425     sal_memcpy((*scache_ptr), &value, sizeof(int));
  10426     (*scache_ptr) += sizeof(int);
  10427 
  10428     value = ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th;
  10429     sal_memcpy((*scache_ptr), &value, sizeof(int));
  10430     (*scache_ptr) += sizeof(int);
  10431 
  10432     value = ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th;
  10433     sal_memcpy((*scache_ptr), &value, sizeof(int));
  10434     (*scache_ptr) += sizeof(int);
  10435 
  10436     value = ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th;
  10437     sal_memcpy((*scache_ptr), &value, sizeof(int));
  10438     (*scache_ptr) += sizeof(int);
  10439 
  10440     value = ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th;
  10441     sal_memcpy((*scache_ptr), &value, sizeof(int));
  10442     (*scache_ptr) += sizeof(int);
  10443 
  10444     value = ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_min_th;
  10445     sal_memcpy((*scache_ptr), &value, sizeof(int));
  10446     (*scache_ptr) += sizeof(int);
  10447 
  10448     value = ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_max_th;
  10449     sal_memcpy((*scache_ptr), &value, sizeof(int));
  10450     (*scache_ptr) += sizeof(int);
  10451 
  10452     value = ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th;
  10453     sal_memcpy((*scache_ptr), &value, sizeof(int));
  10454     (*scache_ptr) += sizeof(int);
  10455 
  10456     value = ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th;
  10457     sal_memcpy((*scache_ptr), &value, sizeof(int));
  10458     (*scache_ptr) += sizeof(int);
  10459 
  10460     /* Store ecmp_dlb_load_weight array */
  10461     num_elements = 1 << soc_mem_field_length(unit,
  10462             DLB_ECMP_QUALITY_CONTROLm, PROFILE_PTRf);
  10463     for (i = 0; i < num_elements; i++) {
  10464         load_weight = ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[i];
  10465         sal_memcpy((*scache_ptr), &load_weight, sizeof(uint8));
  10466         (*scache_ptr) += sizeof(uint8);
  10467     }
  10468         
  10469     return BCM_E_NONE;
  10470 }
  10471 
  10472 /*
  10473  * Function:
  10474  *      bcm_tr3_ecmp_dlb_scache_recover
  10475  * Purpose:
  10476  *      Recover ECMP DLB parameters from scache.
  10477  * Parameters:
  10478  *      unit - (IN) SOC unit number.
  10479  *      scache_ptr - (IN/OUT) Scache pointer
  10480  * Returns:
  10481  *      BCM_E_XXX
  10482  */
  10483 int
  10484 bcm_tr3_ecmp_dlb_scache_recover(int unit, uint8 **scache_ptr) 
  10485 {
  10486     int value;
  10487     int num_elements;
  10488     int i;
  10489     uint8 load_weight;
  10490 
  10491     /* Recover the following ECMP DLB parameters: 
  10492      * int ecmp_dlb_sample_rate;
  10493      * int ecmp_dlb_tx_load_min_th;
  10494      * int ecmp_dlb_tx_load_max_th;
  10495      * int ecmp_dlb_qsize_min_th;
  10496      * int ecmp_dlb_qsize_max_th;
  10497      * int ecmp_dlb_exp_load_min_th;
  10498      * int ecmp_dlb_exp_load_max_th;
  10499      * int ecmp_dlb_imbalance_min_th;
  10500      * int ecmp_dlb_imbalance_max_th;
  10501      */
  10502     sal_memcpy(&value, (*scache_ptr), sizeof(int));
  10503     ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate = value;
  10504     (*scache_ptr) += sizeof(int);
  10505 
  10506     sal_memcpy(&value, (*scache_ptr), sizeof(int));
  10507     ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th = value;
  10508     (*scache_ptr) += sizeof(int);
  10509 
  10510     sal_memcpy(&value, (*scache_ptr), sizeof(int));
  10511     ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th = value;
  10512     (*scache_ptr) += sizeof(int);
  10513 
  10514     sal_memcpy(&value, (*scache_ptr), sizeof(int));
  10515     ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th = value;
  10516     (*scache_ptr) += sizeof(int);
  10517 
  10518     sal_memcpy(&value, (*scache_ptr), sizeof(int));
  10519     ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th = value;
  10520     (*scache_ptr) += sizeof(int);
  10521 
  10522     sal_memcpy(&value, (*scache_ptr), sizeof(int));
  10523     ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_min_th = value;
  10524     (*scache_ptr) += sizeof(int);
  10525 
  10526     sal_memcpy(&value, (*scache_ptr), sizeof(int));
  10527     ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_max_th = value;
  10528     (*scache_ptr) += sizeof(int);
  10529 
  10530     sal_memcpy(&value, (*scache_ptr), sizeof(int));
  10531     ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th = value;
  10532     (*scache_ptr) += sizeof(int);
  10533 
  10534     sal_memcpy(&value, (*scache_ptr), sizeof(int));
  10535     ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th = value;
  10536     (*scache_ptr) += sizeof(int);
  10537 
  10538     /* Recover ecmp_dlb_load_weight array */
  10539     num_elements = 1 << soc_mem_field_length(unit,
  10540             DLB_ECMP_QUALITY_CONTROLm, PROFILE_PTRf);
  10541     for (i = 0; i < num_elements; i++) {
  10542         sal_memcpy(&load_weight, (*scache_ptr), sizeof(uint8));
  10543         ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[i] = load_weight;
  10544         (*scache_ptr) += sizeof(uint8);
  10545     }
  10546         
  10547     ECMP_DLB_INFO(unit)->recovered_from_scache = TRUE;
  10548 
  10549     return BCM_E_NONE;
  10550 }
  10551 
  10552 /*
  10553  * Function:
  10554  *      _bcm_tr3_ecmp_dlb_member_recover
  10555  * Purpose:
  10556  *      Recover ECMP DLB member ID usage and the next hop indices associated
  10557  *      with the member IDs.
  10558  * Parameters:
  10559  *      unit - (IN) SOC unit number.
  10560  * Returns:
  10561  *      BCM_E_XXX
  10562  */
  10563 STATIC int
  10564 _bcm_tr3_ecmp_dlb_member_recover(int unit) 
  10565 {
  10566     int rv = BCM_E_NONE;
  10567     int member_bitmap_width;
  10568     int alloc_size;
  10569     SHR_BITDCL *member_bitmap = NULL;
  10570     int member_id;
  10571     dlb_ecmp_member_attribute_entry_t member_attr_entry;
  10572     int nh_index;
  10573     int group;
  10574     int i;
  10575     dlb_ecmp_group_membership_entry_t group_membership_entry;
  10576     int match, match_index, free_index_found, free_index;
  10577     _tr3_ecmp_dlb_nh_membership_t *membership;
  10578 
  10579     member_bitmap_width = soc_mem_field_length(unit,
  10580             DLB_ECMP_GROUP_MEMBERSHIPm, MEMBER_BITMAPf);
  10581     alloc_size = SHR_BITALLOCSIZE(member_bitmap_width);
  10582     member_bitmap = sal_alloc(alloc_size, "DLB ECMP member bitmap"); 
  10583     if (NULL == member_bitmap) {
  10584         return BCM_E_MEMORY;
  10585     }
  10586 
  10587     for (member_id = 0; member_id < soc_mem_index_count(unit,
  10588                 DLB_ECMP_MEMBER_ATTRIBUTEm); member_id++) {
  10589         rv = READ_DLB_ECMP_MEMBER_ATTRIBUTEm(unit, MEM_BLOCK_ANY,
  10590                 member_id, &member_attr_entry);
  10591         if (BCM_FAILURE(rv)) {
  10592             sal_free(member_bitmap);
  10593             return rv;
  10594         }
  10595         nh_index = soc_DLB_ECMP_MEMBER_ATTRIBUTEm_field32_get(unit,
  10596                 &member_attr_entry, NEXT_HOP_INDEXf);
  10597         if (0 == nh_index) {
  10598             /* If next hop index is 0, this member ID is not used. */
  10599             continue;
  10600         }
  10601 
  10602         /* Member ID is used */
  10603         _BCM_ECMP_DLB_MEMBER_ID_USED_SET(unit, member_id);
  10604 
  10605         /* Find the ECMP DLB group this member ID belongs to */
  10606         group = -1;
  10607         for (i = 0; i < soc_mem_index_count(unit,
  10608                     DLB_ECMP_GROUP_MEMBERSHIPm); i++) {
  10609             rv = READ_DLB_ECMP_GROUP_MEMBERSHIPm(unit,
  10610                     MEM_BLOCK_ANY, i, &group_membership_entry);
  10611             if (BCM_FAILURE(rv)) {
  10612                 sal_free(member_bitmap);
  10613                 return rv;
  10614             }
  10615             soc_DLB_ECMP_GROUP_MEMBERSHIPm_field_get(unit,
  10616                     &group_membership_entry, MEMBER_BITMAPf, member_bitmap);
  10617             if (SHR_BITGET(member_bitmap, member_id)) {
  10618                 group = i;
  10619                 break;
  10620             }
  10621         }
  10622 
  10623         /* Traverse ecmp_dlb_nh_info array to find the nh_index */
  10624         match = FALSE;
  10625         match_index = 0;
  10626         free_index_found = FALSE;
  10627         free_index = 0;
  10628         for (i = 0; i < ECMP_DLB_INFO(unit)->ecmp_dlb_nh_info_size; i++) {
  10629             if (ECMP_DLB_NH_INFO(unit, i).valid) {
  10630                 if (nh_index == ECMP_DLB_NH_INFO(unit, i).nh_index) {
  10631                     match = TRUE;
  10632                     match_index = i;
  10633                     break;
  10634                 }
  10635             } else {
  10636                 if (!free_index_found) {
  10637                     free_index_found = TRUE;
  10638                     free_index = i;
  10639                 }
  10640             }
  10641         }
  10642 
  10643         /* Insert member ID and group to the next hop's linked list of member
  10644          * IDs and groups.
  10645          */
  10646         membership = sal_alloc(sizeof(_tr3_ecmp_dlb_nh_membership_t),
  10647                 "ecmp dlb nh membership");
  10648         if (NULL == membership) {
  10649             sal_free(member_bitmap);
  10650             return BCM_E_MEMORY;
  10651         }
  10652         membership->member_id = member_id;
  10653         membership->group = group;
  10654         if (match) {
  10655             membership->next =
  10656                 ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list; 
  10657             ECMP_DLB_NH_INFO(unit, match_index).nh_membership_list = membership;
  10658         } else {
  10659             if (!free_index_found) {
  10660                 return BCM_E_FULL;
  10661             }
  10662             membership->next =
  10663                 ECMP_DLB_NH_INFO(unit, free_index).nh_membership_list; 
  10664             ECMP_DLB_NH_INFO(unit, free_index).nh_membership_list = membership;
  10665             ECMP_DLB_NH_INFO(unit, free_index).nh_index = nh_index;
  10666             ECMP_DLB_NH_INFO(unit, free_index).valid = 1;
  10667         }
  10668     }
  10669 
  10670     sal_free(member_bitmap);
  10671 
  10672     return BCM_E_NONE;
  10673 }
  10674 
  10675 /*
  10676  * Function:
  10677  *      _bcm_tr3_ecmp_dlb_group_recover
  10678  * Purpose:
  10679  *      Recover ECMP DLB group usage and flowset table usage.
  10680  * Parameters:
  10681  *      unit - (IN) SOC unit number.
  10682  * Returns:
  10683  *      BCM_E_XXX
  10684  */
  10685 STATIC int
  10686 _bcm_tr3_ecmp_dlb_group_recover(int unit) 
  10687 {
  10688     int i;
  10689     ecmp_count_entry_t ecmp_group_entry;
  10690     int group_enable, dlb_id;
  10691     dlb_ecmp_group_control_entry_t group_control_entry;
  10692     int entry_base_ptr, dynamic_size_encode, dynamic_size;
  10693     int block_base_ptr, num_blocks;
  10694 
  10695     for (i = 0; i < soc_mem_index_count(unit, L3_ECMP_COUNTm); i++) {
  10696         SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, i,
  10697                     &ecmp_group_entry));
  10698         group_enable = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_group_entry,
  10699                 GROUP_ENABLEf);
  10700         if (0 == group_enable) {
  10701             /* DLB not enabled */
  10702             continue;
  10703         }
  10704 
  10705         /* Get DLB group ID and marked it as used */
  10706         dlb_id = soc_L3_ECMP_COUNTm_field32_get(unit, &ecmp_group_entry,
  10707                 DLB_IDf);
  10708         _BCM_ECMP_DLB_ID_USED_SET(unit, dlb_id);
  10709 
  10710         /* Get flow set table usage */
  10711         SOC_IF_ERROR_RETURN(READ_DLB_ECMP_GROUP_CONTROLm(unit,
  10712                     MEM_BLOCK_ANY, dlb_id, &group_control_entry));
  10713         entry_base_ptr = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
  10714                 &group_control_entry, FLOW_SET_BASEf);
  10715         dynamic_size_encode = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit,
  10716                 &group_control_entry, FLOW_SET_SIZEf);
  10717         BCM_IF_ERROR_RETURN
  10718             (_bcm_tr3_ecmp_dlb_dynamic_size_decode(dynamic_size_encode,
  10719                                                    &dynamic_size));
  10720         block_base_ptr = entry_base_ptr >> 9;
  10721         num_blocks = dynamic_size >> 9; 
  10722         _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr,
  10723                 num_blocks);
  10724     }
  10725 
  10726     return BCM_E_NONE;
  10727 }
  10728 
  10729 /*
  10730  * Function:
  10731  *      _bcm_tr3_ecmp_dlb_quality_parameters_recover
  10732  * Purpose:
  10733  *      Recover ECMP DLB parameters used to derive a member's quality.
  10734  * Parameters:
  10735  *      unit - (IN) SOC unit number.
  10736  * Returns:
  10737  *      BCM_E_XXX
  10738  */
  10739 STATIC int
  10740 _bcm_tr3_ecmp_dlb_quality_parameters_recover(int unit) 
  10741 {
  10742     uint32 measure_control_reg;
  10743     int num_time_units;
  10744     dlb_ecmp_pla_quantize_threshold_entry_t quantize_threshold_entry;
  10745     int min_th_bytes, min_th_cells;
  10746     int max_th_bytes, max_th_cells;
  10747     dlb_ecmp_vla_expected_loading_threshold_entry_t expected_loading_threshold_entry;
  10748     int exp_load_min_th_kbytes, exp_load_max_th_kbytes;
  10749     dlb_ecmp_vla_member_imbalance_threshold_entry_t imbalance_threshold_entry;
  10750     int imbalance_min_th_kbytes, imbalance_max_th_kbytes;
  10751     int entries_per_profile;
  10752     int profile_ptr, base_index;
  10753     dlb_ecmp_quality_mapping_entry_t quality_mapping_entry;
  10754     int quality;
  10755 
  10756     if (ECMP_DLB_INFO(unit)->recovered_from_scache) {
  10757         /* If already recovered from scache, do nothing. */ 
  10758         return BCM_E_NONE;
  10759     }
  10760 
  10761     /* Recover sampling rate */
  10762     SOC_IF_ERROR_RETURN(READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit,
  10763                 &measure_control_reg));
  10764     num_time_units = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr,
  10765             measure_control_reg, HISTORICAL_SAMPLING_PERIODf);
  10766     if (num_time_units > 0) {
  10767         ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate = 1000000 / num_time_units;
  10768     }
  10769 
  10770     /* Recover min and max load and queue size thresholds: 
  10771      * Load threshold (in mbps)
  10772      *     = (bytes per sampling period) * 8 bits per byte /
  10773      *       (sampling period in seconds) / 10^6
  10774      *     = (bytes per sampling period) * 8 bits per byte /
  10775      *       (num_time_units * 1 us per time unit * 10^-6) / 10^6
  10776      *     = (bytes per sampling period) * 8 / num_time_units 
  10777      */ 
  10778     SOC_IF_ERROR_RETURN(READ_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm(unit,
  10779                 MEM_BLOCK_ANY, 0, &quantize_threshold_entry));
  10780     min_th_bytes = soc_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm_field32_get
  10781         (unit, &quantize_threshold_entry, THRESHOLD_HIST_LOADf); 
  10782     ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th = (min_th_bytes << 3) /
  10783         num_time_units;
  10784     min_th_cells = soc_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm_field32_get
  10785         (unit, &quantize_threshold_entry, THRESHOLD_HIST_QSIZEf); 
  10786     ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th = min_th_cells * 208;
  10787 
  10788     SOC_IF_ERROR_RETURN(READ_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm(unit,
  10789                 MEM_BLOCK_ANY, soc_mem_index_max(unit,
  10790                     DLB_ECMP_PLA_QUANTIZE_THRESHOLDm),
  10791                 &quantize_threshold_entry));
  10792     max_th_bytes = soc_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm_field32_get
  10793         (unit, &quantize_threshold_entry, THRESHOLD_HIST_LOADf); 
  10794     ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th = (max_th_bytes << 3) /
  10795         num_time_units;
  10796     max_th_cells = soc_DLB_ECMP_PLA_QUANTIZE_THRESHOLDm_field32_get
  10797         (unit, &quantize_threshold_entry, THRESHOLD_HIST_QSIZEf); 
  10798     ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th = max_th_cells * 208;
  10799 
  10800     /* Recover min and max expected load thresholds: 
  10801      * Load threshold (in mbps)
  10802      *     = (bytes per sampling period) * 8 bits per byte /
  10803      *       (sampling period in seconds) / 10^6
  10804      *     = (bytes per sampling period) * 8 bits per byte /
  10805      *       (num_time_units * 1 us per time unit * 10^-6) / 10^6
  10806      *     = (bytes per sampling period) * 8 / num_time_units 
  10807      *     = (kilobytes per sampling period) * 8000 / num_time_units 
  10808      */ 
  10809     SOC_IF_ERROR_RETURN(READ_DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLDm(unit,
  10810                 MEM_BLOCK_ANY, 0, &expected_loading_threshold_entry));
  10811     exp_load_min_th_kbytes =
  10812         soc_DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLDm_field32_get
  10813         (unit, &expected_loading_threshold_entry, THRESHOLDf); 
  10814     ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_min_th =
  10815         (exp_load_min_th_kbytes << 3) * 1000 / num_time_units;
  10816 
  10817     SOC_IF_ERROR_RETURN(READ_DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLDm(unit,
  10818                 MEM_BLOCK_ANY, 14, &expected_loading_threshold_entry));
  10819     exp_load_max_th_kbytes =
  10820         soc_DLB_ECMP_VLA_EXPECTED_LOADING_THRESHOLDm_field32_get
  10821         (unit, &expected_loading_threshold_entry, THRESHOLDf); 
  10822     ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_max_th =
  10823         (exp_load_max_th_kbytes << 3) * 1000 / num_time_units;
  10824 
  10825     /* Recover min and max imbalance thresholds: 
  10826      * Imbalance threshold (in percentage)
  10827      *     = (imbalance threshold in kbytes) / 
  10828      *       (expected load threshold in kbytes) * 100
  10829      */
  10830     SOC_IF_ERROR_RETURN(READ_DLB_ECMP_VLA_MEMBER_IMBALANCE_THRESHOLDm(unit,
  10831                 MEM_BLOCK_ANY, 14, &imbalance_threshold_entry));
  10832     imbalance_min_th_kbytes =
  10833         soc_DLB_ECMP_VLA_MEMBER_IMBALANCE_THRESHOLDm_field32_get
  10834         (unit, &imbalance_threshold_entry, THRESHOLD_0f); 
  10835     if ((imbalance_min_th_kbytes >> 20) & 0x1) {
  10836         /* Imbalance threshold is negative. Take absolute value. */
  10837         imbalance_min_th_kbytes = ((~imbalance_min_th_kbytes) + 1) & 0x1fffff; 
  10838         ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th =
  10839             imbalance_min_th_kbytes * 100 / (exp_load_max_th_kbytes) * -1;
  10840     } else {
  10841         ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th =
  10842             imbalance_min_th_kbytes * 100 / (exp_load_max_th_kbytes);
  10843     }
  10844 
  10845     imbalance_max_th_kbytes =
  10846         soc_DLB_ECMP_VLA_MEMBER_IMBALANCE_THRESHOLDm_field32_get
  10847         (unit, &imbalance_threshold_entry, THRESHOLD_6f); 
  10848     if ((imbalance_max_th_kbytes >> 20) & 0x1) {
  10849         /* Imbalance threshold is negative. Take absolute value. */
  10850         imbalance_max_th_kbytes = ((~imbalance_max_th_kbytes) + 1) & 0x1fffff; 
  10851         ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th =
  10852             imbalance_max_th_kbytes * 100 / (exp_load_max_th_kbytes) * -1;
  10853     } else {
  10854         ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th =
  10855             imbalance_max_th_kbytes * 100 / (exp_load_max_th_kbytes);
  10856     }
  10857 
  10858     /* Recover load weights */
  10859     entries_per_profile = 64;
  10860     for (profile_ptr = 0; profile_ptr < (1 << soc_mem_field_length(unit,
  10861                     DLB_ECMP_QUALITY_CONTROLm, PROFILE_PTRf)); profile_ptr++) {
  10862         base_index = profile_ptr * entries_per_profile;
  10863         /* quality = (quantized_tx_load * tx_load_percent +
  10864          *            quantized_qsize * (100 - tx_load_percent)) /
  10865          *           100;
  10866          * quality = ((quantized_tx_load - quantized_qsize) *
  10867          *            tx_load_percent + quantized_qsize * 100) /
  10868          *           100;
  10869          * quality = (quantized_tx_load - quantized_qsize) *
  10870          *           tx_load_percent / 100 + quantized_qsize;
  10871          * tx_load_percent = (quality - quantized_qsize) * 100 /
  10872          *                   (quantized_tx_load - quantized_qsize); 
  10873          *
  10874          * The index to DLB_ECMP_QUALITY_MAPPING table consists of
  10875          * base_index + quantized_tx_load * 8 + quantized_qsize,
  10876          * where quantized_tx_load and quantized_qsize range from
  10877          * 0 to 7.
  10878          *
  10879          * With quantized_tx_load = 7 and quantized_qsize = 0, the 
  10880          * index to DLB_ECMP_QUALITY_MAPPING table is
  10881          * base_index + 56, and the tx_load_percent expression
  10882          * simplifies to quality * 100 / 7;
  10883          */
  10884         BCM_IF_ERROR_RETURN(READ_DLB_ECMP_QUALITY_MAPPINGm(unit,
  10885                     MEM_BLOCK_ANY, base_index + 56,
  10886                     &quality_mapping_entry));
  10887         quality = soc_DLB_ECMP_QUALITY_MAPPINGm_field32_get(unit,
  10888                 &quality_mapping_entry, QUALITYf);
  10889         ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[profile_ptr] =
  10890             quality * 100 / 7;
  10891     }
  10892 
  10893     return BCM_E_NONE;
  10894 }
  10895 
  10896 /*
  10897  * Function:
  10898  *      bcm_tr3_ecmp_dlb_hw_recover
  10899  * Purpose:
  10900  *      Recover ECMP DLB internal state from hardware.
  10901  * Parameters:
  10902  *      unit - (IN) SOC unit number.
  10903  *      scache_ptr - (IN/OUT) Scache pointer
  10904  * Returns:
  10905  *      BCM_E_XXX
  10906  */
  10907 int
  10908 bcm_tr3_ecmp_dlb_hw_recover(int unit) 
  10909 {
  10910     /* TD3TBD */
  10911     if (SOC_IS_TRIDENT3X(unit)) {
  10912         return BCM_E_NONE;
  10913     }
  10914     BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_member_recover(unit));
  10915     BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_group_recover(unit));
  10916     BCM_IF_ERROR_RETURN(_bcm_tr3_ecmp_dlb_quality_parameters_recover(unit));
  10917     return BCM_E_NONE;
  10918 }
  10919 
  10920 /*
  10921  * Function:
  10922  *      _bcm_tr3_l3_esm_host_state_recover
  10923  * Purpose:
  10924  *      Warmboot recovery for ESM host tbl state.
  10925  *      This is a 'level one' recovery.
  10926  * Parameters:
  10927  *      unit   - (IN) SOC unit number.
  10928  * Returns:
  10929  *      BCM_E_XXX
  10930  */
  10931 int
  10932 _bcm_tr3_l3_esm_host_state_recover(int unit) 
  10933 {
  10934 #if 0
  10935     int tbl;
  10936     soc_mem_t mem[_BCM_TR3_NUM_ESM_HOST_TABLES];
  10937 
  10938     mem[0] = BCM_XGS3_L3_MEM(unit, v4_esm);
  10939     mem[1] = BCM_XGS3_L3_MEM(unit, v4_esm_wide);
  10940     mem[2] = BCM_XGS3_L3_MEM(unit, v6_esm);
  10941     mem[3] = BCM_XGS3_L3_MEM(unit, v6_esm_wide);
  10942 
  10943     for (tbl = 0; tbl < _BCM_TR3_NUM_ESM_HOST_TABLES; tbl++) {
  10944     /* For each of the ESM tables, starting from zero,
  10945      * check the index of the first EXT_TCAM_VBITm 
  10946      * that is invalid. That is the first available 
  10947      * free entry. Set _TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl) 
  10948      * to this value */
  10949     
  10950     }
  10951 #endif
  10952     
  10953     return (BCM_E_NONE);
  10954 }
  10955 
  10956 #endif /* BCM_WARM_BOOT_SUPPORT */
  10957 
  10958 #ifndef BCM_SW_STATE_DUMP_DISABLE
  10959 
  10960 /*
  10961  * Function:
  10962  *     _bcm_l3_sw_dump
  10963  * Purpose:
  10964  *     Displays L3 information maintained by software.
  10965  * Parameters:
  10966  *     unit - Device unit number
  10967  * Returns:
  10968  *     None
  10969  */
  10970 void
  10971 bcm_tr3_ecmp_dlb_sw_dump(int unit)
  10972 {
  10973     int i;
  10974     _tr3_ecmp_dlb_nh_membership_t *current_ptr;
  10975     int num_entries_per_profile;
  10976     int num_profiles;
  10977     int rv;
  10978     int ref_count;
  10979 
  10980     LOG_CLI((BSL_META_U(unit,
  10981                         "  ECMP DLB Info -\n")));
  10982 
  10983     /* Print ECMP DLB next hop info */
  10984     LOG_CLI((BSL_META_U(unit,
  10985                         "    ECMP DLB Next Hop Info -\n")));
  10986     for (i = 0; i < ECMP_DLB_INFO(unit)->ecmp_dlb_nh_info_size; i++) {
  10987         if (ECMP_DLB_NH_INFO(unit, i).valid) {
  10988             LOG_CLI((BSL_META_U(unit,
  10989                                 "      Next hop index %d is "),
  10990                      ECMP_DLB_NH_INFO(unit, i).nh_index));
  10991             current_ptr = ECMP_DLB_NH_INFO(unit, i).nh_membership_list;
  10992             while (NULL != current_ptr) {
  10993                 LOG_CLI((BSL_META_U(unit,
  10994                                     "member %d in group %d"),
  10995                          current_ptr->member_id, current_ptr->group));
  10996                 current_ptr = current_ptr->next;
  10997                 if (NULL == current_ptr) {
  10998                     LOG_CLI((BSL_META_U(unit,
  10999                                         "\n")));
  11000                 } else {
  11001                     LOG_CLI((BSL_META_U(unit,
  11002                                         ", ")));
  11003                 }
  11004             }
  11005         }
  11006     }
  11007 
  11008     /* Print ECMP DLB group usage */
  11009     LOG_CLI((BSL_META_U(unit,
  11010                         "    ECMP DLB Groups Used:")));
  11011     for (i = 0; i < soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm); i++) {
  11012         if (_BCM_ECMP_DLB_ID_USED_GET(unit, i)) {
  11013             LOG_CLI((BSL_META_U(unit,
  11014                                 " %d"), i));
  11015         }
  11016     }
  11017     LOG_CLI((BSL_META_U(unit,
  11018                         "\n")));
  11019 
  11020     /* Print ECMP DLB flowset table usage */
  11021     LOG_CLI((BSL_META_U(unit,
  11022                         "    ECMP DLB Flowset Table Blocks Used:")));
  11023     for (i = 0; i < soc_mem_index_count(unit, DLB_ECMP_FLOWSETm) >> 9; i++) {
  11024         if (_BCM_ECMP_DLB_FLOWSET_BLOCK_USED_GET(unit, i)) {
  11025             LOG_CLI((BSL_META_U(unit,
  11026                                 " %d"), i));
  11027         }
  11028     }
  11029     LOG_CLI((BSL_META_U(unit,
  11030                         "\n")));
  11031 
  11032     /* Print ECMP DLB member ID usage */
  11033     LOG_CLI((BSL_META_U(unit,
  11034                         "    ECMP DLB Member IDs Used:")));
  11035     for (i = 0; i < soc_mem_index_count(unit, DLB_ECMP_MEMBER_ATTRIBUTEm); i++) {
  11036         if (_BCM_ECMP_DLB_MEMBER_ID_USED_GET(unit, i)) {
  11037             LOG_CLI((BSL_META_U(unit,
  11038                                 " %d"), i));
  11039         }
  11040     }
  11041     LOG_CLI((BSL_META_U(unit,
  11042                         "\n")));
  11043 
  11044     /* Print sample rate and threshold parameters */
  11045     LOG_CLI((BSL_META_U(unit,
  11046                         "    Sample rate: %d per second\n"),
  11047              ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate));
  11048     LOG_CLI((BSL_META_U(unit,
  11049                         "    Tx load min threshold: %d mbps\n"),
  11050              ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th));
  11051     LOG_CLI((BSL_META_U(unit,
  11052                         "    Tx load max threshold: %d mbps\n"),
  11053              ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th));
  11054     LOG_CLI((BSL_META_U(unit,
  11055                         "    Queue size min threshold: %d cells\n"),
  11056              ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th));
  11057     LOG_CLI((BSL_META_U(unit,
  11058                         "    Queue size max threshold: %d cells\n"),
  11059              ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th));
  11060     LOG_CLI((BSL_META_U(unit,
  11061                         "    Expected load min threshold: %d mbps\n"),
  11062              ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_min_th));
  11063     LOG_CLI((BSL_META_U(unit,
  11064                         "    Expected load max threshold: %d mbps\n"),
  11065              ECMP_DLB_INFO(unit)->ecmp_dlb_exp_load_max_th));
  11066     LOG_CLI((BSL_META_U(unit,
  11067                         "    Imbalance min threshold: %d percent\n"),
  11068              ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_min_th));
  11069     LOG_CLI((BSL_META_U(unit,
  11070                         "    Imbalance max threshold: %d percent\n"),
  11071              ECMP_DLB_INFO(unit)->ecmp_dlb_imbalance_max_th));
  11072 
  11073     /* Print quality mapping profiles */
  11074     LOG_CLI((BSL_META_U(unit,
  11075                         "    Quality mapping profiles:\n")));
  11076     num_entries_per_profile = 64;
  11077     num_profiles = soc_mem_index_count(unit, DLB_ECMP_QUALITY_MAPPINGm) /
  11078         num_entries_per_profile;
  11079     for (i = 0; i < num_profiles; i++) {
  11080         LOG_CLI((BSL_META_U(unit,
  11081                             "      Profile %d: load weight %d percent, "),
  11082                  i, ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[i]));
  11083         rv = soc_profile_mem_ref_count_get(unit, 
  11084                 ECMP_DLB_INFO(unit)->ecmp_dlb_quality_map_profile,
  11085                 i * num_entries_per_profile, &ref_count);
  11086         if (SOC_FAILURE(rv)) {
  11087             LOG_CLI((BSL_META_U(unit,
  11088                                 "\n")));
  11089             continue;
  11090         }
  11091         LOG_CLI((BSL_META_U(unit,
  11092                             "ref count %d\n"), ref_count));
  11093     }
  11094 
  11095     return;
  11096 }
  11097 
  11098 /*
  11099  * Function:
  11100  *     _bcm_tr3_esm_host_tbl_sw_dump
  11101  * Purpose:
  11102  *     Displays L3 information maintained by software.
  11103  * Parameters:
  11104  *     unit - Device unit number
  11105  * Returns:
  11106  *     None
  11107  */
  11108 void 
  11109 _bcm_tr3_esm_host_tbl_sw_dump(int unit) {
  11110 
  11111     int tbl;
  11112     for (tbl = 0; tbl < _BCM_TR3_NUM_ESM_HOST_TABLES ; tbl++) {
  11113         LOG_CLI((BSL_META_U(unit,
  11114                             "ESM Host table %d, free entry: %d\n"), tbl, 
  11115                  _TR3_ESM_HOST_TBL_FREE_ENTRY(unit, tbl)));    
  11116     }
  11117 }
  11118 
  11119 #endif /* BCM_SW_STATE_DUMP_DISABLE */
  11120 
  11121 #endif /* INCLUDE_L3 && BCM_TRIUMPH3_SUPPORT  */