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


      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:     trident2plus specific L3 function implementations
      9  */
     10 #include <shared/bsl.h>
     11 #include <soc/defs.h>
     12 
     13 #if defined(INCLUDE_L3)
     14 #if defined(BCM_FIREBOLT_SUPPORT)
     15 #include <bcm_int/esw/firebolt.h>
     16 #endif
     17 
     18 #ifdef BCM_RIOT_SUPPORT
     19 #include <assert.h>
     20 #include <sal/core/libc.h>
     21 #include <shared/util.h>
     22 #if defined(BCM_FIREBOLT_SUPPORT)
     23 #include <soc/mem.h>
     24 #include <soc/l3x.h>
     25 #include <bcm/l3.h>
     26 #include <bcm/error.h>
     27 #include <bcm_int/esw/mbcm.h>
     28 #include <bcm_int/esw/l3.h>
     29 #include <bcm_int/esw/vlan.h>
     30 #include <bcm_int/esw/virtual.h>
     31 #if defined(BCM_TRIDENT_SUPPORT)
     32 #include <bcm_int/esw/trident.h>
     33 #endif /* BCM_TRIDENT_SUPPORT*/
     34 #if defined(BCM_TRIDENT2_SUPPORT)
     35 #include <soc/trident2.h>
     36 #include <bcm_int/esw/trident2.h>
     37 #include <bcm_int/esw/nat.h>
     38 #include <bcm_int/esw/qos.h>
     39 #endif /* BCM_TRIDENT_SUPPORT*/
     40 #include <bcm_int/esw/trident2plus.h>
     41 #ifdef BCM_WARM_BOOT_SUPPORT
     42 #include <bcm_int/esw/switch.h>
     43 #endif /* BCM_WARM_BOOT_SUPPORT */
     44 #include <bcm_int/common/multicast.h>
     45 #include <bcm_int/esw_dispatch.h>
     46 #include <bcm_int/esw/failover.h>
     47 #endif
     48 #endif /* BCM_RIOT_SUPPORT */
     49 
     50 /* initialize pointer for useful bokkkeeping information */
     51 #define L3_BK_INFO(_unit_)   (&_bcm_l3_bk_info[_unit_])
     52 
     53 #ifdef BCM_RIOT_SUPPORT
     54 /* Set ul-ol link params */
     55 #define BCM_L3_NH_NUM_UNDERLAY_BUCKETS    1024     
     56 ul_nh_link_t *ul_nh_assoc_head
     57     [BCM_MAX_NUM_UNITS][BCM_L3_NH_NUM_UNDERLAY_BUCKETS] = {{NULL}};
     58 
     59 /*
     60  * Function:
     61  *      bcmi_l3_riot_bank_sel
     62  * Purpose:
     63  *      Initialize banks for L3 objects.
     64  *      The whole l3 table can be divided into 
     65  *      multiple layers and you can set different banks
     66  *      for different layers.
     67  * Parameters:
     68  *      unit - SOC device unit number
     69  * Returns:
     70  *      BCM_E_NONE              Success
     71  *      BCM_E_XXX               ERROR
     72  */
     73 int 
     74 bcmi_l3_riot_bank_sel(int unit)
     75 {   
     76     uint32 bank_sel_reg_val     = 0;
     77     uint32 num_ol_banks      = 0;
     78     uint32 l2_tunnel_parse_control = 0;
     79     _bcm_l3_bookkeeping_t *l3   = L3_BK_INFO(unit);
     80     uint32 ol_bank_bit_value = 0;
     81     int iter;
     82     int num_nh, num_l3_intf;
     83     int max_nh_banks, max_l3_intf_banks;
     84 
     85     if (!(BCMI_RIOT_IS_ENABLED(unit))) {
     86         return BCM_E_NONE;
     87     }
     88 
     89     /* The interface entries can only be allocated in terms of 2k
     90      * banks. if user is allocating in between boundries then we need
     91      * to throw error as hardware cannot divide overlay and underlay 
     92      * entries in between bank.
     93      * If SDK does not return error here then user can start using
     94      * different entries in same banks for overlay and underlay and may
     95      * see unextected results.
     96      */
     97     if (l3->l3_intf_overlay_entries % BCMI_L3_INTF_ENT_PER_BANK(unit)) {
     98         LOG_ERROR(BSL_LS_BCM_L3, (BSL_META_U(unit,
     99             "Please allocate entries in the multiple of %d.\n"), 
    100             BCMI_L3_INTF_ENT_PER_BANK(unit)));
    101 
    102         return BCM_E_PARAM;
    103     }
    104 
    105     if (l3->l3_nh_overlay_entries %  BCMI_L3_NH_ENT_PER_BANK(unit)) {
    106         LOG_ERROR(BSL_LS_BCM_L3, (BSL_META_U(unit,
    107             "Please allocate entries in the multiple of %d.\n"), 
    108             BCMI_L3_NH_ENT_PER_BANK(unit)));
    109 
    110         return BCM_E_PARAM;
    111     }
    112     num_nh = soc_mem_index_count(unit, ING_L3_NEXT_HOPm);
    113     num_l3_intf = soc_mem_index_count(unit, EGR_L3_INTFm);
    114 
    115     max_nh_banks = num_nh / BCMI_L3_NH_ENT_PER_BANK(unit);
    116     max_l3_intf_banks = num_l3_intf / BCMI_L3_INTF_ENT_PER_BANK(unit);
    117 
    118     if (max_nh_banks == 0) {
    119         LOG_ERROR(BSL_LS_BCM_L3, (BSL_META_U(unit,
    120             "No NH banks in system.\n")));
    121         return BCM_E_RESOURCE;
    122     }
    123     if (max_l3_intf_banks == 0) {
    124         LOG_ERROR(BSL_LS_BCM_L3, (BSL_META_U(unit,
    125             "No EGR_L3_INTF banks in system.\n")));
    126         return BCM_E_RESOURCE;
    127     }
    128     /* 
    129      * set banks for EGR_L3_INTF 
    130      * By default ("alloc mode" is 0):
    131      * First set of banks are for overlay.
    132      * Second set of banks are for underlay.
    133      * If "alloc mode" is 1:
    134      * First set of banks are for underlay.
    135      * Second set of banks are for overlay.
    136      */
    137     num_ol_banks = (l3->l3_intf_overlay_entries /
    138         BCMI_L3_INTF_ENT_PER_BANK(unit)) +
    139         ((l3->l3_intf_overlay_entries % BCMI_L3_INTF_ENT_PER_BANK(unit)) ? 1 :
    140         0);
    141 
    142     if (num_ol_banks > max_l3_intf_banks) {
    143         LOG_ERROR(BSL_LS_BCM_L3, (BSL_META_U(unit,
    144             "ERROR : Overlay l3 interface(%d) > total interfaces(%d).\n"),
    145             l3->l3_intf_overlay_entries,
    146             max_l3_intf_banks * BCMI_L3_INTF_ENT_PER_BANK(unit)));
    147 
    148         return BCM_E_CONFIG;
    149     }
    150 
    151     /* Setup the bits for overlay banks. */
    152     for (iter = 0; iter < num_ol_banks; iter++) {
    153         ol_bank_bit_value |= (1 << iter) ;
    154     }
    155     if (l3->l3_intf_overlay_alloc_mode > 0) {
    156         ol_bank_bit_value <<= (max_l3_intf_banks - num_ol_banks);
    157     }
    158 
    159     soc_reg_field_set(unit, EGR_L3_INTF_BANK_SELr, &bank_sel_reg_val,
    160         BANK_SELf, ol_bank_bit_value);
    161     /* set banks in EGR_L3_INTF_BANK_SELr */
    162     SOC_IF_ERROR_RETURN(WRITE_EGR_L3_INTF_BANK_SELr
    163                           (unit, bank_sel_reg_val));
    164 
    165     ol_bank_bit_value = 0;
    166     bank_sel_reg_val     = 0;
    167     /* 
    168      * set banks for ING/EGR/INITIAL_ING_L3_NEXT_HOP. 
    169      * By default ("alloc mode" is 0):
    170      * First set of banks are for overlay.
    171      * Second set of banks are for underlay.
    172      * If "alloc mode" is 1:
    173      * First set of banks are for underlay.
    174      * Second set of banks are for overlay.
    175      */
    176     num_ol_banks = (l3->l3_nh_overlay_entries / BCMI_L3_NH_ENT_PER_BANK(unit)) +
    177         ((l3->l3_nh_overlay_entries % BCMI_L3_NH_ENT_PER_BANK(unit)) ? 1 : 0);
    178     if (l3->l3_nh_reserve_for_ecmp) {
    179         max_nh_banks -=
    180             (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / BCMI_L3_ECMP_PER_BANK(unit))
    181             + ((BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) %
    182             BCMI_L3_ECMP_PER_BANK(unit)) ? 1 : 0);
    183     }
    184     if (num_ol_banks > max_nh_banks) {
    185         LOG_ERROR(BSL_LS_BCM_L3, (BSL_META_U(unit,
    186             "ERROR : Overlay l3 Next hop (%d) > total l3 next hop(%d).\n"),
    187             l3->l3_nh_overlay_entries,
    188             max_nh_banks * BCMI_L3_NH_ENT_PER_BANK(unit)));
    189 
    190         return BCM_E_CONFIG;
    191     }
    192     if (l3->l3_nh_reserve_for_ecmp && (l3->l3_nh_overlay_alloc_mode == 0)) {
    193         num_ol_banks +=
    194             (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) / BCMI_L3_ECMP_PER_BANK(unit))
    195             + ((BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) %
    196             BCMI_L3_ECMP_PER_BANK(unit)) ? 1 : 0);
    197     }
    198     for (iter=0; iter < num_ol_banks; iter++) {
    199         ol_bank_bit_value |= (1 << iter) ;
    200     }
    201     if (l3->l3_nh_overlay_alloc_mode > 0) {
    202         if (l3->l3_nh_reserve_for_ecmp) {
    203             ol_bank_bit_value <<= (max_nh_banks - num_ol_banks +
    204                 (BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) /
    205                 BCMI_L3_ECMP_PER_BANK(unit)) +
    206                 ((BCM_XGS3_L3_ECMP_MAX_GROUPS(unit) %
    207                 BCMI_L3_ECMP_PER_BANK(unit)) ? 1 : 0));
    208         } else {
    209             ol_bank_bit_value <<= (max_nh_banks - num_ol_banks);
    210         }
    211     }
    212 
    213     /* set banks in INITIAL_ING_L3_NEXT_HOP_BANK_SELr */
    214     soc_reg_field_set(unit, INITIAL_ING_L3_NEXT_HOP_BANK_SELr,
    215         &bank_sel_reg_val, BANK_SELf, ol_bank_bit_value);
    216 
    217     SOC_IF_ERROR_RETURN(WRITE_INITIAL_ING_L3_NEXT_HOP_BANK_SELr
    218         (unit, bank_sel_reg_val));
    219 
    220     /* set banks in ING_L3_NEXT_HOP_BANK_SELr */
    221     soc_reg_field_set(unit, ING_L3_NEXT_HOP_BANK_SELr,
    222         &bank_sel_reg_val, BANK_SELf, ol_bank_bit_value);
    223 
    224     SOC_IF_ERROR_RETURN(WRITE_ING_L3_NEXT_HOP_BANK_SELr
    225         (unit, bank_sel_reg_val));
    226 
    227     /* set banks in EGR_L3_NEXT_HOP_BANK_SELr */
    228     soc_reg_field_set(unit, EGR_L3_NEXT_HOP_BANK_SELr,
    229         &bank_sel_reg_val, BANK_SELf, ol_bank_bit_value);
    230     SOC_IF_ERROR_RETURN(WRITE_EGR_L3_NEXT_HOP_BANK_SELr
    231         (unit, bank_sel_reg_val));
    232 
    233 #ifdef BCM_TRIDENT3_SUPPORT
    234     if (SOC_IS_TRIDENT3X(unit) &&
    235         (soc_property_get(unit, spn_L3_ECMP_LEVELS, 1) == 2) &&
    236         (l3->l3_ecmp_group_first_lkup_mem_size ||
    237          l3->l3_ecmp_member_first_lkup_mem_size)) {
    238         uint32 rval = 0, rval2 = 0;
    239         int ecmp_level_sel_reg_val = (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit) ? 1 : 0);
    240         soc_reg_field_set(unit, ECMP_CONFIGr, &rval, ECMP_MODEf,
    241                           ecmp_level_sel_reg_val);
    242         soc_reg_field_set(unit, ECMP_CONFIG_2r, &rval2, ECMP_MODEf,
    243                           ecmp_level_sel_reg_val);
    244 
    245         SOC_IF_ERROR_RETURN(WRITE_ECMP_CONFIGr(unit, rval));
    246         SOC_IF_ERROR_RETURN(WRITE_ECMP_CONFIG_2r(unit, rval2));
    247 
    248         if (l3->l3_ecmp_group_first_lkup_mem_size <= BCM_XGS3_L3_ECMP_MAX_GROUPS(unit)) {
    249             ol_bank_bit_value = (1 <<
    250                     ((l3->l3_ecmp_group_first_lkup_mem_size / BCMI_L3_ECMP_GROUP_PER_BANK(unit)) +
    251                      ((l3->l3_ecmp_group_first_lkup_mem_size % BCMI_L3_ECMP_GROUP_PER_BANK(unit)) ?
    252                       1 : 0))) - 1;
    253             soc_reg_field_set(unit, ING_L3_ECMP_GROUP_BANK_SELr,
    254                     &bank_sel_reg_val, BANK_SELf, ol_bank_bit_value);
    255             SOC_IF_ERROR_RETURN(WRITE_ING_L3_ECMP_GROUP_BANK_SELr
    256                     (unit, bank_sel_reg_val));
    257             soc_reg_field_set(unit, INITIAL_ING_L3_ECMP_GROUP_BANK_SELr,
    258                     &bank_sel_reg_val, BANK_SELf, ol_bank_bit_value);
    259             SOC_IF_ERROR_RETURN(WRITE_INITIAL_ING_L3_ECMP_GROUP_BANK_SELr
    260                     (unit, bank_sel_reg_val));
    261         } else {
    262             LOG_ERROR(BSL_LS_BCM_L3, (BSL_META_U(unit,
    263                             "ERROR : l3 ecmp group (%d) > total l3 ecmp group(%d).\n"),
    264                         l3->l3_ecmp_group_first_lkup_mem_size,
    265                         BCM_XGS3_L3_ECMP_MAX_GROUPS(unit)));
    266 
    267             return BCM_E_CONFIG;
    268         }
    269 
    270         if (l3->l3_ecmp_member_first_lkup_mem_size <= (soc_mem_index_count(unit,
    271             L3_ECMPm))) {
    272             ol_bank_bit_value = (1 <<
    273                     ((l3->l3_ecmp_group_first_lkup_mem_size / BCMI_L3_ECMP_PER_BANK(unit)) +
    274                      ((l3->l3_ecmp_group_first_lkup_mem_size % BCMI_L3_ECMP_PER_BANK(unit)) ?
    275                       1 : 0))) - 1;
    276             soc_reg_field_set(unit, ING_L3_ECMP_BANK_SELr,
    277                     &bank_sel_reg_val, BANK_SELf, ol_bank_bit_value);
    278             SOC_IF_ERROR_RETURN(WRITE_ING_L3_ECMP_BANK_SELr
    279                     (unit, bank_sel_reg_val));
    280             soc_reg_field_set(unit, INITIAL_ING_L3_ECMP_BANK_SELr,
    281                     &bank_sel_reg_val, BANK_SELf, ol_bank_bit_value);
    282             SOC_IF_ERROR_RETURN(WRITE_INITIAL_ING_L3_ECMP_BANK_SELr
    283                     (unit, bank_sel_reg_val));
    284         } else {
    285             LOG_ERROR(BSL_LS_BCM_L3, (BSL_META_U(unit,
    286                             "ERROR : l3 ecmp group (%d) > total l3 ecmp group(%d).\n"),
    287                         l3->l3_ecmp_group_first_lkup_mem_size,
    288                         BCM_XGS3_L3_ECMP_MAX(unit)));
    289 
    290             return BCM_E_CONFIG;
    291         }
    292     }
    293 #endif
    294 
    295     /* Enable the control to look into inner l3 header for RioT */
    296     soc_reg_field_set(unit, ING_L2_TUNNEL_PARSE_CONTROLr,
    297         &l2_tunnel_parse_control, IFP_L2_TUNNEL_PAYLOAD_FIELD_SELf, 0x1);
    298     soc_reg_field_set(unit, ING_L2_TUNNEL_PARSE_CONTROLr,
    299         &l2_tunnel_parse_control, PARSE_IPV4_PAYLOADf, 0x1);
    300     soc_reg_field_set(unit, ING_L2_TUNNEL_PARSE_CONTROLr,
    301         &l2_tunnel_parse_control, PARSE_IPV6_PAYLOADf, 0x1);
    302     SOC_IF_ERROR_RETURN(WRITE_ING_L2_TUNNEL_PARSE_CONTROLr
    303         (unit, l2_tunnel_parse_control));
    304 
    305     return BCM_E_NONE;
    306 }
    307 
    308 /*
    309  * Function:
    310  *      bcmi_l3_riot_ecmp_level_sel
    311  * Purpose:
    312  *      Initialize banks for L3 objects.
    313  *      The whole l3 table can be divided into 
    314  *      multiple layers and you can set different banks
    315  *      for different layers.
    316  * Parameters:
    317  *      unit - SOC device unit number
    318  * Returns:
    319  *      BCM_E_NONE              Success
    320  *      BCM_E_XXX               ERROR
    321  */
    322 int
    323 bcmi_l3_riot_ecmp_level_sel(int unit)
    324 {   
    325     uint32 ecmp_level_sel_reg_val = 0;
    326     uint32 rval = 0;
    327 #if defined(BCM_TRIDENT3_SUPPORT)
    328     uint32 rval2 = 0;
    329     uint32 ecmp_bank_sel_reg_val = 0;
    330 #endif
    331 
    332     /* 
    333      * If ecmp level is multi level then set ecmp config register to 1.
    334      * else set the ecmp config register to 0. 0 is default case for
    335      * legacy single level of ecmp.
    336      */
    337     ecmp_level_sel_reg_val = (BCMI_L3_ECMP_IS_MULTI_LEVEL(unit) ? 1 : 0);
    338 #if defined(BCM_TRIDENT3_SUPPORT)
    339     if (soc_feature(unit, soc_feature_td3_style_riot)) {
    340         soc_reg_field_set(unit, ECMP_CONFIGr, &rval, ECMP_MODEf,
    341                 ecmp_level_sel_reg_val);
    342         soc_reg_field_set(unit, ECMP_CONFIG_2r, &rval2, ECMP_MODEf,
    343                 ecmp_level_sel_reg_val);
    344 
    345         SOC_IF_ERROR_RETURN(WRITE_ECMP_CONFIGr(unit, rval));
    346         SOC_IF_ERROR_RETURN(WRITE_ECMP_CONFIG_2r(unit, rval2));
    347 
    348         if (ecmp_level_sel_reg_val) {
    349             /* Divide ECMP entries into two equal halves for two level resolution */
    350             /* Need to provide option for bank selection later */
    351             /* Maximum number of ECMP group and member banks is 8 in TD3 and 4
    352              * in HX5.
    353              */
    354             soc_reg_field_set(unit, INITIAL_ING_L3_ECMP_BANK_SELr,
    355                               &ecmp_bank_sel_reg_val, BANK_SELf,
    356                               ((1 << (soc_reg_field_length(unit,
    357                               INITIAL_ING_L3_ECMP_BANK_SELr, BANK_SELf) / 2))
    358                               - 1));
    359             SOC_IF_ERROR_RETURN(WRITE_INITIAL_ING_L3_ECMP_BANK_SELr
    360                                 (unit, ecmp_bank_sel_reg_val));
    361 
    362             soc_reg_field_set(unit, ING_L3_ECMP_BANK_SELr,
    363                               &ecmp_bank_sel_reg_val, BANK_SELf,
    364                               ((1 << (soc_reg_field_length(unit,
    365                               ING_L3_ECMP_BANK_SELr, BANK_SELf) / 2))
    366                               - 1));
    367             SOC_IF_ERROR_RETURN(WRITE_ING_L3_ECMP_BANK_SELr
    368                                 (unit, ecmp_bank_sel_reg_val));
    369 
    370             ecmp_bank_sel_reg_val = 0;
    371 
    372             soc_reg_field_set(unit, INITIAL_ING_L3_ECMP_GROUP_BANK_SELr,
    373                               &ecmp_bank_sel_reg_val, BANK_SELf,
    374                               ((1 << (soc_reg_field_length(unit,
    375                               INITIAL_ING_L3_ECMP_GROUP_BANK_SELr, BANK_SELf)
    376                               / 2)) - 1));
    377             SOC_IF_ERROR_RETURN(WRITE_INITIAL_ING_L3_ECMP_GROUP_BANK_SELr
    378                                 (unit, ecmp_bank_sel_reg_val));
    379 
    380             soc_reg_field_set(unit, ING_L3_ECMP_GROUP_BANK_SELr,
    381                               &ecmp_bank_sel_reg_val, BANK_SELf,
    382                               ((1 << (soc_reg_field_length(unit,
    383                               ING_L3_ECMP_GROUP_BANK_SELr, BANK_SELf) / 2))
    384                               - 1));
    385             SOC_IF_ERROR_RETURN(WRITE_ING_L3_ECMP_GROUP_BANK_SELr
    386                                 (unit, ecmp_bank_sel_reg_val));
    387 
    388         }
    389     } else
    390 #endif
    391     {
    392     soc_reg_field_set(unit, ECMP_CONFIGr, &rval, ECMP_CONFIGURATIONf,
    393         ecmp_level_sel_reg_val);
    394 
    395     SOC_IF_ERROR_RETURN(WRITE_ECMP_CONFIGr(unit, rval));
    396     }
    397     return BCM_E_NONE;
    398 }
    399 
    400 /*
    401  * Function:
    402  *       bcmi_l3_nh_assoc_ol_ul_link_hash_dump 
    403  * Purpose:
    404  *       dumps the whole hash table
    405  * Parameters:
    406  *           IN :  Unit
    407  * Returns:
    408  *        void
    409  */
    410 void bcmi_l3_nh_assoc_ol_ul_link_hash_dump(int unit)
    411 {   
    412 
    413     ol_nh_link_t *temp;
    414     ul_nh_link_t *hash;
    415     int i = 0;
    416 
    417     LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U(unit,
    418         "printing nh association hash table\n")));
    419 
    420     for (; i< BCM_L3_NH_NUM_UNDERLAY_BUCKETS; i++) {
    421         hash =  ul_nh_assoc_head[unit][i];
    422         while (hash != NULL) {
    423             temp = hash->ol_nh_assoc;
    424             while (temp != NULL) {
    425                 LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U(unit,
    426                     "bkt_idx = %d : ol index = %d : ul index = %d \n"),
    427                     i, hash->u_nh_idx, temp->o_nh_idx));
    428                 temp = temp->next_link;
    429             }
    430             hash = hash->ul_nh_link;
    431         }
    432     }
    433 }
    434 
    435 /*
    436  * Function:
    437  *      bcmi_nh_assoc_alloc_ol_link 
    438  * Purpose:
    439  *      Allocates link memory and sets overlay nh.
    440  * Parameters:
    441  *      ol_nh - overlay nh number
    442  * Returns:
    443  *      pointer to allocated link memory              
    444  */
    445 
    446 ol_nh_link_t *
    447 bcmi_nh_assoc_alloc_ol_link(int ol_nh)
    448 {
    449     ol_nh_link_t *ptr ;
    450 
    451     ptr = (ol_nh_link_t *) sal_alloc(sizeof(ol_nh_link_t), "ol_nh_link" );
    452 
    453     sal_memset(ptr, 0, sizeof(ol_nh_link_t));
    454     ptr->o_nh_idx = ol_nh;
    455     return ptr;
    456 }
    457 
    458 /*
    459  * Function:
    460  *      bcmi_nh_assoc_alloc_ul_link 
    461  * Purpose:
    462  *      Allocates link memory and sets underlay nh.
    463  * Parameters:
    464  *      ul_nh - underlay nh number
    465  * Returns:
    466  *      pointer to allocated link memory              
    467  */
    468 ul_nh_link_t *
    469 bcmi_nh_assoc_alloc_ul_link(int ul_nh)
    470 {   
    471     ul_nh_link_t *ptr;
    472 
    473     ptr = (ul_nh_link_t *) sal_alloc(sizeof(ul_nh_link_t), "ul_nh_link");
    474     sal_memset(ptr, 0, sizeof(ul_nh_link_t));
    475 
    476     ptr->u_nh_idx = ul_nh;
    477     return ptr;
    478 }
    479 
    480 
    481 /*
    482  * Function:
    483  *      bcmi_nh_assoc_bkt_get
    484  * Purpose:
    485  *      Adds a overlay/underlay association.
    486  * Parameters:
    487  *      ol_nh - overlay nh number
    488  *      ul_nh - underlay nh number
    489  * Returns:
    490  *      BCM_ERROR_T              
    491  */
    492 int 
    493 bcmi_nh_assoc_bkt_get(int nh_idx)
    494 {
    495 
    496 
    497     return( _shr_crc16b(0, (uint8 *)(&nh_idx),
    498         BYTES2BITS(sizeof(nh_idx))) %
    499         BCM_L3_NH_NUM_UNDERLAY_BUCKETS);
    500 
    501 }
    502 /*
    503  * Function:
    504  *      bcmi_l3_nh_assoc_ol_ul_link_sw_add
    505  * Purpose:
    506  *      Adds a overlay/underlay association.
    507  * Parameters:
    508  *      ol_nh - overlay nh number
    509  *      ul_nh - underlay nh number
    510  * Returns:
    511  *      BCM_ERROR_T              
    512  */
    513 int 
    514 bcmi_l3_nh_assoc_ol_ul_link_sw_add(int unit, int ol_nh, int ul_nh)
    515 {   
    516 
    517     ul_nh_link_t *ul_assoc, *prev_assoc, *ul_alloc;
    518     ol_nh_link_t *ol_link, *prev_link, *ol_alloc;
    519     int bkt_idx = 0;
    520 
    521     if (!(BCMI_RIOT_IS_ENABLED(unit))) {
    522         return BCM_E_NONE;
    523     }
    524 
    525     bkt_idx = bcmi_nh_assoc_bkt_get(ul_nh);
    526 
    527     prev_assoc = ul_assoc = ul_nh_assoc_head[unit][bkt_idx];
    528     while (ul_assoc && (ul_assoc->u_nh_idx != ul_nh)) {
    529         prev_assoc = ul_assoc;
    530         ul_assoc = ul_assoc->ul_nh_link;
    531     }
    532 
    533     if (ul_assoc) {
    534         prev_link = ol_link = ul_assoc->ol_nh_assoc;
    535         while (ol_link && (ol_link->o_nh_idx != ol_nh)) {
    536             prev_link = ol_link;
    537             ol_link = ol_link->next_link;
    538         }
    539         if (!ol_link) {
    540             ol_alloc =  bcmi_nh_assoc_alloc_ol_link(ol_nh);
    541             if (ol_alloc == NULL) {
    542                 return BCM_E_MEMORY;
    543             }
    544             prev_link->next_link = ol_alloc;
    545         }
    546     } else {
    547 
    548         ul_alloc = bcmi_nh_assoc_alloc_ul_link(ul_nh);
    549         if (ul_alloc == NULL) {
    550             return BCM_E_MEMORY;
    551         }
    552         ol_alloc = bcmi_nh_assoc_alloc_ol_link(ol_nh);
    553         if (ol_alloc == NULL) {
    554             sal_free(ul_alloc);
    555             return BCM_E_MEMORY;
    556         }
    557 
    558         if (prev_assoc) {
    559             prev_assoc->ul_nh_link = ul_alloc;
    560             prev_assoc->ul_nh_link->ol_nh_assoc = ol_alloc;
    561         } else {
    562             ul_nh_assoc_head[unit][bkt_idx] = ul_alloc;
    563             ul_nh_assoc_head[unit][bkt_idx]->ol_nh_assoc = ol_alloc;
    564         }
    565     }
    566     /* 
    567      * increase the ref count of second next hop so that it
    568      * not deleted in case someone tries to delete it. 
    569      */
    570     BCM_XGS3_L3_ENT_REF_CNT_INC 
    571         (BCM_XGS3_L3_TBL_PTR(unit, next_hop), ul_nh,
    572         _BCM_SINGLE_WIDE); 
    573 
    574     return BCM_E_NONE;
    575 }
    576 
    577 /*
    578  * Function:
    579  *      bcmi_l3_nh_del_nh_nh_assoc 
    580  * Purpose:
    581  *      Encode the dstination value based on the gport.
    582  * Parameters:
    583  *      unit - SOC device unit number
    584  *      nh_idx - next hop index
    585  * Returns:
    586  *      BCM_E_NONE              Success
    587  *      BCM_E_XXX               ERROR
    588  */
    589 int bcmi_l3_nh_assoc_ol_ul_link_delete(int unit, int nh_idx)
    590 {
    591     soc_mem_t mem;                        /* Table location memory. */
    592     egr_l3_next_hop_entry_t  egr_entry;   /* Egress next hop entry. */
    593     int ent_type, next_ptr_type, next_nh_idx;
    594 
    595     if (!(BCMI_RIOT_IS_ENABLED(unit))) {
    596         return BCM_E_NONE;
    597     }
    598 
    599     mem = EGR_L3_NEXT_HOPm;
    600     sal_memset(&egr_entry, 0, sizeof(egr_l3_next_hop_entry_t));
    601 
    602     SOC_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, EGR_L3_NEXT_HOPm,
    603                                           nh_idx, &egr_entry));
    604 
    605     if (soc_feature(unit, soc_feature_mem_access_data_type)) {
    606         ent_type = soc_mem_field32_get(unit, mem, &egr_entry, DATA_TYPEf);
    607     } else {
    608     ent_type = soc_mem_field32_get(unit, mem, &egr_entry, ENTRY_TYPEf);
    609     }
    610 
    611     /* chk if the entry is L3MC */
    612     if (ent_type == BCMI_L3_EGR_NH_MCAST_ENTRY_TYPE) {
    613         next_ptr_type = soc_mem_field32_get
    614             (unit, mem, &egr_entry, L3MC__NEXT_PTR_TYPEf);
    615 
    616         if (next_ptr_type  == BCMI_L3_NH_EGR_NEXT_PTR_TYPE_NH) {
    617             next_nh_idx = soc_mem_field32_get(unit, mem, &egr_entry,
    618                               L3MC__NEXT_PTRf);
    619 
    620             BCM_IF_ERROR_RETURN(
    621                 bcmi_l3_nh_assoc_ol_ul_link_sw_delete(unit, nh_idx, 
    622                 next_nh_idx));
    623         }
    624     }
    625 
    626     return BCM_E_NONE;
    627 }
    628 
    629 /*
    630  * Function:
    631  *      bcmi_l3_nh_assoc_ol_ul_link_sw_delete
    632  * Purpose:
    633  *      Deletes a overlay/underlay association.
    634  *      If there is only one underlay nh link, 
    635  *      then remove the overlay link also.
    636  * Parameters:
    637  *      ol_nh - overlay nh number
    638  *      ul_nh - underlay nh number
    639  * Returns:
    640  *      BCM_ERROR_T              
    641  */
    642 int 
    643 bcmi_l3_nh_assoc_ol_ul_link_sw_delete(int unit, int ol_nh, int ul_nh)
    644 {
    645     ul_nh_link_t *ul_assoc, *prev_assoc;
    646     ol_nh_link_t *link_nh, *prev_link;
    647     int bkt_idx = 0;
    648 
    649     if (!(BCMI_RIOT_IS_ENABLED(unit))) {
    650         return BCM_E_NONE;
    651     }
    652 
    653     bkt_idx = bcmi_nh_assoc_bkt_get(ul_nh);
    654 
    655     prev_assoc = ul_assoc = ul_nh_assoc_head[unit][bkt_idx];
    656 
    657     while (ul_assoc && (ul_assoc->u_nh_idx != ul_nh)) {
    658         prev_assoc = ul_assoc;
    659         ul_assoc = ul_assoc->ul_nh_link;
    660     }
    661 
    662     if (ul_assoc) {
    663         prev_link = link_nh = ul_assoc->ol_nh_assoc;
    664         while (link_nh && (link_nh->o_nh_idx != ol_nh)) {
    665             prev_link = link_nh;
    666             link_nh = link_nh->next_link;
    667         }
    668 
    669         if (link_nh) {
    670             if (link_nh == ul_assoc->ol_nh_assoc) {
    671                 ul_assoc->ol_nh_assoc = link_nh->next_link;
    672             } else {
    673                 prev_link->next_link = link_nh->next_link;
    674             }
    675             sal_free(link_nh);
    676         } else {
    677             /* send an error here */
    678             return BCM_E_NOT_FOUND;
    679         }
    680     }
    681 
    682     if (ul_assoc && (ul_assoc->ol_nh_assoc == NULL)) {
    683         if (ul_assoc == ul_nh_assoc_head[unit][bkt_idx]) {
    684             ul_nh_assoc_head[unit][bkt_idx] = ul_assoc->ul_nh_link;
    685         } else {
    686             prev_assoc->ul_nh_link = ul_assoc->ul_nh_link;
    687         }
    688         sal_free(ul_assoc);
    689     } else if (ul_assoc == NULL) {
    690         return BCM_E_NOT_FOUND;
    691     }
    692     /* 
    693      * decrease the ref count of second next hop so that it
    694      * not deleted in case someone tries to delete it. 
    695      */
    696     BCM_XGS3_L3_ENT_REF_CNT_DEC 
    697         (BCM_XGS3_L3_TBL_PTR(unit, next_hop), ul_nh,
    698         _BCM_SINGLE_WIDE); 
    699 
    700  return BCM_E_NONE;
    701 }
    702 
    703 
    704 /*
    705  * Function:
    706  *      bcmi_l3_nh_assoc_ol_ul_link_replace
    707  * Purpose:
    708  *      Replace overlay/underlay association.
    709  *
    710  * Parameters:
    711  *      ol_nh - overlay nh number
    712  *      ul_nh - underlay nh number
    713  * Returns:
    714  *      BCM_ERROR_T              
    715  */
    716 int 
    717 bcmi_l3_nh_assoc_ol_ul_link_replace(int unit, int old_ul, int new_ul)
    718 {   
    719 
    720     int entry_type, next_ptr_type;
    721     egr_l3_next_hop_entry_t egr_nh;
    722     ul_nh_link_t *ul_assoc;
    723     ol_nh_link_t *ol_link;
    724     int bkt_idx = 0;
    725 
    726     if (!(BCMI_RIOT_IS_ENABLED(unit))) {
    727         return BCM_E_NONE;
    728     }
    729 
    730     bkt_idx = bcmi_nh_assoc_bkt_get(old_ul);
    731 
    732     if (ul_nh_assoc_head[unit][bkt_idx] == NULL) {
    733         /* There is nothing to replace */
    734         return BCM_E_NONE;
    735     }
    736     ul_assoc = ul_nh_assoc_head[unit][bkt_idx];
    737     while (ul_assoc && (ul_assoc->u_nh_idx != old_ul)) {
    738         ul_assoc = ul_assoc->ul_nh_link;
    739     }
    740     /* replace underlay nh index */
    741     if (ul_assoc) {
    742         ol_link = ul_assoc->ol_nh_assoc;
    743         while (ol_link) {
    744 
    745             SOC_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ALL,
    746                 ol_link->o_nh_idx, &egr_nh));
    747             if (soc_feature(unit, soc_feature_mem_access_data_type)) {
    748                 entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit,
    749                                  &egr_nh, DATA_TYPEf);
    750             } else {
    751             entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit,
    752                 &egr_nh, ENTRY_TYPEf);
    753             }
    754             if (entry_type == BCMI_L3_EGR_NH_MCAST_ENTRY_TYPE) {
    755                 next_ptr_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit,
    756                     &egr_nh, L3MC__NEXT_PTR_TYPEf);
    757                 if (next_ptr_type == BCMI_L3_NH_EGR_NEXT_PTR_TYPE_NH) {
    758 
    759                     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
    760                         L3MC__NEXT_PTR_TYPEf, BCMI_L3_NH_EGR_NEXT_PTR_TYPE_NH);
    761                     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
    762                         L3MC__NEXT_PTRf, new_ul);
    763 
    764                     SOC_IF_ERROR_RETURN(soc_mem_write(unit, EGR_L3_NEXT_HOPm,
    765                         MEM_BLOCK_ALL, ol_link->o_nh_idx, &egr_nh));
    766                 }
    767             }
    768         /* For all overlay NHs, replace the underlay NH. */
    769         bcmi_l3_nh_assoc_ol_ul_link_sw_delete(unit, ol_link->o_nh_idx, 
    770             old_ul);
    771         bcmi_l3_nh_assoc_ol_ul_link_sw_add(unit, ol_link->o_nh_idx, 
    772             new_ul);
    773         ol_link = ol_link->next_link;
    774         }
    775 
    776     }
    777 
    778     return BCM_E_NONE;
    779 }
    780 
    781 /*
    782  * Function:
    783  *      bcmi_l3_nh_assoc_ol_ul_link_is_required 
    784  * Purpose:
    785  *      check if nh-nh association is needed.
    786  * Parameters:
    787  *      unit        - unit number
    788  *      vp nh index - underlay nh number
    789  * Returns:
    790  *      BCM_ERROR_T              
    791  */
    792 int 
    793 bcmi_l3_nh_assoc_ol_ul_link_is_required(int unit, int vp_nh_index)
    794 { 
    795    /* int entry_type = 0;
    796     egr_l3_next_hop_entry_t egr_nh;
    797     int action_present=0, action_not_present=0, vntag_actions = 0;*/
    798 
    799     if (!(BCMI_RIOT_IS_ENABLED(unit))) {
    800         return BCM_E_NONE;
    801     }
    802 #if 0
    803     /*For TD3, the overlay nh can't be updated easily when underlay nh is changed*/
    804     SOC_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ALL,
    805                   vp_nh_index, &egr_nh));
    806     if (soc_feature(unit, soc_feature_mem_access_data_type)) {
    807         entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh, DATA_TYPEf);
    808     } else {
    809     entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh, ENTRY_TYPEf);
    810     }
    811     /* only TD3 can have no underlay sd_tag. For TD2+, SRC MAC will not be modified */
    812     if (SOC_IS_TRIDENT3X(unit) && (entry_type == BCMI_L3_EGR_NH_SD_TAG_ENTRY_TYPE)) {
    813         /* check if sdtag egr nh has some tag actions */
    814         action_present =
    815              soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh,
    816                                          SD_TAG__SD_TAG_ACTION_IF_PRESENTf);
    817         action_not_present =
    818              soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh,
    819                                          SD_TAG__SD_TAG_ACTION_IF_NOT_PRESENTf);
    820         vntag_actions =
    821              soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh,
    822                                          SD_TAG__VNTAG_ACTIONSf);
    823 
    824         if (vntag_actions || action_present || action_not_present) {
    825             /* 
    826              * this next hop can do some modifications and therefore
    827              * we should set nh-nh association for this NH.
    828              */
    829             return 1;
    830         } else {
    831             return 0;
    832         }
    833     }
    834 #endif
    835     return 1;
    836 }
    837 
    838 /*
    839  * Function:
    840  *      bcmi_l3_nh_assoc_ol_ul_link_reinit
    841  * Purpose:
    842  *      re-initializes overlay/underlay association.
    843  * Parameters:
    844  *      unit     - unit number
    845  *      ol_nh - overlay nh number
    846  *      ul_nh - underlay nh number
    847  * Returns:
    848  *      BCM_ERROR_T              
    849  */
    850 int 
    851 bcmi_l3_nh_assoc_ol_ul_link_reinit(int unit, int ol_nh_idx)
    852 {
    853     int entry_type, next_ptr_type, ul_nh_idx;
    854     egr_l3_next_hop_entry_t egr_nh;
    855 
    856     if (!(BCMI_RIOT_IS_ENABLED(unit))) {
    857         return BCM_E_NONE;
    858     }
    859 
    860     BCM_IF_ERROR_RETURN
    861         (READ_EGR_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY, ol_nh_idx, &egr_nh));
    862 
    863     if (soc_feature(unit, soc_feature_mem_access_data_type)) {
    864        entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh, DATA_TYPEf);
    865     } else {
    866     entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh, ENTRY_TYPEf);
    867     }
    868 
    869     if (entry_type == BCMI_L3_EGR_NH_MCAST_ENTRY_TYPE) { 
    870         next_ptr_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit,
    871             &egr_nh, L3MC__NEXT_PTR_TYPEf);
    872         if (next_ptr_type == BCMI_L3_NH_EGR_NEXT_PTR_TYPE_NH) {
    873         
    874             ul_nh_idx =  soc_EGR_L3_NEXT_HOPm_field32_get(unit,
    875                 &egr_nh, L3MC__NEXT_PTRf);
    876 
    877             BCM_IF_ERROR_RETURN(
    878                 bcmi_l3_nh_assoc_ol_ul_link_sw_add(unit, ol_nh_idx, 
    879                 ul_nh_idx));
    880         }
    881     }
    882     return BCM_E_NONE;
    883 }
    884 
    885 /*
    886  * Function:
    887  *      bcmi_nh_destination_set
    888  * Purpose:
    889  *      Encode the dstination value based on the gport.
    890  * Parameters:
    891  *      unit - SOC device unit number
    892  * Returns:
    893  *      BCM_E_NONE              Success
    894  *      BCM_E_XXX               ERROR
    895  */
    896 
    897 int bcmi_l3_nh_dest_set(int unit, bcm_l3_egress_t *nh_entry, uint32 *nh_dest)
    898 {
    899     int gport_type = 0, port = -1, gport = -1;
    900     int mc_group = 0;
    901 
    902     if(nh_entry->flags2 & BCM_L3_FLAGS2_MC_GROUP){
    903         if (!_BCM_MULTICAST_IS_L3(nh_entry->mc_group)) {
    904             return BCM_E_PARAM;
    905         }
    906         mc_group = _BCM_MULTICAST_ID_GET(nh_entry->mc_group);
    907         *nh_dest = BCMI_L3_NH_DEST_IPMC_GET(mc_group);
    908         return BCM_E_NONE;
    909     }
    910 
    911     gport = nh_entry->port;
    912     gport_type = BCMI_GPORT_TYPE_GET(gport);
    913 
    914     if (BCMI_RIOT_IS_ENABLED(unit)) {
    915 
    916         switch(gport_type) {
    917         case BCM_GPORT_VXLAN_PORT:
    918             port = BCM_GPORT_VXLAN_PORT_ID_GET(gport);
    919             *nh_dest =  BCMI_L3_NH_DEST_DVP_GET(port);
    920         break;
    921         case BCM_GPORT_L2GRE_PORT:
    922             port = BCM_GPORT_L2GRE_PORT_ID_GET(gport);
    923             *nh_dest =  BCMI_L3_NH_DEST_DVP_GET(port);
    924         break;
    925         case BCM_GPORT_MPLS_PORT:
    926             port = BCM_GPORT_MPLS_PORT_ID_GET(gport);
    927             *nh_dest =  BCMI_L3_NH_DEST_DVP_GET(port);
    928         break;
    929         case BCM_GPORT_MIM_PORT:
    930             port = BCM_GPORT_MIM_PORT_ID_GET(gport);
    931             *nh_dest =  BCMI_L3_NH_DEST_DVP_GET(port);
    932         break;
    933         default:
    934             if (nh_entry->flags & BCM_L3_TGID) {
    935                 int tid_is_vp_lag = 0;
    936                 if (soc_feature(unit, soc_feature_vp_lag)) {
    937                     (void)_bcm_esw_trunk_id_is_vp_lag(unit, gport, &tid_is_vp_lag);
    938                 }
    939 
    940                 if (tid_is_vp_lag) {
    941                     int vp_lag_vp;
    942                     /* Get the VP value representing VP LAG */
    943                     BCM_IF_ERROR_RETURN(_bcm_esw_trunk_tid_to_vp_lag_vp(unit,
    944                         gport, &vp_lag_vp));
    945 
    946                     *nh_dest = BCMI_L3_NH_DEST_DVP_GET(vp_lag_vp);
    947                 } else {
    948                     *nh_dest = BCMI_L3_NH_DEST_LAG_GET(nh_entry->port);
    949                 }
    950             } else {
    951                 *nh_dest =  BCMI_L3_NH_DEST_DGLP_GET
    952                     (BCM_L3_DGLP_GET(nh_entry->module, nh_entry->port));
    953             }
    954         }
    955     } else {
    956         if (nh_entry->flags & BCM_L3_TGID) {
    957             *nh_dest = BCMI_L3_NH_DEST_LAG_GET(nh_entry->port);
    958         } else {
    959             *nh_dest =  BCMI_L3_NH_DEST_DGLP_GET
    960                 (BCM_L3_DGLP_GET(nh_entry->module, nh_entry->port));
    961         }
    962 #if defined(BCM_MONTEREY_SUPPORT)
    963         if (soc_feature(unit, soc_feature_xflow_macsec) &&
    964             ((nh_entry->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_ENCRYPT) ||
    965             (nh_entry->flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_DECRYPT))) {
    966             int local_modid;
    967             BCM_IF_ERROR_RETURN
    968                 (bcm_esw_stk_my_modid_get (unit, &local_modid));
    969             *nh_dest =  BCMI_L3_NH_DEST_DGLP_GET
    970                         (BCM_L3_DGLP_GET(local_modid, 66));
    971         }
    972 #endif
    973     }
    974     return BCM_E_NONE;
    975 }
    976 
    977 /*
    978  * Function:
    979  *      bcmi_get_gport_from_destination
    980  * Purpose:
    981  *      Encode the dstination value based on the gport.
    982  * Parameters:
    983  *      unit - SOC device unit number
    984  * Returns:
    985  *      BCM_E_NONE              Success
    986  *      BCM_E_XXX               ERROR
    987  */
    988 int bcmi_get_port_from_destination(int unit, uint32 dest,
    989                                         bcm_l3_egress_t *nh)
    990 {
    991     int vp;
    992 
    993     if (BCMI_L3_NH_DEST_IS_LAG(dest)) {
    994         nh->port = BCMI_L3_NH_PORT_LAG_GET(dest);
    995         nh->flags |= BCM_L3_TGID;
    996     } else if (BCMI_L3_NH_DEST_IS_DGLP(dest)) {
    997         nh->port = BCMI_L3_NH_PORT_DGLP_GET(dest);
    998     } else if (BCMI_L3_NH_DEST_IS_DVP(dest)) {
    999         vp = BCMI_L3_NH_PORT_DVP_GET(dest);
   1000         _bcm_vp_encode_gport(unit, vp, &(nh->port));
   1001     } else if (BCMI_L3_NH_DEST_IS_IPMC(dest)) {
   1002         _BCM_MULTICAST_GROUP_SET(nh->mc_group, _BCM_MULTICAST_TYPE_L3,
   1003                                  BCMI_L3_NH_PORT_IPMC_GET(dest));
   1004         nh->flags2 |= BCM_L3_FLAGS2_MC_GROUP;
   1005     } else {
   1006         nh->port = dest;
   1007     }
   1008 
   1009     return BCM_E_NONE;
   1010 
   1011 }
   1012 
   1013 static soc_profile_mem_t *_bcm_td2p_macda_oui_profile[BCM_MAX_NUM_UNITS] = {NULL};
   1014 
   1015 /*
   1016  * Function:
   1017  *      _bcm_td2p_macda_oui_profile_init
   1018  * Purpose:
   1019  *      Allocate and initialize _bcm_td2p_macda_oui_profile_init
   1020  * Parameters:
   1021  *      unit - (IN)SOC unit number.
   1022  * Returns:
   1023  *      BCM_X_XXX
   1024  */
   1025 bcm_error_t
   1026 _bcm_td2p_macda_oui_profile_init(int unit)
   1027 {
   1028     soc_mem_t mem_profile;
   1029     int entry_words[1];
   1030 
   1031     _bcm_td2p_macda_oui_profile_deinit(unit);
   1032 
   1033     /* Create profile for MACDA_OUI_PROFILE table*/
   1034     _bcm_td2p_macda_oui_profile[unit] = sal_alloc(sizeof(soc_profile_mem_t),
   1035                                                   "MACDA OUI Profile Mem");
   1036     if (_bcm_td2p_macda_oui_profile[unit] == NULL) {
   1037         return BCM_E_MEMORY;
   1038     }
   1039     soc_profile_mem_t_init(_bcm_td2p_macda_oui_profile[unit]);
   1040     mem_profile = EGR_MACDA_OUI_PROFILEm;
   1041     entry_words[0] = BYTES2WORDS(sizeof(egr_macda_oui_profile_entry_t));
   1042     SOC_IF_ERROR_RETURN
   1043         (soc_profile_mem_create(unit, &mem_profile, entry_words, 1,
   1044                                 _bcm_td2p_macda_oui_profile[unit]));
   1045 
   1046     return BCM_E_NONE;
   1047 }
   1048 
   1049 
   1050 /*
   1051  * Function:
   1052  *      _bcm_td2p_macda_oui_profile_deinit
   1053  * Purpose:
   1054  *      Deallocate _bcm_td2p_macda_oui_profile
   1055  * Parameters:
   1056  *      unit - (IN)SOC unit number.
   1057  * Returns:
   1058  *      BCM_X_XXX
   1059  */
   1060 void
   1061 _bcm_td2p_macda_oui_profile_deinit(int unit)
   1062 {
   1063     if (_bcm_td2p_macda_oui_profile[unit]) {
   1064         (void)soc_profile_mem_destroy(unit, _bcm_td2p_macda_oui_profile[unit]);
   1065         sal_free(_bcm_td2p_macda_oui_profile[unit]);
   1066         _bcm_td2p_macda_oui_profile[unit] = NULL;
   1067     }
   1068 }
   1069 
   1070 /*
   1071  * Function:
   1072  *      _bcm_td2p_l3_macda_oui_profile_entry_del
   1073  * Purpose:
   1074  *      Delete entry from profile table
   1075  * Parameters:
   1076  *      unit     - (IN) SOC unit number.
   1077  *      ipv6     - (IN) IPV4 or IPv6 flag
   1078  *      l3cfg    - (IN) L3 entry info.
   1079  *      bufentry - (IN) hw buffer
   1080  * Returns:
   1081  */
   1082 bcm_error_t
   1083 _bcm_td2p_l3_macda_oui_profile_entry_del(int unit, _bcm_l3_cfg_t *l3cfg,
   1084                                          int macda_oui_profile_index)
   1085 {
   1086     /* delete an entry or decrement ref count from EGR_MACDA_OUI_PROFILE table */
   1087     if (macda_oui_profile_index != -1) {
   1088         SOC_IF_ERROR_RETURN(soc_profile_mem_delete(unit, _bcm_td2p_macda_oui_profile[unit],
   1089                                                    macda_oui_profile_index));
   1090     }
   1091     return SOC_E_NONE;
   1092 }
   1093 
   1094 /*
   1095  * Function:
   1096  *      _bcm_td2p_l3_macda_oui_profile_entry_parse
   1097  * Purpose:
   1098  *      TD2P helper routine used to parse hw l3 entry to api format
   1099  * Parameters:
   1100  *      unit      - (IN) SOC unit number.
   1101  *      mem       - (IN) L3 table memory.
   1102  *      l3cfg     - (IN) L3 entry info.
   1103  *      l3x_entry - (IN) hw buffer.
   1104  * Returns:
   1105  */
   1106 bcm_error_t
   1107 _bcm_td2p_l3_macda_oui_profile_entry_parse(int unit, soc_mem_t mem,
   1108                                            _bcm_l3_cfg_t *l3cfg, void *l3x_entry)
   1109 {
   1110     uint32 profile_index;
   1111     uint32 mac_field;
   1112     int rv = BCM_E_NONE;
   1113     int ipv6;                     /* Entry is IPv6 flag.         */
   1114     _bcm_l3_fields_t *fld;        /* L3 table common fields.     */
   1115     uint32 *buf_p;                /* HW buffer address.          */
   1116     egr_macda_oui_profile_entry_t macda_oui_profile_entry;
   1117 
   1118     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
   1119     buf_p = (uint32 *)l3x_entry;
   1120 
   1121     /* Set table fields */
   1122     BCM_TD2_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
   1123     soc_mem_mac_address_get(unit, mem, buf_p, fld->macda_lsb,
   1124                             l3cfg->l3c_mac_addr,
   1125                             SOC_MEM_MAC_LOWER_ONLY);
   1126     /* Read upper 3 bytes of MAC address from profile table */
   1127     profile_index = soc_mem_field32_get(unit, mem, buf_p,
   1128                                               fld->oui_profile_index);
   1129     SOC_IF_ERROR_RETURN
   1130         (READ_EGR_MACDA_OUI_PROFILEm(unit, MEM_BLOCK_ANY, profile_index,
   1131                                      &macda_oui_profile_entry));
   1132     soc_EGR_MACDA_OUI_PROFILEm_field_get(unit, &macda_oui_profile_entry,
   1133                                          MACDA_OUIf, &mac_field);
   1134     l3cfg->l3c_mac_addr[0] = (uint8) (mac_field >> 16 & 0xff);
   1135     l3cfg->l3c_mac_addr[1] = (uint8) (mac_field >> 8 & 0xff);
   1136     l3cfg->l3c_mac_addr[2] = (uint8) (mac_field & 0xff);
   1137 
   1138     return rv;
   1139 }
   1140 
   1141 
   1142 /*
   1143  * Function:
   1144  *      _bcm_td2p_l3_macda_oui_profile_entry_add
   1145  * Purpose:
   1146  *      TD2P helper routine used to set some fields in hw l3 entry
   1147  * Parameters:
   1148  *      unit      - (IN) SOC unit number.
   1149  *      mem       - (IN) L3 table memory.
   1150  *      l3cfg     - (IN) L3 entry info.
   1151  *      buf_p     - (IN) hw buffer.
   1152  * Returns:
   1153  *      BCM_X_XXX
   1154  */
   1155 bcm_error_t
   1156 _bcm_td2p_l3_macda_oui_profile_entry_add(int unit, soc_mem_t mem, _bcm_l3_cfg_t *l3cfg,
   1157                                          uint32 *buf_p, int *macda_oui_profile_index)
   1158 {
   1159     int rv = BCM_E_NONE;
   1160     int ipv6;                     /* Entry is IPv6 flag.         */
   1161     _bcm_l3_fields_t *fld;        /* L3 table common fields.     */
   1162     uint32 *bufp;                 /* HW buffer address.          */
   1163     uint32 profile_idx;
   1164     uint32 mac_oui;
   1165     void *entries[1];
   1166     egr_macda_oui_profile_entry_t macda_oui_profile_entry;
   1167 
   1168     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
   1169     /* Set table fields */
   1170     BCM_TD2_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld);
   1171     bufp = buf_p;
   1172 
   1173     /* Set MACDA_OUI_PROFILE_VALID to 1 */
   1174     soc_mem_field32_set(unit, mem, bufp, fld->oui_profile_valid, 1);
   1175 
   1176     /* Set the MACDA_LSB field */
   1177     soc_mem_mac_address_set(unit, mem, bufp, fld->macda_lsb,
   1178                             l3cfg->l3c_mac_addr,
   1179                             SOC_MEM_MAC_LOWER_ONLY);
   1180     /* Setup EGR_MACDA_OUI_PROFILE table with MACDA_OUI */
   1181     mac_oui = ((l3cfg->l3c_mac_addr[0] << 16) |
   1182                (l3cfg->l3c_mac_addr[1] << 8)  |
   1183                (l3cfg->l3c_mac_addr[2] << 0));
   1184     sal_memset(&macda_oui_profile_entry, 0, sizeof(macda_oui_profile_entry));
   1185     soc_EGR_MACDA_OUI_PROFILEm_field_set(unit, &macda_oui_profile_entry,
   1186                                          MACDA_OUIf, &mac_oui);
   1187     entries[0] = &macda_oui_profile_entry;
   1188     rv = soc_profile_mem_add(unit, _bcm_td2p_macda_oui_profile[unit],
   1189                              entries, 1, &profile_idx);
   1190 
   1191     *macda_oui_profile_index = profile_idx;
   1192     /* Set the MACDA_OUI_PROFILE_INDEX field */
   1193     soc_mem_field32_set(unit, mem, bufp, fld->oui_profile_index, profile_idx);
   1194 
   1195     return rv;
   1196 }
   1197 /*
   1198  * Function:
   1199  *      _bcm_td2p_l3_macda_oui_profile_entry_replace
   1200  * Purpose:
   1201  *      TD2P helper routine used to replace hw L3 entry
   1202  * Parameters:
   1203  *      unit      - (IN) SOC unit number.
   1204  *      mem       - (IN) L3 table memory.
   1205  *      l3cfg     - (IN) L3 entry info.
   1206  *      buf_p     - (IN) hw buffer.
   1207  * Returns:
   1208  *      BCM_X_XXX
   1209  */
   1210 bcm_error_t
   1211 _bcm_td2p_l3_macda_oui_profile_entry_replace(int unit, soc_mem_t mem,
   1212                                              _bcm_l3_cfg_t *l3cfg, uint32 *bufp)
   1213 {
   1214     /* For BCM_L3_REPLACE, get profile index for EGR_MACDA_OUI_PROFILE table.
   1215      * Delete the profile entry if it's not used by any other host.
   1216      */
   1217     int macda_oui_profile_index = -1;
   1218     int macda_oui_profile_index_new = -1;
   1219     int ref_count = 0;
   1220     int rv = BCM_E_NONE;
   1221     rv = _bcm_td2p_l3_get_macda_oui_profile_index(unit, mem, l3cfg,
   1222                                                   &macda_oui_profile_index,
   1223                                                   &ref_count);
   1224     if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) {
   1225         return rv;
   1226     }
   1227     if (macda_oui_profile_index == -1) {
   1228         /* Host entry was done in regular L3_ENTRY table view, add it to extended view */
   1229         BCM_IF_ERROR_RETURN
   1230         (_bcm_td2p_l3_macda_oui_profile_entry_add(unit, mem, l3cfg, bufp,
   1231                                                   &macda_oui_profile_index_new));
   1232     } else {
   1233         /* Add new entry, ref_count is automatically incremented */
   1234         rv = _bcm_td2p_l3_macda_oui_profile_entry_add(unit, mem, l3cfg, bufp,
   1235                                                       &macda_oui_profile_index_new);
   1236         if (BCM_SUCCESS(rv)) {
   1237             /* Delete old entry from profile table */
   1238             BCM_IF_ERROR_RETURN
   1239             (_bcm_td2p_l3_macda_oui_profile_entry_del(unit, l3cfg,
   1240                                                       macda_oui_profile_index));
   1241         } else {
   1242             return rv;
   1243         }
   1244     }
   1245     return rv;
   1246 }
   1247 
   1248 /*
   1249  * Function:
   1250  *      _bcm_td2p_l3_get_macda_oui_profile_index
   1251  * Purpose:
   1252  *      TD2P helper routine used to get profile index for EGR_MACDA_OUI_PROFILE
   1253  * Parameters:
   1254  *      unit                      - (IN) SOC unit number.
   1255  *      mem                       - (IN) L3 Extended table memory.
   1256  *      l3cfg                     - (IN) L3 entry info.
   1257  *      macda_oui_profile_index   - (out) EGR_MACDA_OUI profile index.
   1258  * Returns:
   1259  *      BCM_X_XXX
   1260  */
   1261 bcm_error_t
   1262 _bcm_td2p_l3_get_macda_oui_profile_index(int unit, soc_mem_t mem_ext, _bcm_l3_cfg_t *l3cfg,
   1263                                          int *macda_oui_profile_index, int *ref_count)
   1264 {
   1265     int ipv6;                          /* IPv6 entry indicator.*/
   1266     int rv = BCM_E_NONE;               /* Operation return status. */
   1267     uint32 *buf_key, *buf_entry;       /* Key and entry buffer ptrs*/
   1268     l3_entry_ipv4_unicast_entry_t l3v4_key, l3v4_entry;            /* IPv4 */
   1269     l3_entry_ipv4_multicast_entry_t l3v4_ext_key, l3v4_ext_entry; /* IPv4-Embedded */
   1270     l3_entry_ipv6_unicast_entry_t l3v6_key, l3v6_entry;           /* IPv6 */
   1271     l3_entry_ipv6_multicast_entry_t l3v6_ext_key, l3v6_ext_entry; /* IPv6-Embedded */
   1272     soc_field_t macda_oui_index, macda_oui_valid;
   1273     uint32 macda_oui_profile_valid = 0;
   1274     soc_mem_t mem;
   1275 
   1276     /* Get entry type. */
   1277     ipv6 = (l3cfg->l3c_flags & BCM_L3_IP6);
   1278 
   1279     if (ipv6) {
   1280         macda_oui_index  = IPV6UC_EXT__MACDA_OUI_PROFILE_INDEXf;
   1281         macda_oui_valid  = IPV6UC_EXT__MACDA_OUI_PROFILE_VALIDf;
   1282         mem = BCM_XGS3_L3_MEM(unit, v6);
   1283     } else {
   1284         macda_oui_index  = IPV4UC_EXT__MACDA_OUI_PROFILE_INDEXf;
   1285         macda_oui_valid  = IPV4UC_EXT__MACDA_OUI_PROFILE_VALIDf;
   1286         mem = BCM_XGS3_L3_MEM(unit, v4);
   1287     }
   1288 
   1289     /* Assign entry-key buf based on table being used */
   1290     BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_key,
   1291                               l3v4_key,
   1292                               l3v4_ext_key,
   1293                               l3v6_key,
   1294                               l3v6_ext_key);
   1295 
   1296     /* Assign entry buf based on table being used */
   1297     BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem_ext, buf_entry,
   1298                               l3v4_entry,
   1299                               l3v4_ext_entry,
   1300                               l3v6_entry,
   1301                               l3v6_ext_entry);
   1302     /* Prepare lookup key. */
   1303     BCM_IF_ERROR_RETURN
   1304     (_bcm_td2_l3_ent_init(unit, mem_ext, l3cfg, buf_key));
   1305 
   1306     /* Perform lookup hw. to get full entry in ext-view */
   1307     rv = soc_mem_generic_lookup(unit, mem_ext, MEM_BLOCK_ANY,
   1308                                 _BCM_TD2_L3_MEM_BANKS_ALL,
   1309                                 buf_key, buf_entry, &l3cfg->l3c_hw_index);
   1310     if (SOC_SUCCESS(rv)) {
   1311         /* If entry found, get value of MACDA_OUI_PROFILE_VALIDf */
   1312         macda_oui_profile_valid = soc_mem_field32_get(unit, mem_ext, buf_entry,
   1313                                                       macda_oui_valid);
   1314         if (macda_oui_profile_valid) {
   1315             /* Only if MACDA_OUI_PROFILE_VALIDf is set */
   1316             *macda_oui_profile_index = soc_mem_field32_get(unit, mem_ext, buf_entry,
   1317                                                            macda_oui_index);
   1318             rv = soc_profile_mem_ref_count_get(unit,
   1319                                                _bcm_td2p_macda_oui_profile[unit],
   1320                                                *macda_oui_profile_index,
   1321                                                ref_count);
   1322         }
   1323     } else if (rv == SOC_E_NOT_FOUND) {
   1324         /* Check if entry was added in regular L3_ENTRY table view */
   1325 
   1326         /* Assign entry-key buf based on table being used */
   1327         BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem, buf_key,
   1328                                   l3v4_key,
   1329                                   l3v4_ext_key,
   1330                                   l3v6_key,
   1331                                   l3v6_ext_key);
   1332 
   1333         /* Assign entry buf based on table being used */
   1334         BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem, buf_entry,
   1335                                   l3v4_entry,
   1336                                   l3v4_ext_entry,
   1337                                   l3v6_entry,
   1338                                   l3v6_ext_entry);
   1339         /* Prepare lookup key. */
   1340         BCM_IF_ERROR_RETURN(_bcm_td2_l3_ent_init(unit, mem, l3cfg, buf_key));
   1341 
   1342         /* Perform lookup */
   1343         rv = soc_mem_generic_lookup(unit, mem, MEM_BLOCK_ANY,
   1344                                     _BCM_TD2_L3_MEM_BANKS_ALL,
   1345                                     buf_key, buf_entry, &l3cfg->l3c_hw_index);
   1346     }
   1347 
   1348     return rv;
   1349 }
   1350 
   1351 /*
   1352  * Function:
   1353  *      bcm_td2p_l3_extended_required_scache_size_get
   1354  * Purpose:
   1355  *      Get required MACDA_OUI_PROFILE scache size for Level 2 Warm Boot in TD2P
   1356  *      L3_ENTRY extended view
   1357  * Parameters:
   1358  *      unit - StrataSwitch unit number.
   1359  *      size - (OUT) Required scache size.
   1360  */
   1361 void
   1362 bcm_td2p_l3_extended_required_scache_size_get(int unit, int *size)
   1363 {
   1364     /* Sync the ref_count of EGR_MACDA_OUI_PROFILEm */
   1365     *size += SOC_MEM_SIZE(unit, EGR_MACDA_OUI_PROFILEm) * sizeof(uint32);
   1366 }
   1367 
   1368 /*
   1369  * Function:
   1370  *      bcm_td2p_l3_extended_view_sync
   1371  * Purpose:
   1372  *      Record persistent info into the scache for the MACDA_OUI_PROFILE
   1373  *      for L3_ENTRY extended view.
   1374  * Parameters:
   1375  *      unit - StrataSwitch unit #
   1376  *      scache_ptr - (IN/OUT) Scache pointer
   1377  * Returns:
   1378  *      BCM_E_xxx
   1379  */
   1380 bcm_error_t
   1381 bcm_td2p_l3_extended_view_sync(int unit, uint8 **scache_ptr)
   1382 {
   1383     int rv = BCM_E_NONE;
   1384     int i;
   1385     int ref_count;
   1386 
   1387     if ((scache_ptr == NULL) || (*scache_ptr == NULL)) {
   1388         return BCM_E_PARAM;
   1389     }
   1390 
   1391     /* Record EGR_MACDA_OUI_PROFILEm ref_count in scache */
   1392     for (i = 0; i < SOC_MEM_SIZE(unit, EGR_MACDA_OUI_PROFILEm); i++) {
   1393         rv = soc_profile_mem_ref_count_get(unit,
   1394                                            _bcm_td2p_macda_oui_profile[unit],
   1395                                            i,
   1396                                            &ref_count);
   1397         if (!(rv == SOC_E_NONE)) {
   1398             return rv;
   1399         }
   1400 
   1401         sal_memcpy((*scache_ptr), &ref_count, sizeof(uint32));
   1402         (*scache_ptr) += sizeof(ref_count);
   1403     }
   1404 
   1405     return rv;
   1406 }
   1407 
   1408 /*
   1409  * Function:
   1410  *      bcm_td2p_l3_extended_view_reinit
   1411  * Purpose:
   1412  *      Warm boot recovery for the MACDA_OUI_PROFILE
   1413  *      extended view
   1414  * Parameters:
   1415  *      unit - Device Number
   1416  *      defaul_ver - Warm boot default version
   1417  * Returns:
   1418  *      BCM_E_XXX
   1419  */
   1420 bcm_error_t
   1421 bcm_td2p_l3_extended_view_reinit(int unit, uint8 **scache_ptr)
   1422 {
   1423     int rv = BCM_E_NONE;
   1424     soc_profile_mem_t *profile_mem;
   1425     int i, j, size;
   1426     uint32 ref_count;
   1427 
   1428     if ((scache_ptr == NULL) || (*scache_ptr == NULL)) {
   1429         return BCM_E_PARAM;
   1430     }
   1431 
   1432     /* Update EGR_MACDA_OUI_PROFILE memory profile reference counter */
   1433     profile_mem = _bcm_td2p_macda_oui_profile[unit];
   1434     size = SOC_MEM_SIZE(unit, EGR_MACDA_OUI_PROFILEm);
   1435     for (i = 0; i < size; i++) {
   1436         sal_memcpy(&ref_count, (*scache_ptr), sizeof(uint32));
   1437         (*scache_ptr) += sizeof(ref_count);
   1438         for (j = 0; j < ref_count; j++) {
   1439             SOC_IF_ERROR_RETURN(
   1440             soc_profile_mem_reference(unit, profile_mem, i, 1));
   1441         }
   1442     }
   1443     return rv;
   1444 }
   1445 #endif /* BCM_RIOT_SUPPORT */
   1446 
   1447 /*
   1448  * Function:
   1449  *      bcm_td2p_l3_tables_init
   1450  * Purpose:
   1451  *      Initialize internal L3 tables and enable L3.
   1452  *      TD2P has configurable multi domain banks for
   1453  *      various l3 objects. This routine sets up h/w
   1454  *      tables for corresponding objects and then calls
   1455  *      common tables init routine.
   1456  * Parameters:
   1457  *      unit - SOC unit number.
   1458  * Returns:
   1459  *      BCM_E_XXX.
   1460  */
   1461 int
   1462 bcm_td2p_l3_tables_init(int unit)
   1463 {
   1464 
   1465 #ifdef BCM_TRIDENT3_SUPPORT
   1466     _bcm_l3_bookkeeping_t *l3   = L3_BK_INFO(unit);
   1467 #endif
   1468 #ifdef BCM_RIOT_SUPPORT
   1469     /* Selects L3 banks based on user inputs */
   1470     BCM_IF_ERROR_RETURN(bcmi_l3_riot_bank_sel(unit));
   1471 #endif
   1472 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT)
   1473     if ((!SOC_IS_TRIDENT3X(unit))
   1474 #ifdef BCM_TRIDENT3_SUPPORT
   1475              || ((l3->l3_ecmp_group_first_lkup_mem_size == 0)
   1476              && (l3->l3_ecmp_member_first_lkup_mem_size == 0))
   1477 #endif
   1478     ) {
   1479 #if defined(BCM_RIOT_SUPPORT)
   1480         /* Non-default ecmp partitions not configured */
   1481         /* selects ecmp level */
   1482         BCM_IF_ERROR_RETURN(bcmi_l3_riot_ecmp_level_sel(unit));
   1483 #endif
   1484     }
   1485 #endif
   1486     BCM_IF_ERROR_RETURN(bcm_xgs3_l3_tables_init(unit));
   1487 
   1488     return BCM_E_NONE;
   1489 }
   1490 #endif /* INCLUDE_L3 */