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

ipmc.c (120246B)


      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:        ipmc.c
      8  * Purpose:     Tracks and manages IPMC tables.
      9  */
     10 
     11 #ifdef INCLUDE_L3
     12 #include <shared/bsl.h>
     13 #include <shared/l3.h>
     14 #include <soc/l3x.h>
     15 #if defined(BCM_BRADLEY_SUPPORT)
     16 #include <soc/bradley.h>
     17 #endif /* BCM_BRADLEY_SUPPORT */
     18 
     19 #include <bcm/error.h>
     20 #include <bcm/ipmc.h>
     21 
     22 #include <bcm_int/esw/ipmc.h>
     23 #include <bcm_int/esw/mbcm.h>
     24 #include <bcm_int/esw/firebolt.h>
     25 #include <bcm_int/esw/trx.h>
     26 #include <bcm_int/esw/stack.h>
     27 #include <bcm_int/esw/bradley.h>
     28 #include <bcm_int/esw/triumph.h>
     29 #include <bcm_int/common/multicast.h>
     30 #include <bcm_int/esw/multicast.h>
     31 
     32 #ifdef BCM_TRIUMPH2_SUPPORT
     33 #include <bcm_int/esw/triumph2.h>
     34 #endif /* BCM_TRIUMPH2_SUPPORT */
     35 #if defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_KATANA2_SUPPORT)
     36 #include <bcm_int/esw/triumph3.h>
     37 #endif /* BCM_TRIUMPH3_SUPPORT */
     38 #ifdef BCM_TRIDENT2_SUPPORT
     39 #include <soc/trident2.h>
     40 #include <bcm_int/esw/trident2.h>
     41 #endif /* BCM_TRIDENT2_SUPPORT */
     42 #ifdef BCM_TRIDENT2PLUS_SUPPORT
     43 #include <bcm_int/esw/trident2plus.h>
     44 #endif /* BCM_TRIDENT2PLUS_SUPPORT */
     45 
     46 #ifdef BCM_KATANA2_SUPPORT
     47 #include <bcm_int/esw/katana2.h>
     48 #endif /* BCM_KATANA2_SUPPORT */
     49 #ifdef BCM_TOMAHAWK_SUPPORT
     50 #include <bcm_int/esw/tomahawk.h>
     51 #endif /* BCM_TOMAHAWK_SUPPORT */
     52 
     53 #ifdef BCM_SABER2_SUPPORT
     54 #include <bcm_int/esw/saber2.h>
     55 #endif /* BCM_SABER2_SUPPORT */
     56 #include <bcm_int/esw_dispatch.h>
     57 
     58 /* 
     59  * to define the no_src_check_port_id chip specific value :
     60  *  - GREYHOUND : 0x1f 
     61  *  - HURRICANE3 : 0x3f
     62  *  - GREYHOUND2 : 0x7f
     63  */
     64 #define TR_IPMC_NO_SRC_CHECK_PORT_DEFAULT   (0x3f)
     65 #define TR_IPMC_NO_SRC_CHECK_PORT(unit) ((SOC_IS_TD_TT(unit) || \
     66                                           SOC_IS_TRIUMPH3(unit) || \
     67                                           SOC_IS_KATANAX(unit) || \
     68                                           SOC_IS_GREYHOUND2(unit)) ? 0x7f : \
     69                                           ((SOC_IS_ENDURO(unit) || \
     70                                            SOC_IS_HURRICANE(unit) || \
     71                                            SOC_IS_HURRICANE2(unit) || \
     72                                            SOC_IS_GREYHOUND(unit)) ? 0x1f : \
     73                                            SOC_IS_HURRICANE3(unit) ? 0x3f : \
     74                                            TR_IPMC_NO_SRC_CHECK_PORT_DEFAULT))
     75 
     76 /*
     77  * Function:
     78  *      _bcm_tr_ipmc_l3entry_list_add
     79  * Purpose:
     80  *      Add a L3 entry to IPMC group's linked list of L3 entries
     81  * Parameters:
     82  *      unit       - (IN) BCM device number.
     83  *      ipmc_index - (IN) IPMC group ID.
     84  *      _bcm_l3_cfg_t - (IN) l3 config structure
     85  * Returns:
     86  *      BCM_E_XXX
     87  */
     88 STATIC int
     89 _bcm_tr_ipmc_l3entry_list_add(int unit, int ipmc_index,
     90                                _bcm_l3_cfg_t *l3cfg)
     91 {
     92     _bcm_esw_ipmc_l3entry_t *ipmc_l3entry;
     93    
     94     ipmc_l3entry = sal_alloc(sizeof(_bcm_esw_ipmc_l3entry_t), "IPMC L3 entry");
     95     sal_memset(ipmc_l3entry, 0, sizeof(_bcm_esw_ipmc_l3entry_t));
     96     if (ipmc_l3entry == NULL) {
     97         return BCM_E_MEMORY;
     98     }
     99     ipmc_l3entry->ip6 = (l3cfg->l3c_flags & BCM_L3_IP6) ? 1 : 0;
    100     ipmc_l3entry->l3info.flags = l3cfg->l3c_flags;
    101     ipmc_l3entry->l3info.vrf = l3cfg->l3c_vrf;
    102     ipmc_l3entry->l3info.ip_addr = l3cfg->l3c_ipmc_group;
    103     ipmc_l3entry->l3info.src_ip_addr = l3cfg->l3c_src_ip_addr;
    104     sal_memcpy(ipmc_l3entry->l3info.ip6, l3cfg->l3c_ip6, BCM_IP6_ADDRLEN);
    105     sal_memcpy(ipmc_l3entry->l3info.sip6, l3cfg->l3c_sip6, BCM_IP6_ADDRLEN);
    106     ipmc_l3entry->l3info.vid = l3cfg->l3c_vid;
    107     ipmc_l3entry->l3info.ing_intf = l3cfg->l3c_ing_intf;
    108     ipmc_l3entry->l3info.prio = l3cfg->l3c_prio;
    109     ipmc_l3entry->l3info.ipmc_ptr = l3cfg->l3c_ipmc_ptr;
    110     ipmc_l3entry->l3info.ipmc_ptr_l2 = l3cfg->l3c_ipmc_ptr_l2;
    111     ipmc_l3entry->l3info.lookup_class = l3cfg->l3c_lookup_class;
    112     ipmc_l3entry->l3info.rp_id = l3cfg->l3c_rp_id;
    113 #ifdef BCM_TRIDENT3_SUPPORT
    114     if (soc_feature(unit, soc_feature_flex_flow)) {
    115         ipmc_l3entry->l3info.flow_handle = l3cfg->l3c_flow_handle;
    116         ipmc_l3entry->l3info.flow_option_handle = l3cfg->l3c_flow_option_handle;
    117         ipmc_l3entry->l3info.num_logical_fields = l3cfg->l3c_num_of_fields;
    118         sal_memcpy(ipmc_l3entry->l3info.logical_fields, l3cfg->l3c_logical_fields,
    119                    l3cfg->l3c_num_of_fields*sizeof(bcm_flow_logical_field_t));
    120     }
    121 #endif /* BCM_TRIDENT3_SUPPORT */
    122     ipmc_l3entry->next = IPMC_GROUP_INFO(unit, ipmc_index)->l3entry_list;
    123     IPMC_GROUP_INFO(unit, ipmc_index)->l3entry_list = ipmc_l3entry;
    124 
    125     return BCM_E_NONE;
    126 }
    127 
    128 /*
    129  * Function:
    130  *      _bcm_tr_ipmc_l3entry_list_del
    131  * Purpose:
    132  *      Delete a L3 entry from IPMC group's linked list of L3 entries
    133  * Parameters:
    134  *      unit       - (IN) BCM device number.
    135  *      ipmc_index - (IN) IPMC group ID.
    136  *      _bcm_l3_cfg_t - (IN) l3 config structure
    137  * Returns:
    138  *      BCM_E_XXX
    139  */
    140 STATIC int
    141 _bcm_tr_ipmc_l3entry_list_del(int unit, int ipmc_index,
    142                               _bcm_l3_cfg_t *l3cfg)
    143 {
    144     _bcm_esw_ipmc_l3entry_t *ipmc_l3entry;
    145     _bcm_esw_ipmc_l3entry_t *prev_ipmc_l3entry = NULL;
    146     uint8 matched=0;
    147 
    148     ipmc_l3entry = IPMC_GROUP_INFO(unit, ipmc_index)->l3entry_list;
    149     while (ipmc_l3entry != NULL) {
    150         if ((ipmc_l3entry->l3info.ip_addr == l3cfg->l3c_ip_addr) &&
    151             (ipmc_l3entry->l3info.src_ip_addr == l3cfg->l3c_src_ip_addr) && 
    152             (!_shr_ip6_addr_compare(ipmc_l3entry->l3info.ip6, l3cfg->l3c_ip6)) &&
    153             (!_shr_ip6_addr_compare(ipmc_l3entry->l3info.sip6, l3cfg->l3c_sip6)) &&
    154             (ipmc_l3entry->l3info.vrf == l3cfg->l3c_vrf)) {
    155             
    156             if((ipmc_l3entry->l3info.flags & BCM_L3_L2ONLY) || 
    157                 (ipmc_l3entry->l3info.ing_intf == BCM_IF_INVALID)) {
    158                 matched = (ipmc_l3entry->l3info.vid == l3cfg->l3c_vid) ? 1 : 0;
    159             } else {
    160                 matched = (ipmc_l3entry->l3info.ing_intf == l3cfg->l3c_ing_intf) ? 1 : 0;
    161             }
    162             if(matched) {        
    163                 if (ipmc_l3entry == IPMC_GROUP_INFO(unit, ipmc_index)->l3entry_list) {
    164                     IPMC_GROUP_INFO(unit, ipmc_index)->l3entry_list = ipmc_l3entry->next;
    165                 } else {
    166                     /* 
    167                      * In the following line of code, Coverity thinks the
    168                      * prev_ipmc_l3entry pointer may still be NULL when 
    169                      * dereferenced. This situation will never occur because 
    170                      * if ipmc_l3entry is not pointing to the head of the 
    171                      * linked list, prev_ipmc_l3entry would not be NULL.
    172                      */
    173                     /* coverity[var_deref_op : FALSE] */
    174                     prev_ipmc_l3entry->next = ipmc_l3entry->next;
    175                 }
    176                 sal_free(ipmc_l3entry);
    177                 break;
    178             }
    179         }
    180         prev_ipmc_l3entry = ipmc_l3entry;
    181         ipmc_l3entry = ipmc_l3entry->next;
    182     }
    183 
    184     if (ipmc_l3entry == NULL) {
    185         return BCM_E_NOT_FOUND;
    186     }
    187 
    188     return BCM_E_NONE;
    189 }
    190 
    191 STATIC int
    192 _bcm_tr_ipmc_l3entry_list_update(int unit, int ipmc_index,
    193                                  _bcm_l3_cfg_t *l3cfg)
    194 {
    195     _bcm_esw_ipmc_l3entry_t *ipmc_l3entry;
    196     uint8 matched;
    197 
    198     ipmc_l3entry = IPMC_GROUP_INFO(unit, ipmc_index)->l3entry_list;
    199     while (ipmc_l3entry != NULL) {
    200         if ((ipmc_l3entry->l3info.ip_addr == l3cfg->l3c_ip_addr) &&
    201             (ipmc_l3entry->l3info.src_ip_addr == l3cfg->l3c_src_ip_addr) && 
    202             (!sal_memcmp(ipmc_l3entry->l3info.ip6, l3cfg->l3c_ip6, BCM_IP6_ADDRLEN)) &&
    203             (!sal_memcmp(ipmc_l3entry->l3info.sip6, l3cfg->l3c_sip6, BCM_IP6_ADDRLEN)) &&
    204             (ipmc_l3entry->l3info.ing_intf == l3cfg->l3c_ing_intf) &&
    205             (ipmc_l3entry->l3info.vid == l3cfg->l3c_vid) &&
    206             (ipmc_l3entry->l3info.vrf == l3cfg->l3c_vrf)) {
    207 
    208             if((ipmc_l3entry->l3info.flags & BCM_L3_L2ONLY) || 
    209                     (ipmc_l3entry->l3info.ing_intf == BCM_IF_INVALID)) {
    210                 matched = (ipmc_l3entry->l3info.vid == l3cfg->l3c_vid) ? 1 : 0;
    211             } else {
    212                 matched = (ipmc_l3entry->l3info.ing_intf == l3cfg->l3c_ing_intf) ? 1 : 0; 
    213             }
    214 
    215             if(matched) {
    216                 /* set new values */
    217                 ipmc_l3entry->l3info.flags = l3cfg->l3c_flags;
    218                 ipmc_l3entry->l3info.vrf = l3cfg->l3c_vrf;
    219                 ipmc_l3entry->l3info.prio = l3cfg->l3c_prio;
    220                 ipmc_l3entry->l3info.ipmc_ptr = l3cfg->l3c_ipmc_ptr;
    221                 ipmc_l3entry->l3info.ipmc_ptr_l2 = l3cfg->l3c_ipmc_ptr_l2;
    222                 ipmc_l3entry->l3info.lookup_class = l3cfg->l3c_lookup_class;
    223                 ipmc_l3entry->l3info.rp_id = l3cfg->l3c_rp_id;
    224                 ipmc_l3entry->l3info.vid = l3cfg->l3c_vid;
    225                 ipmc_l3entry->l3info.ing_intf = l3cfg->l3c_ing_intf;
    226             }
    227             break;
    228         }
    229         ipmc_l3entry = ipmc_l3entry->next;
    230     }
    231 
    232     if (ipmc_l3entry == NULL) {
    233         return BCM_E_NOT_FOUND;
    234     }
    235 
    236     return BCM_E_NONE;
    237 }
    238 
    239 /*
    240  * Function:
    241  *      _bcm_tr_ipmc_l3entry_list_size_get
    242  * Purpose:
    243  *      Get the number of L3 entries in IPMC group's linked list.
    244  * Parameters:
    245  *      unit       - (IN) BCM device number.
    246  *      ipmc_index - (IN) IPMC group ID.
    247  *      size       - (OUT) Number of L3 entries.
    248  * Returns:
    249  *      BCM_E_XXX
    250  */
    251 STATIC int
    252 _bcm_tr_ipmc_l3entry_list_size_get(int unit, int ipmc_index,
    253         int *size)
    254 {
    255     if (IPMC_USED_ISSET(unit, ipmc_index)) {
    256         *size = IPMC_GROUP_INFO(unit, ipmc_index)->ref_count - 1;
    257     } else {
    258         *size = 0;
    259     }
    260 
    261     return BCM_E_NONE;
    262 }
    263 
    264 #ifdef BCM_TRIUMPH2_SUPPORT
    265 /*
    266  * Function:
    267  *      _tr2_ipmc_glp_get
    268  * Purpose:
    269  *      Fill source information to bcm_ipmc_addr_t struct.
    270  */
    271 int
    272 _tr2_ipmc_glp_get(int unit, bcm_ipmc_addr_t *ipmc, ipmc_1_entry_t *entry)
    273 
    274 {
    275     int                 mod, port_tgid, is_trunk, rv = BCM_E_NONE;
    276     int                 no_src_check = FALSE;
    277     int                 modid_max = 0;
    278 
    279     is_trunk = soc_L3_IPMC_1m_field32_get(unit, entry, Tf);
    280     mod = soc_L3_IPMC_1m_field32_get(unit, entry, MODULE_IDf);
    281     port_tgid = soc_L3_IPMC_1m_field32_get(unit, entry, PORT_NUMf);
    282 #ifdef BCM_METROLITE_SUPPORT
    283     if (SOC_IS_METROLITE(unit)) {
    284         modid_max = SOC_MEM_FIELD32_VALUE_MAX(
    285                                  unit, L3_IPMC_1m, MODULE_IDf);
    286     }else
    287 #endif
    288     {
    289         modid_max =  SOC_MODID_MAX(unit);
    290     }
    291     if (is_trunk) {
    292         if ((port_tgid == TR_IPMC_NO_SRC_CHECK_PORT(unit)) &&
    293             (mod == modid_max)) {
    294             no_src_check = TRUE;
    295         } else {
    296             mod = 0;
    297             port_tgid = soc_L3_IPMC_1m_field32_get(unit, entry, TGIDf);
    298         }
    299     }
    300     if (no_src_check) {
    301         ipmc->ts = 0;
    302         ipmc->mod_id = -1;
    303         ipmc->port_tgid = -1;
    304         ipmc->flags |= BCM_IPMC_SOURCE_PORT_NOCHECK;
    305     } else if (is_trunk) {
    306         ipmc->ts = 1;
    307         ipmc->mod_id = 0;
    308         ipmc->port_tgid = port_tgid;
    309     } else {
    310         bcm_module_t    mod_in, mod_out;
    311         bcm_port_t      port_in, port_out;
    312 
    313         mod_in = mod;
    314         port_in = port_tgid;
    315         BCM_IF_ERROR_RETURN
    316             (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
    317                                     mod_in, port_in,
    318                                     &mod_out, &port_out));
    319         ipmc->ts = 0;
    320         ipmc->mod_id = mod_out;
    321         ipmc->port_tgid = port_out;
    322     }
    323     return rv;
    324 }
    325 #endif
    326 
    327 /*
    328  * Function:
    329  *      _tr_ipmc_info_get
    330  * Purpose:
    331  *      Fill information in bcm_ipmc_addr_t struct.
    332  */
    333 
    334 STATIC int
    335 _tr_ipmc_info_get(int unit, int ipmc_index, bcm_ipmc_addr_t *ipmc, 
    336                   ipmc_entry_t *entry, uint8 do_l3_lkup, 
    337                   _bcm_esw_ipmc_l3entry_t *use_ipmc_l3entry)
    338 {
    339     int           mod = -1, port_tgid = -1, is_trunk = 0;
    340     int           no_src_check = FALSE;
    341     int           modid_max = 0;
    342 
    343     ipmc->v = soc_L3_IPMCm_field32_get(unit, entry, VALIDf);
    344 #ifdef BCM_METROLITE_SUPPORT
    345     if (SOC_IS_METROLITE(unit)) {
    346         modid_max = SOC_MEM_FIELD32_VALUE_MAX(
    347                                  unit, L3_IPMC_1m, MODULE_IDf);
    348     }else
    349 #endif
    350     {
    351         modid_max =  SOC_MODID_MAX(unit);
    352     }
    353 
    354     if (soc_mem_field_valid(unit, L3_IPMCm, PORT_NUMf)) {
    355         is_trunk = soc_L3_IPMCm_field32_get(unit, entry, Tf);
    356         mod = soc_L3_IPMCm_field32_get(unit, entry, MODULE_IDf);
    357         port_tgid = soc_L3_IPMCm_field32_get(unit, entry, PORT_NUMf);
    358         if (is_trunk) {
    359             if ((port_tgid == TR_IPMC_NO_SRC_CHECK_PORT(unit)) &&
    360                 (mod == modid_max)) {
    361                 no_src_check = TRUE;
    362             } else {
    363                 mod = 0;
    364                 port_tgid = soc_L3_IPMCm_field32_get(unit, entry, TGIDf);
    365             }
    366         }
    367         if (no_src_check) {
    368             ipmc->ts = 0;
    369             ipmc->mod_id = -1;
    370             ipmc->port_tgid = -1;
    371             ipmc->flags |= BCM_IPMC_SOURCE_PORT_NOCHECK;
    372         } else if (is_trunk) {
    373             ipmc->ts = 1;
    374             ipmc->mod_id = 0;
    375             ipmc->port_tgid = port_tgid;
    376         } else {
    377             bcm_module_t    mod_in, mod_out;
    378             bcm_port_t      port_in, port_out;
    379 
    380             mod_in = mod;
    381             port_in = port_tgid;
    382             BCM_IF_ERROR_RETURN
    383                 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
    384                                         mod_in, port_in,
    385                                         &mod_out, &port_out));
    386             ipmc->ts = 0;
    387             ipmc->mod_id = mod_out;
    388             ipmc->port_tgid = port_out;
    389         }
    390     }
    391 
    392     if ((ipmc->v) && (do_l3_lkup)) {
    393         _bcm_l3_cfg_t l3cfg;
    394         _bcm_esw_ipmc_l3entry_t *ipmc_l3entry;
    395 
    396         if (use_ipmc_l3entry) {
    397             /* use the passed in l3 info */
    398             ipmc_l3entry = use_ipmc_l3entry;
    399         } else {
    400             /* Note: this simply picks up the first l3 info */
    401             ipmc_l3entry = IPMC_GROUP_INFO(unit, ipmc_index)->l3entry_list;
    402             if (NULL == ipmc_l3entry) {
    403                 /* No entries in Multicast host table */
    404                 return BCM_E_EMPTY;
    405             }
    406         }
    407         sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
    408         l3cfg.l3c_flags = BCM_L3_IPMC;
    409         l3cfg.l3c_vrf = ipmc_l3entry->l3info.vrf;
    410         l3cfg.l3c_vid = ipmc_l3entry->l3info.vid;
    411         l3cfg.l3c_ing_intf = ipmc_l3entry->l3info.ing_intf;
    412 
    413         if (ipmc_l3entry->l3info.flags & BCM_L3_L2ONLY) {
    414             l3cfg.l3c_flags |= BCM_L3_L2ONLY;
    415             ipmc->flags |= BCM_IPMC_L2;
    416         }
    417         if (ipmc_l3entry->ip6) {
    418             ipmc->flags |= BCM_IPMC_IP6;
    419         } else {
    420             ipmc->flags &= ~BCM_IPMC_IP6;
    421         }
    422         if (ipmc->flags & BCM_IPMC_HIT_CLEAR) {
    423             l3cfg.l3c_flags |= BCM_L3_HIT_CLEAR;
    424         }
    425 
    426         /* need to get current l3 info from h/w like hit bits */
    427         if (ipmc->flags & BCM_IPMC_IP6) {
    428             sal_memcpy(ipmc->s_ip6_addr, &ipmc_l3entry->l3info.sip6, BCM_IP6_ADDRLEN);
    429             sal_memcpy(ipmc->mc_ip6_addr, &ipmc_l3entry->l3info.ip6, BCM_IP6_ADDRLEN);
    430             sal_memcpy(l3cfg.l3c_sip6, &ipmc_l3entry->l3info.sip6, BCM_IP6_ADDRLEN);
    431             sal_memcpy(l3cfg.l3c_ip6, &ipmc_l3entry->l3info.ip6, BCM_IP6_ADDRLEN);
    432             l3cfg.l3c_flags |= BCM_L3_IP6;
    433             BCM_IF_ERROR_RETURN(mbcm_driver[unit]->mbcm_l3_ip6_get(unit, &l3cfg));
    434         } else {
    435             ipmc->s_ip_addr = ipmc_l3entry->l3info.src_ip_addr;
    436             ipmc->mc_ip_addr = ipmc_l3entry->l3info.ipmc_group;
    437             l3cfg.l3c_src_ip_addr = ipmc_l3entry->l3info.src_ip_addr;
    438             l3cfg.l3c_ipmc_group = ipmc_l3entry->l3info.ipmc_group;
    439             BCM_IF_ERROR_RETURN(mbcm_driver[unit]->mbcm_l3_ip4_get(unit, &l3cfg));
    440         }
    441         
    442         if (l3cfg.l3c_flags & BCM_L3_HIT) {
    443             ipmc->flags |= BCM_IPMC_HIT;
    444         }
    445 
    446         if (l3cfg.l3c_flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) {
    447             ipmc->flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK;
    448             ipmc->l3a_intf = l3cfg.l3c_intf;
    449             if (l3cfg.l3c_flags & BCM_IPMC_RPF_FAIL_DROP) {
    450                 ipmc->flags |= BCM_IPMC_RPF_FAIL_DROP;
    451             }
    452             if (l3cfg.l3c_flags & BCM_IPMC_RPF_FAIL_TOCPU) {
    453                 ipmc->flags |= BCM_IPMC_RPF_FAIL_TOCPU;
    454             }
    455         }
    456 
    457 #ifdef BCM_MONTEREY_SUPPORT
    458         if (l3cfg.l3c_flags2 & BCM_L3_FLAGS2_DECAP_ROE_HEADER) {
    459             ipmc->flags |= BCM_IPMC_DECAP_ROE_HEADER;
    460         }
    461 #endif
    462 
    463         if (ipmc_l3entry->l3info.flags & BCM_L3_RPE) {
    464             ipmc->cos = ipmc_l3entry->l3info.prio;
    465             ipmc->flags |= BCM_IPMC_SETPRI;
    466         } else {
    467             ipmc->cos = -1;
    468             ipmc->flags &= ~BCM_IPMC_SETPRI;
    469         }
    470         ipmc->group = ipmc_index;
    471         ipmc->lookup_class = ipmc_l3entry->l3info.lookup_class;
    472         ipmc->vrf = ipmc_l3entry->l3info.vrf;
    473         ipmc->vid = ipmc_l3entry->l3info.vid;
    474         ipmc->ing_intf = ipmc_l3entry->l3info.ing_intf;
    475         ipmc->rp_id = ipmc_l3entry->l3info.rp_id;
    476     }
    477 
    478     return BCM_E_NONE;
    479 }
    480 
    481 /*
    482  * Function:
    483  *      _tr_ipmc_write
    484  * Purpose:
    485  *      Write an ipmc entry from bcm_ipmc_addr_t struct.
    486  */
    487 
    488 STATIC int
    489 _tr_ipmc_write(int unit, int ipmc_id, bcm_ipmc_addr_t *ipmc)
    490 {
    491     int                 rv = BCM_E_NONE;
    492     ipmc_entry_t        entry;
    493     int                 mod, port_tgid, is_trunk, no_src_check = FALSE;
    494     int                 valid_chg = FALSE;
    495 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT)
    496     ipmc_1_entry_t      entry_1;
    497     sal_memset(&entry_1, 0, sizeof(ipmc_1_entry_t));
    498 #endif
    499 
    500     BCM_IF_ERROR_RETURN
    501         (soc_mem_read(unit, L3_IPMCm, MEM_BLOCK_ANY, ipmc_id, &entry));
    502 
    503     if (ipmc->v != soc_L3_IPMCm_field32_get(unit, &entry, VALIDf)) {
    504         valid_chg = TRUE;
    505         soc_L3_IPMCm_field32_set(unit, &entry, VALIDf, ipmc->v);
    506     }
    507   
    508     if (soc_feature(unit, soc_feature_src_port_consistency_check_skip)) {
    509         /* Source port check for L3 Multicast has been moved in lookup table in Tomahawk,
    510          * hence no need to write in replication table for Tomahawk
    511          */
    512         if (valid_chg) {
    513             rv = soc_mem_write(unit, L3_IPMCm, MEM_BLOCK_ALL, ipmc_id, &entry);
    514         }
    515         return rv;
    516     }
    517 
    518     if ((ipmc->flags & BCM_IPMC_SOURCE_PORT_NOCHECK) ||
    519         (ipmc->port_tgid < 0)) {                        /* no source port */
    520         no_src_check = TRUE;
    521         is_trunk = 0;
    522 #ifdef BCM_METROLITE_SUPPORT
    523     if (SOC_IS_METROLITE(unit)) {
    524             mod = SOC_MEM_FIELD32_VALUE_MAX(unit, L3_IPMC_1m, MODULE_IDf);
    525         } else
    526 #endif
    527         {
    528             mod = SOC_MODID_MAX(unit);
    529         }
    530         port_tgid = TR_IPMC_NO_SRC_CHECK_PORT(unit);
    531     } else if (ipmc->ts) {                              /* trunk source port */
    532         is_trunk = 1;
    533         mod = 0;
    534         port_tgid = ipmc->port_tgid;
    535     } else {                                            /* source port */
    536         bcm_module_t    mod_in, mod_out;
    537         bcm_port_t      port_in, port_out;
    538 
    539         mod_in = ipmc->mod_id;
    540         port_in = ipmc->port_tgid;
    541         BCM_IF_ERROR_RETURN
    542             (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET,
    543                                     mod_in, port_in,
    544                                     &mod_out, &port_out));
    545         /* Check parameters, since above is an application callback */
    546         if (!SOC_MODID_ADDRESSABLE(unit, mod_out)) {
    547             return BCM_E_BADID;
    548         }
    549         if (!SOC_PORT_ADDRESSABLE(unit, port_out)) {
    550             return BCM_E_PORT;
    551         }
    552         is_trunk = 0;
    553         mod = mod_out;
    554         port_tgid = port_out;
    555     }
    556 
    557     if (is_trunk) {
    558 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT)
    559         if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) {
    560             soc_L3_IPMC_1m_field32_set(unit, &entry_1, Tf, 1);
    561             soc_L3_IPMC_1m_field32_set(unit, &entry_1, TGIDf, port_tgid);
    562         } else
    563 #endif
    564         {
    565             if (soc_mem_field_valid(unit, L3_IPMCm, Tf)) {
    566                 soc_L3_IPMCm_field32_set(unit, &entry, Tf, 1);
    567             }
    568             if (soc_mem_field_valid(unit, L3_IPMCm, TGIDf)) {
    569                 soc_L3_IPMCm_field32_set(unit, &entry, TGIDf, port_tgid);
    570             }
    571         }
    572     } else {
    573 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT)
    574         if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) {
    575             soc_L3_IPMC_1m_field32_set(unit, &entry_1, MODULE_IDf, mod);
    576             soc_L3_IPMC_1m_field32_set(unit, &entry_1, PORT_NUMf, port_tgid);
    577             if (no_src_check) {
    578                 soc_L3_IPMC_1m_field32_set(unit, &entry_1, Tf, 1);
    579             } else {
    580                 soc_L3_IPMC_1m_field32_set(unit, &entry_1, Tf, 0);
    581             }
    582         } else
    583 #endif
    584         {
    585             if (soc_mem_field_valid(unit, L3_IPMCm, MODULE_IDf)) {
    586                 soc_L3_IPMCm_field32_set(unit, &entry, MODULE_IDf, mod);
    587             }
    588 
    589             if (soc_mem_field_valid(unit, L3_IPMCm, PORT_NUMf)) {
    590                 soc_L3_IPMCm_field32_set(unit, &entry, PORT_NUMf, port_tgid);
    591             }
    592 
    593             if (soc_mem_field_valid(unit, L3_IPMCm, Tf)) {
    594                 if (no_src_check) {
    595                     soc_L3_IPMCm_field32_set(unit, &entry, Tf, 1);
    596                 } else {
    597                     soc_L3_IPMCm_field32_set(unit, &entry, Tf, 0);
    598                 }
    599             }
    600         }
    601     }
    602 
    603 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT)
    604     if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) {
    605         if (valid_chg) {
    606             BCM_IF_ERROR_RETURN(
    607                 soc_mem_write(unit, L3_IPMCm, MEM_BLOCK_ALL, ipmc_id, &entry));
    608         }
    609         rv = soc_mem_write(unit, L3_IPMC_1m, MEM_BLOCK_ALL, ipmc_id, &entry_1);
    610         return (rv);
    611     } else
    612 #endif
    613     {
    614         rv = soc_mem_write(unit, L3_IPMCm, MEM_BLOCK_ALL, ipmc_id, &entry);
    615     }
    616 
    617     return (rv);
    618 }
    619 
    620 /*
    621  * Function:
    622  *      _tr_ipmc_enable
    623  * Purpose:
    624  *      Enable/disable IPMC support.
    625  * Parameters:
    626  *      unit - StrataSwitch PCI device unit number (driver internal).
    627  *      enable - TRUE: enable IPMC support.
    628  *               FALSE: disable IPMC support.
    629  * Returns:
    630  *      BCM_E_XXX
    631  */
    632 
    633 STATIC int
    634 _tr_ipmc_enable(int unit, int enable)
    635 {
    636     int        port, do_vlan;
    637     bcm_pbmp_t port_pbmp;
    638     soc_field_t flds[3] = {V4IPMC_ENABLEf, V6IPMC_ENABLEf, IPMC_DO_VLANf};
    639     uint32      vals[3];
    640 
    641     enable = enable ? 1 : 0;
    642     do_vlan = soc_property_get(unit, spn_IPMC_DO_VLAN, 1);
    643 
    644     BCM_PBMP_CLEAR(port_pbmp);
    645     BCM_PBMP_ASSIGN(port_pbmp, PBMP_PORT_ALL(unit));
    646     
    647 #ifdef BCM_KATANA2_SUPPORT
    648     if (SOC_IS_KATANA2(unit) && soc_feature(unit, soc_feature_flex_port)) {
    649         BCM_IF_ERROR_RETURN(_bcm_kt2_flexio_pbmp_update(unit, &port_pbmp));
    650     }
    651     if (soc_feature(unit, soc_feature_linkphy_coe) ||
    652         soc_feature(unit, soc_feature_subtag_coe)) {
    653         _bcm_kt2_subport_pbmp_update(unit, &port_pbmp);
    654     }
    655 #endif
    656 
    657     vals[0] = vals[1] = enable;
    658     vals[2] = (enable && do_vlan) ? 1 : 0;
    659 
    660     PBMP_ITER(port_pbmp, port) {
    661         int rv = BCM_E_NONE;
    662         PORT_LOCK(unit);
    663         rv = _bcm_esw_port_tab_multi_set(unit, port, _BCM_CPU_TABS_BOTH, 3,
    664                                          flds, vals);
    665         PORT_UNLOCK(unit);
    666         if (BCM_FAILURE(rv)) {
    667             return rv;
    668         }
    669     }
    670 
    671 #if defined(BCM_TRX_SUPPORT)
    672     if (soc_feature(unit, soc_feature_lport_tab_profile)) {
    673         /* Update LPORT Profile Table */
    674         BCM_IF_ERROR_RETURN(
    675             _bcm_lport_profile_fields32_modify(unit, LPORT_PROFILE_LPORT_TAB,
    676                                                3, flds, vals));
    677     }
    678 #endif /* BCM_TRX_SUPPORT */
    679 
    680     return BCM_E_NONE;
    681 }
    682 
    683 /*
    684  * Function:
    685  *      bcm_tr_ipmc_init
    686  * Purpose:
    687  *      Initialize the IPMC module and enable IPMC support.
    688  * Parameters:
    689  *      unit - StrataSwitch PCI device unit number (driver internal).
    690  * Returns:
    691  *      BCM_E_XXX
    692  * Notes:
    693  *      This function has to be called before any other IPMC functions.
    694  */
    695 
    696 int
    697 bcm_tr_ipmc_init(int unit)
    698 {
    699     _bcm_esw_ipmc_t  *info = IPMC_INFO(unit);
    700     int rv = BCM_E_NONE;
    701 #if defined(BCM_TRIUMPH2_SUPPORT)
    702     int i;
    703 #endif /*BCM_TRIUMPH2_SUPPORT*/
    704 
    705     BCM_IF_ERROR_RETURN(bcm_tr_ipmc_detach(unit));
    706     BCM_IF_ERROR_RETURN(_tr_ipmc_enable(unit, TRUE));
    707 
    708     IPMC_GROUP_NUM(unit) = soc_mem_index_count(unit, L3_IPMCm);
    709 #if defined(BCM_TRIUMPH3_SUPPORT)
    710     if (soc_feature(unit, soc_feature_static_repl_head_alloc)) {
    711         soc_info_t *si;
    712         int member_count;
    713         int port, phy_port, mmu_port;
    714 
    715         /* Each replication group is statically allocated a region
    716          * in REPL_HEAD table. The size of the region depends on the
    717          * maximum number of valid ports. Thus, the max number of
    718          * replication groups is limited to number of REPL_HEAD entries
    719          * divided by the max number of valid ports.
    720          */
    721         si = &SOC_INFO(unit);
    722         member_count = 0;
    723         PBMP_ITER(SOC_CONTROL(unit)->repl_eligible_pbmp, port) {
    724             phy_port = si->port_l2p_mapping[port];
    725             mmu_port = si->port_p2m_mapping[phy_port];
    726             if ((mmu_port == 57) || (mmu_port == 59) || (mmu_port == 61) || (mmu_port == 62)) {
    727                 /* No replication on MMU ports 57, 59, 61 and 62 */
    728                 continue;
    729             }
    730             member_count++;
    731         }
    732         if (member_count > 0) {
    733             IPMC_GROUP_NUM(unit) =
    734                 soc_mem_index_count(unit, MMU_REPL_HEAD_TBLm) / member_count;
    735             if (IPMC_GROUP_NUM(unit) > soc_mem_index_count(unit, L3_IPMCm)) {
    736                 IPMC_GROUP_NUM(unit) = soc_mem_index_count(unit, L3_IPMCm);
    737             }
    738         }
    739     }
    740 #endif /* BCM_TRIUMPH3_SUPPORT */
    741 
    742 #ifdef BCM_BRADLEY_SUPPORT
    743     if(!SOC_IS_MONTEREY(unit)) {
    744         if (SOC_REG_FIELD_VALID(unit, MC_CONTROL_5r, SHARED_TABLE_IPMC_SIZEf)) {
    745             int ipmc_base, ipmc_size;
    746 
    747             SOC_IF_ERROR_RETURN
    748                 (soc_hbx_ipmc_size_get(unit, &ipmc_base, &ipmc_size));
    749 
    750             if (IPMC_GROUP_NUM(unit) > ipmc_size) {
    751                 /* Reduce to fix allocated table space */
    752                 IPMC_GROUP_NUM(unit) = ipmc_size;
    753             }
    754         }
    755     }
    756 #endif
    757 
    758     info->ipmc_count = 0;
    759 
    760     info->ipmc_group_info =
    761         sal_alloc(IPMC_GROUP_NUM(unit) * sizeof(_bcm_esw_ipmc_group_info_t),
    762                   "IPMC group info");
    763     if (info->ipmc_group_info == NULL) {
    764         return (BCM_E_MEMORY);
    765     }
    766     sal_memset(info->ipmc_group_info, 0, 
    767                IPMC_GROUP_NUM(unit) * sizeof(_bcm_esw_ipmc_group_info_t));
    768 
    769 #ifdef BCM_TRIDENT2_SUPPORT
    770     if(soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) && 
    771             soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) {
    772         
    773         rv = soc_reg_field32_modify(unit, ING_CONFIG_64r,
    774                 REG_PORT_ANY, L2MC_LOOKUP_USE_BROADCAST_DOMAINf, 1);
    775         if (BCM_FAILURE(rv)) {
    776             sal_free(info->ipmc_group_info);
    777             info->ipmc_group_info = NULL;
    778             return rv;
    779         }
    780     }
    781     if (soc_feature(unit, soc_feature_pim_bidir)) {
    782         rv = bcm_td2_ipmc_pim_bidir_init(unit);
    783         if (BCM_FAILURE(rv)) {
    784             sal_free(info->ipmc_group_info);
    785             info->ipmc_group_info = NULL;
    786             return rv;
    787         }
    788     }
    789 #endif /* BCM_TRIDENT2_SUPPORT */
    790 
    791     /* Program the table IPMC_GROUP_NUM = index_count(L3_IPMCm) 
    792      * index_count of L3_IPMCm, L3_IPMC_REMAPm, EGR_IPMCm are the same
    793      */
    794 #if defined(BCM_TRIUMPH2_SUPPORT)
    795     if (SOC_MEM_IS_VALID(unit, L3_IPMC_REMAPm)) {
    796         int size;
    797         ipmc_remap_entry_t *ipmc_remap_entry;
    798         uint8 *mbuf;
    799 
    800         size = SOC_MEM_TABLE_BYTES(unit, L3_IPMC_REMAPm);
    801         mbuf = soc_cm_salloc(unit, size, "L3_IPMC_REMAP");
    802         if (NULL == mbuf) {
    803             return BCM_E_MEMORY;
    804         }
    805         sal_memset(mbuf, 0, size);
    806         for (i = 0; i < IPMC_GROUP_NUM(unit); i++) {
    807             ipmc_remap_entry = soc_mem_table_idx_to_pointer(unit, L3_IPMC_REMAPm, 
    808                                         ipmc_remap_entry_t *, mbuf, i);
    809             soc_L3_IPMC_REMAPm_field32_set(unit, ipmc_remap_entry, L3MC_INDEXf, i);
    810         }
    811         rv = soc_mem_write_range(unit, L3_IPMC_REMAPm, MEM_BLOCK_ANY,
    812                                  soc_mem_index_min(unit, L3_IPMC_REMAPm),
    813                                  soc_mem_index_max(unit, L3_IPMC_REMAPm),
    814                                  mbuf);
    815         soc_cm_sfree(unit, mbuf);
    816         if (rv < 0) {
    817             sal_free(info->ipmc_group_info);
    818             info->ipmc_group_info = NULL;
    819             return rv;
    820         }
    821     }
    822 #endif
    823     if (SOC_MEM_IS_VALID(unit, EGR_IPMCm)) {
    824         /* Initialize EGR_IPMC entries need to have:
    825          * { L3_PAYLOAD == 0,  REPLICATION_TYPE == 0, DONT_PRUNE_VLAN == 0 } 
    826          * Just same to clear it.
    827          */
    828         rv = soc_mem_clear(unit, EGR_IPMCm, MEM_BLOCK_ANY, TRUE);
    829         if (rv < 0) {
    830             sal_free(info->ipmc_group_info);
    831             info->ipmc_group_info = NULL;
    832             return rv;
    833         }
    834     }
    835 
    836     info->ipmc_initialized = TRUE;
    837     return BCM_E_NONE;
    838 }
    839 
    840 /*
    841  * Function:
    842  *      bcm_tr_ipmc_detach
    843  * Purpose:
    844  *      Detach the IPMC module.
    845  * Parameters:
    846  *      unit - StrataSwitch PCI device unit number (driver internal).
    847  * Returns:
    848  *      BCM_E_XXX
    849  */
    850 
    851 int
    852 bcm_tr_ipmc_detach(int unit)
    853 {
    854     _bcm_esw_ipmc_t    *info = IPMC_INFO(unit);
    855     _bcm_esw_ipmc_l3entry_t *ipmc_l3entry; 
    856     int i, rv;
    857 
    858     if (info->ipmc_initialized) {
    859         /* Delete all IPMC entries. BCM_E_NOT_FOUND may be
    860          * returned by bcm_tr_ipmc_delete_all since L3 module
    861          * clears L3 tables during initialization.
    862          */
    863         rv = bcm_tr_ipmc_delete_all(unit);
    864         if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) {
    865             return rv;
    866         }
    867 
    868         if (!SOC_WARM_BOOT(unit)) {
    869             BCM_IF_ERROR_RETURN(_tr_ipmc_enable(unit, FALSE));
    870         }
    871 
    872         if (info->ipmc_group_info != NULL) {
    873             for (i = 0; i < IPMC_GROUP_NUM(unit); i++) {
    874                 ipmc_l3entry = IPMC_GROUP_INFO(unit, i)->l3entry_list;
    875                 while (ipmc_l3entry != NULL) {
    876                     IPMC_GROUP_INFO(unit, i)->l3entry_list = ipmc_l3entry->next;
    877                     sal_free(ipmc_l3entry);
    878                     ipmc_l3entry = IPMC_GROUP_INFO(unit, i)->l3entry_list;
    879                 }
    880             }
    881             sal_free(info->ipmc_group_info);
    882             info->ipmc_group_info = NULL;
    883         }
    884 
    885 #ifdef BCM_TRIDENT2_SUPPORT
    886         if (soc_feature(unit, soc_feature_pim_bidir)) {
    887             BCM_IF_ERROR_RETURN(bcm_td2_ipmc_pim_bidir_detach(unit));
    888         }
    889 #endif /* BCM_TRIDENT2_SUPPORT */
    890 
    891         info->ipmc_initialized = FALSE;
    892     }
    893 
    894     return BCM_E_NONE;
    895 }
    896 
    897 /*
    898  * Function:
    899  *      bcm_tr_ipmc_get
    900  * Purpose:
    901  *      Get an IPMC entry by index.
    902  * Parameters:
    903  *      unit - StrataSwitch PCI device unit number (driver internal).
    904  *      index - The index number.
    905  *      ipmc - (OUT) IPMC entry information.
    906  * Returns:
    907  *      BCM_E_XXX
    908  */
    909 
    910 int
    911 bcm_tr_ipmc_get(int unit, int index, bcm_ipmc_addr_t *ipmc)
    912 {
    913     ipmc_entry_t        ipmc_entry;
    914 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT)
    915     ipmc_1_entry_t      ipmc_1_entry;
    916 #endif
    917 
    918     IPMC_INIT(unit);
    919     IPMC_ID(unit, index);
    920 
    921     if (IPMC_USED_ISSET(unit, index)) {
    922         BCM_IF_ERROR_RETURN
    923             (soc_mem_read(unit, L3_IPMCm, MEM_BLOCK_ANY, index, &ipmc_entry));
    924 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT)
    925         if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) {
    926             BCM_IF_ERROR_RETURN
    927                 (soc_mem_read(unit, L3_IPMC_1m, MEM_BLOCK_ANY, index, 
    928                               &ipmc_1_entry));
    929             BCM_IF_ERROR_RETURN
    930                 (_tr2_ipmc_glp_get(unit, ipmc, &ipmc_1_entry));
    931         }
    932 #endif
    933 #ifdef BCM_TOMAHAWK_SUPPORT
    934         if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
    935             BCM_IF_ERROR_RETURN
    936                 (_th_ipmc_info_get(unit, index, ipmc, &ipmc_entry, NULL));
    937         } else
    938 #endif /* BCM_TOMAHAWK_SUPPORT */
    939         {
    940             BCM_IF_ERROR_RETURN
    941                 (_tr_ipmc_info_get(unit, index, ipmc, &ipmc_entry, 1, NULL));
    942         }
    943 
    944         ipmc->group = index;
    945 
    946         return BCM_E_NONE;
    947     } 
    948 
    949     return BCM_E_NOT_FOUND;
    950 }
    951 
    952 /*
    953  * Function:
    954  *      _bcm_tr_ipmc_find
    955  * Purpose:
    956  *      Search an IPMC entry by sip, mcip and vid
    957  * Parameters:
    958  *      unit - StrataSwitch PCI device unit number (driver internal).
    959  *      ipmc - (IN) IPMC entry information.
    960  *      l3cfg - (OUT) L3 entry information..
    961  * Returns:
    962  *      BCM_E_XXX
    963  */
    964 
    965 STATIC int
    966 _bcm_tr_ipmc_find(int unit, bcm_ipmc_addr_t *ipmc, _bcm_l3_cfg_t *l3cfg)
    967 {
    968     sal_memset(l3cfg, 0, sizeof(_bcm_l3_cfg_t));
    969 
    970     l3cfg->l3c_vid = ipmc->vid;
    971     l3cfg->l3c_flags = BCM_L3_IPMC;
    972     l3cfg->l3c_vrf = ipmc->vrf;
    973     l3cfg->l3c_ing_intf = ipmc->ing_intf;
    974     if (ipmc->flags & BCM_IPMC_HIT_CLEAR) {
    975         l3cfg->l3c_flags |= BCM_L3_HIT_CLEAR;
    976     } 
    977     if (ipmc->flags & BCM_IPMC_L2) {
    978         l3cfg->l3c_flags |= BCM_L3_L2ONLY;
    979     }
    980 #ifdef BCM_TRIDENT3_SUPPORT
    981     if (soc_feature(unit, soc_feature_flex_flow)) {
    982         l3cfg->l3c_rp_id = BCM_IPMC_RP_ID_INVALID;
    983         l3cfg->l3c_flow_handle = ipmc->flow_handle;
    984         l3cfg->l3c_flow_option_handle = ipmc->flow_option_handle;
    985         l3cfg->l3c_num_of_fields = ipmc->num_logical_fields;
    986         sal_memcpy(l3cfg->l3c_logical_fields, ipmc->logical_fields,
    987                    ipmc->num_logical_fields*sizeof(bcm_flow_logical_field_t));
    988     }
    989 #endif /* BCM_TRIDENT3_SUPPORT */
    990     if (ipmc->flags & BCM_IPMC_IP6) {
    991         sal_memcpy(l3cfg->l3c_sip6, ipmc->s_ip6_addr, BCM_IP6_ADDRLEN);
    992         sal_memcpy(l3cfg->l3c_ip6, ipmc->mc_ip6_addr, BCM_IP6_ADDRLEN);
    993         l3cfg->l3c_flags |= BCM_L3_IP6;
    994         BCM_IF_ERROR_RETURN(
    995             mbcm_driver[unit]->mbcm_l3_ip6_get(unit, l3cfg));
    996     } else {
    997         l3cfg->l3c_src_ip_addr = ipmc->s_ip_addr;
    998         l3cfg->l3c_ipmc_group = ipmc->mc_ip_addr;
    999         BCM_IF_ERROR_RETURN(
   1000             mbcm_driver[unit]->mbcm_l3_ip4_get(unit, l3cfg));
   1001     }
   1002 
   1003     return BCM_E_NONE;
   1004 }
   1005 
   1006 /*
   1007  * Function:
   1008  *      bcm_tr_ipmc_lookup
   1009  * Purpose:
   1010  *      Look up an IPMC entry by sip, mcip and vid
   1011  * Parameters:
   1012  *      unit - StrataSwitch PCI device unit number (driver internal).
   1013  *      index - (OUT) The index number.
   1014  *      ipmc - (IN, OUT) IPMC entry information.
   1015  * Returns:
   1016  *      BCM_E_XXX
   1017  */
   1018 
   1019 int
   1020 bcm_tr_ipmc_lookup(int unit, int *index, bcm_ipmc_addr_t *ipmc)
   1021 {
   1022     ipmc_entry_t   ipmc_entry;
   1023 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT)
   1024     ipmc_1_entry_t ipmc_1_entry;
   1025 #endif
   1026     _bcm_l3_cfg_t  l3cfg;
   1027     int            ipmc_id;
   1028 
   1029     IPMC_INIT(unit);
   1030 
   1031     BCM_IF_ERROR_RETURN(
   1032         _bcm_tr_ipmc_find(unit, ipmc, &l3cfg));
   1033 
   1034     ipmc_id = l3cfg.l3c_ipmc_ptr;
   1035     BCM_IF_ERROR_RETURN
   1036         (soc_mem_read(unit, L3_IPMCm, MEM_BLOCK_ANY, ipmc_id, &ipmc_entry));
   1037 
   1038 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT)
   1039     if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) {
   1040         BCM_IF_ERROR_RETURN
   1041             (soc_mem_read(unit, L3_IPMC_1m, MEM_BLOCK_ANY, ipmc_id,
   1042                           &ipmc_1_entry));
   1043         BCM_IF_ERROR_RETURN
   1044             (_tr2_ipmc_glp_get(unit, ipmc, &ipmc_1_entry));
   1045     }
   1046 #endif
   1047 
   1048 #ifdef BCM_TOMAHAWK_SUPPORT
   1049         if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
   1050             ipmc->v = soc_L3_IPMCm_field32_get(unit, &ipmc_entry, VALIDf);            
   1051             BCM_IF_ERROR_RETURN
   1052                 (_th_ipmc_glp_get(unit, ipmc, &l3cfg));
   1053         } else
   1054 #endif /* BCM_TOMAHAWK_SUPPORT */
   1055         {
   1056             BCM_IF_ERROR_RETURN
   1057                 (_tr_ipmc_info_get(unit, ipmc_id, ipmc, &ipmc_entry, 0, NULL));
   1058         }
   1059 
   1060     if (ipmc->v) {
   1061         ipmc->group = ipmc_id;
   1062         ipmc->group_l2 = l3cfg.l3c_ipmc_ptr_l2;
   1063         ipmc->lookup_class = l3cfg.l3c_lookup_class;
   1064         ipmc->rp_id = l3cfg.l3c_rp_id;
   1065         ipmc->ing_intf = l3cfg.l3c_ing_intf;
   1066         ipmc->vid = l3cfg.l3c_vid;
   1067         if (l3cfg.l3c_flags & BCM_L3_HIT) {
   1068             ipmc->flags |= BCM_IPMC_HIT;
   1069         }
   1070         if (l3cfg.l3c_flags & BCM_L3_RPE) {
   1071             ipmc->cos =  l3cfg.l3c_prio;
   1072             ipmc->flags |= BCM_IPMC_SETPRI;
   1073         } else {
   1074             ipmc->cos = -1;
   1075             ipmc->flags &= ~BCM_IPMC_SETPRI;
   1076         }
   1077         if (l3cfg.l3c_flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) {
   1078             ipmc->flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK;
   1079             ipmc->l3a_intf = l3cfg.l3c_intf;
   1080             if (l3cfg.l3c_flags & BCM_IPMC_RPF_FAIL_DROP) {
   1081                 ipmc->flags |= BCM_IPMC_RPF_FAIL_DROP;
   1082             }
   1083             if (l3cfg.l3c_flags & BCM_IPMC_RPF_FAIL_DROP) {
   1084                 ipmc->flags |= BCM_IPMC_RPF_FAIL_TOCPU;
   1085             }
   1086         }
   1087 #ifdef BCM_MONTEREY_SUPPORT
   1088         if (l3cfg.l3c_flags2 & BCM_L3_FLAGS2_DECAP_ROE_HEADER) {
   1089             ipmc->flags |= BCM_IPMC_DECAP_ROE_HEADER;
   1090         }
   1091 #endif
   1092     }    
   1093     if (index != NULL) {
   1094         *index = ipmc_id;
   1095     }
   1096 
   1097     return BCM_E_NONE;
   1098 }
   1099 
   1100 /*
   1101  * Function:
   1102  *      _bcm_tr_ipmc_add
   1103  * Purpose:
   1104  *      Add a new entry to the L3 table.
   1105  * Parameters:
   1106  *      unit - (IN) BCM device number.
   1107  *      ipmc - (IN) IPMC entry information.
   1108  * Returns:
   1109  *      BCM_E_XXX
   1110  */
   1111 
   1112 STATIC int
   1113 _bcm_tr_ipmc_add(int unit, bcm_ipmc_addr_t *ipmc)
   1114 {
   1115     _bcm_l3_cfg_t       l3cfg; /* L3 ipmc entry.           */
   1116     int                 rv;    /* Operation return status. */
   1117 
   1118     sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   1119 
   1120     l3cfg.l3c_vid = ipmc->vid;
   1121     l3cfg.l3c_flags = BCM_L3_IPMC;
   1122     l3cfg.l3c_vrf = ipmc->vrf;
   1123     l3cfg.l3c_lookup_class = ipmc->lookup_class;
   1124     l3cfg.l3c_modid = ipmc->mod_id;
   1125     l3cfg.l3c_port_tgid = ipmc->port_tgid;
   1126     l3cfg.l3c_tunnel = ipmc->ts;
   1127 
   1128     if (ipmc->flags & BCM_IPMC_SETPRI) {
   1129         l3cfg.l3c_flags |= BCM_L3_RPE;
   1130         l3cfg.l3c_prio = ipmc->cos;
   1131     }
   1132     /* Dont set hit bits if user says so */
   1133     if (ipmc->flags & BCM_IPMC_HIT_CLEAR) {
   1134         l3cfg.l3c_flags |= BCM_L3_HIT_CLEAR;
   1135     } else {
   1136         l3cfg.l3c_flags |=  BCM_L3_HIT;
   1137     }   
   1138     if (ipmc->flags & BCM_IPMC_IP6) {
   1139         if (!BCM_IP6_MULTICAST(ipmc->mc_ip6_addr)) {
   1140             return BCM_E_PARAM;
   1141         }
   1142         sal_memcpy(l3cfg.l3c_sip6, ipmc->s_ip6_addr, BCM_IP6_ADDRLEN);
   1143         sal_memcpy(l3cfg.l3c_ip6, ipmc->mc_ip6_addr, BCM_IP6_ADDRLEN);
   1144         l3cfg.l3c_flags |= BCM_L3_IP6;
   1145     } else {
   1146         if (!BCM_IP4_MULTICAST(ipmc->mc_ip_addr)) {
   1147             return BCM_E_PARAM;
   1148         }
   1149         l3cfg.l3c_src_ip_addr = ipmc->s_ip_addr;
   1150         l3cfg.l3c_ipmc_group = ipmc->mc_ip_addr;
   1151     }
   1152 
   1153     l3cfg.l3c_ipmc_ptr = ipmc->group;
   1154     l3cfg.l3c_ipmc_ptr_l2 = ipmc->group_l2;
   1155     l3cfg.l3c_vid = ipmc->vid;
   1156     l3cfg.l3c_rp_id = ipmc->rp_id;
   1157     l3cfg.l3c_ing_intf = ipmc->ing_intf;
   1158     if (ipmc->flags & BCM_IPMC_L2) {
   1159         l3cfg.l3c_flags |= BCM_L3_L2ONLY;
   1160     }
   1161     if (ipmc->flags & BCM_IPMC_REPLACE) {
   1162         l3cfg.l3c_flags |= BCM_L3_REPLACE;
   1163     }
   1164 
   1165     if (ipmc->flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) {
   1166         l3cfg.l3c_intf   = ipmc->l3a_intf;
   1167         l3cfg.l3c_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK;
   1168         if (ipmc->flags & BCM_IPMC_RPF_FAIL_DROP) {
   1169             l3cfg.l3c_flags |= BCM_IPMC_RPF_FAIL_DROP;
   1170         }
   1171         if (ipmc->flags & BCM_IPMC_RPF_FAIL_TOCPU) {
   1172             l3cfg.l3c_flags |= BCM_IPMC_RPF_FAIL_TOCPU;
   1173         }
   1174     }
   1175 
   1176     if (ipmc->flags & BCM_IPMC_SOURCE_PORT_NOCHECK) {
   1177         l3cfg.l3c_flags |= BCM_IPMC_SOURCE_PORT_NOCHECK;
   1178     }
   1179 
   1180 #ifdef BCM_TOMAHAWK_SUPPORT
   1181     if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
   1182         BCM_IF_ERROR_RETURN
   1183             (_th_ipmc_glp_set(unit, ipmc, &l3cfg));
   1184     }
   1185 #endif
   1186     /* Write mcast entry to hw. */
   1187     l3cfg.l3c_hw_index = BCM_XGS3_L3_INVALID_INDEX;/* Add /No overrite. */
   1188 
   1189 #ifdef BCM_MONTEREY_SUPPORT
   1190     if (ipmc->flags & BCM_IPMC_DECAP_ROE_HEADER) {
   1191         l3cfg.l3c_flags2 |= BCM_L3_FLAGS2_DECAP_ROE_HEADER;
   1192     }
   1193 #endif
   1194 
   1195 #ifdef BCM_TRIDENT3_SUPPORT
   1196     if (soc_feature(unit, soc_feature_flex_flow)) {
   1197         l3cfg.l3c_flow_handle = ipmc->flow_handle;
   1198         l3cfg.l3c_flow_option_handle = ipmc->flow_option_handle;
   1199         l3cfg.l3c_num_of_fields = ipmc->num_logical_fields;
   1200         sal_memcpy(l3cfg.l3c_logical_fields, ipmc->logical_fields,
   1201                    ipmc->num_logical_fields*sizeof(bcm_flow_logical_field_t));
   1202     }
   1203 #endif /* BCM_TRIDENT3_SUPPORT */
   1204 
   1205     if (ipmc->flags & BCM_IPMC_IP6) {
   1206         rv = mbcm_driver[unit]->mbcm_l3_ip6_add(unit, &l3cfg);
   1207     } else {
   1208         rv = mbcm_driver[unit]->mbcm_l3_ip4_add(unit, &l3cfg);
   1209     }
   1210 
   1211     if (BCM_SUCCESS(rv)) {
   1212         rv = _bcm_tr_ipmc_l3entry_list_add(unit, ipmc->group, 
   1213                                            &l3cfg); 
   1214     }
   1215     
   1216     return (rv);
   1217 }
   1218 
   1219 /*
   1220  * Function:
   1221  *      _bcm_tr_ipmc_del
   1222  * Purpose:
   1223  *      Remove an  entry from the L3 table.
   1224  * Parameters:
   1225  *      unit - (IN) BCM device number.
   1226  *      ipmc - (IN)IPMC entry information.
   1227  *      modify_l3entry_list - (IN) Controls whether to modify IPMC group's
   1228  *                                 L3 entry list.
   1229  * Returns:
   1230  *      BCM_E_XXX
   1231  */
   1232 
   1233 STATIC int
   1234 _bcm_tr_ipmc_del(int unit, bcm_ipmc_addr_t *ipmc, int modify_l3entry_list)
   1235 {
   1236     _bcm_l3_cfg_t       l3cfg; /* L3 ipmc entry.           */
   1237     int                 rv;    /* Operation return status. */
   1238     int                 ipmc_index = 0;
   1239 
   1240     sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   1241 
   1242     l3cfg.l3c_vid = ipmc->vid;
   1243     l3cfg.l3c_flags = BCM_L3_IPMC;
   1244     l3cfg.l3c_vrf = ipmc->vrf;
   1245     l3cfg.l3c_vid = ipmc->vid;
   1246     l3cfg.l3c_ing_intf = ipmc->ing_intf;
   1247     if (ipmc->flags & BCM_IPMC_L2) {
   1248         l3cfg.l3c_flags |= BCM_L3_L2ONLY;
   1249     }
   1250     if (ipmc->flags & BCM_IPMC_IP6) {
   1251         if (!BCM_IP6_MULTICAST(ipmc->mc_ip6_addr)) {
   1252             return BCM_E_PARAM;
   1253         }
   1254         sal_memcpy(l3cfg.l3c_sip6, ipmc->s_ip6_addr, BCM_IP6_ADDRLEN);
   1255         sal_memcpy(l3cfg.l3c_ip6, ipmc->mc_ip6_addr, BCM_IP6_ADDRLEN);
   1256         l3cfg.l3c_flags |= BCM_L3_IP6;
   1257     } else {
   1258         if (!BCM_IP4_MULTICAST(ipmc->mc_ip_addr)) {
   1259             return BCM_E_PARAM;
   1260         }
   1261         l3cfg.l3c_src_ip_addr = ipmc->s_ip_addr;
   1262         l3cfg.l3c_ipmc_group = ipmc->mc_ip_addr;
   1263     }
   1264 #ifdef BCM_TRIDENT3_SUPPORT
   1265     if (soc_feature(unit, soc_feature_flex_flow)) {
   1266         l3cfg.l3c_rp_id = BCM_IPMC_RP_ID_INVALID;
   1267         l3cfg.l3c_flow_handle = ipmc->flow_handle;
   1268         l3cfg.l3c_flow_option_handle = ipmc->flow_option_handle;
   1269         l3cfg.l3c_num_of_fields = ipmc->num_logical_fields;
   1270         sal_memcpy(l3cfg.l3c_logical_fields, ipmc->logical_fields,
   1271                    ipmc->num_logical_fields*sizeof(bcm_flow_logical_field_t));
   1272     }
   1273 #endif /* BCM_TRIDENT3_SUPPORT */
   1274     if (ipmc->flags & BCM_IPMC_IP6) {
   1275         rv = mbcm_driver[unit]->mbcm_l3_ip6_get(unit, &l3cfg);
   1276         if (BCM_SUCCESS(rv)) {
   1277             ipmc_index = l3cfg.l3c_ipmc_ptr;
   1278             rv = mbcm_driver[unit]->mbcm_l3_ip6_delete(unit, &l3cfg);
   1279         }
   1280     } else {
   1281         rv = mbcm_driver[unit]->mbcm_l3_ip4_get(unit, &l3cfg);
   1282         if (BCM_SUCCESS(rv)) {
   1283             ipmc_index = l3cfg.l3c_ipmc_ptr;
   1284             rv = mbcm_driver[unit]->mbcm_l3_ip4_delete(unit, &l3cfg);
   1285         }
   1286     }
   1287 
   1288     if (BCM_SUCCESS(rv) && modify_l3entry_list) {
   1289         rv = _bcm_tr_ipmc_l3entry_list_del(unit, ipmc_index, &l3cfg); 
   1290     }
   1291 
   1292     return (rv);
   1293 }
   1294 
   1295 /*
   1296  * Function:
   1297  *      _bcm_tr_ipmc_replace
   1298  * Purpose:
   1299  *      Overwrite an entry in the IPMC table.
   1300  * Parameters:
   1301  *      unit - StrataSwitch PCI device unit number (driver internal).
   1302  *      ipmc - New IPMC entry information.
   1303  *      old_l3cfg - Old IPMC configuration information.
   1304  * Returns:
   1305  *      BCM_E_XXX
   1306  */
   1307 STATIC int
   1308 _bcm_tr_ipmc_replace(int unit, bcm_ipmc_addr_t *ipmc, _bcm_l3_cfg_t *old_l3cfg)
   1309 {
   1310     _bcm_l3_cfg_t l3cfg;
   1311     int old_ipmc_index;
   1312     int rv = BCM_E_NONE;
   1313     int flex_fields_replace = 0;
   1314 
   1315     l3cfg = *old_l3cfg;
   1316     old_ipmc_index = l3cfg.l3c_ipmc_ptr;
   1317 
   1318     if (!(ipmc->flags & BCM_IPMC_SETPRI)) {
   1319         l3cfg.l3c_flags &= ~BCM_L3_RPE;
   1320         l3cfg.l3c_prio = 0;
   1321     } else {
   1322         l3cfg.l3c_flags |= BCM_L3_RPE;
   1323         l3cfg.l3c_prio = ipmc->cos;
   1324     }
   1325     if (ipmc->flags & BCM_IPMC_HIT_CLEAR) {
   1326         l3cfg.l3c_flags &= ~BCM_L3_HIT;
   1327     }
   1328     l3cfg.l3c_lookup_class = ipmc->lookup_class;
   1329     l3cfg.l3c_ipmc_ptr = ipmc->group;
   1330     l3cfg.l3c_ipmc_ptr_l2 = ipmc->group_l2;
   1331     l3cfg.l3c_rp_id = ipmc->rp_id;
   1332 
   1333     if (ipmc->flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) {
   1334         l3cfg.l3c_intf = ipmc->l3a_intf;
   1335         l3cfg.l3c_flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK;
   1336         if (ipmc->flags & BCM_IPMC_RPF_FAIL_DROP) {
   1337             l3cfg.l3c_flags |= BCM_IPMC_RPF_FAIL_DROP;
   1338         }
   1339         if (ipmc->flags & BCM_IPMC_RPF_FAIL_TOCPU) {
   1340             l3cfg.l3c_flags |= BCM_IPMC_RPF_FAIL_TOCPU;
   1341         }
   1342     } 
   1343 
   1344 #ifdef BCM_TOMAHAWK_SUPPORT
   1345     if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
   1346         if (!(ipmc->flags & BCM_IPMC_SOURCE_PORT_NOCHECK)) {  
   1347             l3cfg.l3c_flags &= ~BCM_IPMC_SOURCE_PORT_NOCHECK;
   1348         }
   1349         BCM_IF_ERROR_RETURN
   1350             (_th_ipmc_glp_set(unit, ipmc, &l3cfg));
   1351     }
   1352 #endif
   1353 
   1354 #ifdef BCM_TRIDENT3_SUPPORT
   1355     if (soc_feature(unit, soc_feature_flex_flow) &&
   1356         (ipmc->flow_handle != 0)) {
   1357         if (ipmc->flags & BCM_IPMC_REPLACE) {
   1358             l3cfg.l3c_flags |= BCM_L3_REPLACE;
   1359         }
   1360         if ((l3cfg.l3c_flow_handle != ipmc->flow_handle) ||
   1361             (l3cfg.l3c_flow_option_handle != ipmc->flow_option_handle) ||
   1362             (l3cfg.l3c_num_of_fields != ipmc->num_logical_fields) ||
   1363             (!sal_memcmp(l3cfg.l3c_logical_fields, ipmc->logical_fields,
   1364                          ipmc->num_logical_fields*sizeof(bcm_flow_logical_field_t)))) {
   1365             flex_fields_replace = 1;
   1366         }
   1367     }
   1368 #endif
   1369     BCM_IF_ERROR_RETURN
   1370         (bcm_xgs3_l3_replace(unit, &l3cfg));
   1371 
   1372     if ((old_ipmc_index != ipmc->group) || flex_fields_replace) {
   1373         rv = _bcm_tr_ipmc_l3entry_list_del(unit, old_ipmc_index, &l3cfg);
   1374         if (rv == BCM_E_NOT_FOUND) {
   1375             rv = _bcm_tr_ipmc_l3entry_list_add(unit, ipmc->group, &l3cfg);
   1376             return rv;
   1377         } else if (BCM_FAILURE(rv)) {
   1378             return rv;
   1379         }
   1380         rv = _bcm_tr_ipmc_l3entry_list_add(unit, ipmc->group, &l3cfg);
   1381         if (BCM_FAILURE(rv)) {
   1382             (void) _bcm_tr_ipmc_l3entry_list_add(unit, old_ipmc_index, &l3cfg);
   1383             return rv;
   1384         }
   1385     } else {
   1386         BCM_IF_ERROR_RETURN
   1387             (_bcm_tr_ipmc_l3entry_list_update(unit, old_ipmc_index, &l3cfg));
   1388     }
   1389 
   1390     return BCM_E_NONE;
   1391 }
   1392 
   1393 /*
   1394  * Function:
   1395  *      _bcm_tr_ipmc_src_port_compare
   1396  * Purpose:
   1397  *      Compare the IPMC source port parameters.
   1398  * Parameters:
   1399  *      unit - StrataSwitch PCI device unit number (driver internal).
   1400  *      ipmc_index - IPMC index to be shared.
   1401  *      ipmc - IPMC address entry info.
   1402  *      match - (OUT) Match indication.
   1403  * Returns:
   1404  *      BCM_E_XXX
   1405  */
   1406 STATIC int
   1407 _bcm_tr_ipmc_src_port_compare(int unit, int ipmc_index,
   1408         bcm_ipmc_addr_t *ipmc, int *match)
   1409 {
   1410     ipmc_entry_t entry;
   1411     ipmc_1_entry_t entry_1;
   1412     int no_src_check, is_trunk, tgid, mod, port;
   1413     int t_f, tgid_f, mod_f, port_f;
   1414     int modid_max = 0;
   1415 
   1416     if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) {
   1417         BCM_IF_ERROR_RETURN
   1418             (soc_mem_read(unit, L3_IPMC_1m, MEM_BLOCK_ANY, ipmc_index,
   1419                           &entry_1));
   1420     } else {
   1421         BCM_IF_ERROR_RETURN
   1422             (soc_mem_read(unit, L3_IPMCm, MEM_BLOCK_ANY, ipmc_index,
   1423                           &entry));
   1424     }
   1425 
   1426     no_src_check = FALSE;
   1427     is_trunk = 0;
   1428     tgid = -1;
   1429     mod = -1;
   1430     port = -1;
   1431     if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) {
   1432         t_f    = soc_L3_IPMC_1m_field32_get(unit, &entry_1, Tf);
   1433         tgid_f = soc_L3_IPMC_1m_field32_get(unit, &entry_1, TGIDf);
   1434         mod_f  = soc_L3_IPMC_1m_field32_get(unit, &entry_1, MODULE_IDf);
   1435         port_f = soc_L3_IPMC_1m_field32_get(unit, &entry_1, PORT_NUMf);
   1436     } else {
   1437         t_f    = soc_L3_IPMCm_field32_get(unit, &entry, Tf);
   1438         tgid_f = soc_L3_IPMCm_field32_get(unit, &entry, TGIDf);
   1439         mod_f  = soc_L3_IPMCm_field32_get(unit, &entry, MODULE_IDf);
   1440         port_f = soc_L3_IPMCm_field32_get(unit, &entry, PORT_NUMf);
   1441     }
   1442 #ifdef BCM_METROLITE_SUPPORT
   1443     if (SOC_IS_METROLITE(unit)) {
   1444         modid_max = SOC_MEM_FIELD32_VALUE_MAX(
   1445                                  unit, L3_IPMC_1m, MODULE_IDf);
   1446     }else
   1447 #endif
   1448     {
   1449         modid_max =  SOC_MODID_MAX(unit);
   1450     }
   1451 
   1452     if ((t_f == 1) && (mod_f == modid_max) &&
   1453             (port_f == TR_IPMC_NO_SRC_CHECK_PORT(unit))) {
   1454         no_src_check = TRUE;
   1455     } else if (t_f == 1) {
   1456         is_trunk = 1;
   1457         tgid = tgid_f;
   1458     } else {
   1459         mod = mod_f;
   1460         port = port_f;
   1461     }
   1462 
   1463     *match = FALSE;
   1464     if ((ipmc->flags & BCM_IPMC_SOURCE_PORT_NOCHECK) ||
   1465             (ipmc->port_tgid < 0)) {                        /* no source port */
   1466         if (no_src_check) {
   1467             *match = TRUE;
   1468         }
   1469     } else if (ipmc->ts) {                              /* trunk source port */
   1470         if (is_trunk && (tgid == ipmc->port_tgid)) {
   1471             *match = TRUE;
   1472         }
   1473     } else {                                            /* source port */
   1474         bcm_module_t    mod_in, mod_out;
   1475         bcm_port_t      port_in, port_out;
   1476 
   1477         mod_in = ipmc->mod_id;
   1478         port_in = ipmc->port_tgid;
   1479         BCM_IF_ERROR_RETURN
   1480             (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET,
   1481                                      mod_in, port_in,
   1482                                      &mod_out, &port_out));
   1483         /* Check parameters, since above is an application callback */
   1484         if (!SOC_MODID_ADDRESSABLE(unit, mod_out)) {
   1485             return BCM_E_BADID;
   1486         }
   1487         if (!SOC_PORT_ADDRESSABLE(unit, port_out)) {
   1488             return BCM_E_PORT;
   1489         }
   1490 
   1491         if ((mod == mod_out) && (port == port_out)) {
   1492             *match = TRUE;
   1493         }
   1494     }
   1495 
   1496     return BCM_E_NONE;
   1497 }
   1498 
   1499 /*
   1500  * Function:
   1501  *      _bcm_tr_ipmc_src_port_consistency_check
   1502  * Purpose:
   1503  *      When multiple IPMC address entries share the same IPMC
   1504  *      index, they must also have the same port parameter
   1505  *      for the purpose of IPMC source port checking. This
   1506  *      procedure makes sure this is the case.
   1507  * Parameters:
   1508  *      unit - StrataSwitch PCI device unit number (driver internal).
   1509  *      ipmc_index - IPMC index to be shared.
   1510  *      ipmc - IPMC address entry info.
   1511  *      already_used - Indicates if the given IPMC address entry is
   1512  *                     already using the ipmc index to be shared.
   1513  *      need_write - Indicates whether the the ipmc index to be shared 
   1514  *                     should be writen or not.
   1515  * Returns:
   1516  *      BCM_E_XXX
   1517  */
   1518 int
   1519 _bcm_tr_ipmc_src_port_consistency_check(int unit, int ipmc_index,
   1520         bcm_ipmc_addr_t *ipmc, int already_used, int *need_write)
   1521 {
   1522     int l3entry_list_size;
   1523     int match = 0;
   1524     int defip_ref_count;
   1525 
   1526     *need_write = TRUE;
   1527 
   1528     if (soc_feature(unit, soc_feature_src_port_consistency_check_skip)) {
   1529         /* Source port check for L3 Multicast has been moved in lookup table in Tomahawk,
   1530          * hence src port consistency check is not required as the device allows sharing an 
   1531          * ipmc index without doing src port check.
   1532          */
   1533         return BCM_E_NONE;
   1534     }
   1535 
   1536     BCM_IF_ERROR_RETURN(_bcm_tr_ipmc_l3entry_list_size_get(unit,
   1537                 ipmc_index, &l3entry_list_size));
   1538     defip_ref_count = IPMC_GROUP_INFO(unit, ipmc_index)->defip_ref_count;
   1539     if ((already_used && (l3entry_list_size > 1)) ||
   1540             (!already_used && (l3entry_list_size > 0)) ||
   1541             (defip_ref_count > 0)) {
   1542         /* If there are IPMC address entries other than the given IPMC address
   1543          * entry that are pointing the given ipmc index, verify that the IPMC
   1544          * source port check parameters are the same. If not, the ipmc index
   1545          * cannot be shared.
   1546          */
   1547 
   1548         BCM_IF_ERROR_RETURN(_bcm_tr_ipmc_src_port_compare(unit,
   1549                             ipmc_index, ipmc, &match));
   1550 
   1551         if (!match) {
   1552             return BCM_E_PARAM;
   1553         } 
   1554 
   1555         *need_write = FALSE;
   1556     }
   1557 
   1558     return BCM_E_NONE;
   1559 }
   1560 
   1561 /*
   1562  * Function:
   1563  *      bcm_tr_ipmc_add
   1564  * Purpose:
   1565  *      Add a new entry to the IPMC table.
   1566  * Parameters:
   1567  *      unit - StrataSwitch PCI device unit number (driver internal).
   1568  *      ipmc - IPMC entry information.
   1569  * Returns:
   1570  *      BCM_E_XXX
   1571  */
   1572 
   1573 int
   1574 bcm_tr_ipmc_add(int unit, bcm_ipmc_addr_t *ipmc)
   1575 {
   1576     _bcm_l3_cfg_t   l3cfg;
   1577     int             old_ipmc_index;
   1578     int new_entry, rv, need_write;
   1579 #ifdef BCM_TRIDENT2_SUPPORT
   1580     int             old_rp_id;
   1581 #endif /* BCM_TRIDENT2_SUPPORT */
   1582 
   1583     IPMC_INIT(unit);
   1584     IPMC_ID(unit, ipmc->group);
   1585 
   1586     /* To keep logic simple, group_l2 won't be validated here, user needs to
   1587      * maintain the consistency of group_l2 and IPMC table */
   1588     if (!IPMC_USED_ISSET(unit, ipmc->group)) {
   1589         return BCM_E_PARAM;
   1590     }
   1591 
   1592     /* Check if IPMC entry already exists.
   1593      * In case of BCM_IPMC_REPLACE flag being set,
   1594      * if entry is already present, old entry will be replaced,
   1595      * else new entry will be created. This is the expected behaviour
   1596      */
   1597     rv = _bcm_tr_ipmc_find(unit, ipmc, &l3cfg);
   1598     old_ipmc_index = l3cfg.l3c_ipmc_ptr;
   1599 #ifdef BCM_TRIDENT2_SUPPORT
   1600     old_rp_id = l3cfg.l3c_rp_id;
   1601 #endif /* BCM_TRIDENT2_SUPPORT */
   1602     if (BCM_SUCCESS(rv)) {
   1603         if (!(ipmc->flags & BCM_IPMC_REPLACE)) {
   1604            return (BCM_E_EXISTS);
   1605         } else {
   1606             new_entry = FALSE;
   1607         }
   1608     } else {
   1609         /* Return if error occured. */
   1610         if (rv != BCM_E_NOT_FOUND) {
   1611             return (rv);
   1612         }
   1613         new_entry = TRUE;
   1614     }
   1615 
   1616     if (new_entry) { 
   1617         BCM_IF_ERROR_RETURN(_bcm_tr_ipmc_src_port_consistency_check(unit,
   1618                     ipmc->group, ipmc, 0, &need_write));
   1619 
   1620         /* Increment the reference count of the given ipmc_index. */
   1621         BCM_IF_ERROR_RETURN(bcm_xgs3_ipmc_id_alloc(unit, ipmc->group));
   1622     } else {
   1623         if (ipmc->group != old_ipmc_index) {
   1624             BCM_IF_ERROR_RETURN
   1625                 (_bcm_tr_ipmc_src_port_consistency_check(unit,
   1626                                                          ipmc->group,
   1627                                                          ipmc, 0, &need_write));
   1628             /* Increment the reference count of the given ipmc_index. */
   1629             BCM_IF_ERROR_RETURN(bcm_xgs3_ipmc_id_alloc(unit, ipmc->group));
   1630 
   1631             /* Decrement the reference count of the old ipmc_index. */
   1632             BCM_IF_ERROR_RETURN(bcm_xgs3_ipmc_id_free(unit, old_ipmc_index));
   1633             if (!IPMC_USED_ISSET(unit, old_ipmc_index)) {
   1634                 /* Reference count should not be zero yet. */
   1635                 (void) bcm_xgs3_ipmc_id_free(unit, ipmc->group);
   1636                 (void) bcm_xgs3_ipmc_id_alloc(unit, old_ipmc_index);
   1637                 return BCM_E_INTERNAL;
   1638             }
   1639         } else {
   1640             BCM_IF_ERROR_RETURN
   1641                 (_bcm_tr_ipmc_src_port_consistency_check(unit,
   1642                                                          ipmc->group,
   1643                                                          ipmc, 1, &need_write));
   1644         }
   1645     }
   1646 
   1647     ipmc->v = (ipmc->flags & BCM_IPMC_ADD_DISABLED) ? 0 : 1;
   1648 
   1649     if (new_entry) {
   1650         if (need_write) {
   1651             /* Write L3_IPMC table entry. */
   1652             rv = _tr_ipmc_write(unit, ipmc->group, ipmc);
   1653             if (BCM_FAILURE(rv)) {
   1654                 bcm_xgs3_ipmc_id_free(unit, ipmc->group);
   1655                 return (rv);
   1656             }
   1657         }
   1658 
   1659         /* Add new L3 table entry */
   1660         rv = _bcm_tr_ipmc_add(unit, ipmc);
   1661         if (BCM_FAILURE(rv)) {
   1662             bcm_xgs3_ipmc_id_free(unit, ipmc->group);
   1663             if (!IPMC_USED_ISSET(unit, ipmc->group)) {
   1664                 /* Reference count should not be zero yet. */
   1665                 return BCM_E_INTERNAL;
   1666             }
   1667             return (rv);
   1668         }
   1669     } else {
   1670         if (need_write) {
   1671             /* Write L3_IPMC table entry. */
   1672             rv = _tr_ipmc_write(unit, ipmc->group, ipmc);
   1673             if (BCM_FAILURE(rv)) {
   1674                 if (ipmc->group != old_ipmc_index) {
   1675                     (void) bcm_xgs3_ipmc_id_free(unit, ipmc->group);
   1676                     (void) bcm_xgs3_ipmc_id_alloc(unit, old_ipmc_index);
   1677                 }
   1678                 return (rv);
   1679             }
   1680         }
   1681         /* Update existing IPMC entry */
   1682         rv = _bcm_tr_ipmc_replace(unit, ipmc, &l3cfg);
   1683         if (BCM_FAILURE(rv)) {
   1684             if (ipmc->group != old_ipmc_index) {
   1685                 (void) bcm_xgs3_ipmc_id_free(unit, ipmc->group);
   1686                 (void) bcm_xgs3_ipmc_id_alloc(unit, old_ipmc_index);
   1687             }
   1688             return rv;
   1689         }
   1690     }
   1691 
   1692 #ifdef BCM_TRIDENT2_SUPPORT
   1693     /* Update reference count of rendezvous point */
   1694     if (soc_feature(unit, soc_feature_pim_bidir)) {
   1695         if (new_entry) {
   1696             if (ipmc->rp_id != BCM_IPMC_RP_ID_INVALID) {
   1697                 BCM_IF_ERROR_RETURN
   1698                     (bcm_td2_ipmc_rp_ref_count_incr(unit, ipmc->rp_id));
   1699             }
   1700         } else {
   1701             if (old_rp_id != ipmc->rp_id) {
   1702                 if (ipmc->rp_id != BCM_IPMC_RP_ID_INVALID) {
   1703                     BCM_IF_ERROR_RETURN
   1704                         (bcm_td2_ipmc_rp_ref_count_incr(unit, ipmc->rp_id));
   1705                 }
   1706                 if (old_rp_id != BCM_IPMC_RP_ID_INVALID) {
   1707                     BCM_IF_ERROR_RETURN
   1708                         (bcm_td2_ipmc_rp_ref_count_decr(unit, old_rp_id));
   1709                 }
   1710             }
   1711         }
   1712     }
   1713 #endif /* BCM_TRIDENT2_SUPPORT */
   1714 
   1715     return BCM_E_NONE;
   1716 }
   1717 
   1718 /*
   1719  * Function:
   1720  *      bcm_tr_ipmc_put
   1721  * Purpose:
   1722  *      Overwrite an entry in the IPMC table.
   1723  * Parameters:
   1724  *      unit - StrataSwitch PCI device unit number (driver internal).
   1725  *      index - Table index to overwrite.
   1726  *      data - IPMC entry information.
   1727  * Returns:
   1728  *      BCM_E_XXX
   1729  */
   1730 
   1731 int
   1732 bcm_tr_ipmc_put(int unit, int index, bcm_ipmc_addr_t *ipmc)
   1733 {
   1734     _bcm_l3_cfg_t   l3cfg;
   1735 
   1736     IPMC_INIT(unit);
   1737     IPMC_ID(unit, index);
   1738 
   1739     BCM_IF_ERROR_RETURN(_tr_ipmc_write(unit, index, ipmc));
   1740 
   1741     sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   1742 
   1743     l3cfg.l3c_vid = ipmc->vid;
   1744     l3cfg.l3c_flags = BCM_L3_IPMC;
   1745     l3cfg.l3c_vrf = ipmc->vrf;
   1746     l3cfg.l3c_ing_intf = ipmc->ing_intf;
   1747     if (ipmc->flags & BCM_IPMC_L2) {
   1748         l3cfg.l3c_flags |= BCM_L3_L2ONLY;
   1749     }
   1750     if (ipmc->flags & BCM_IPMC_IP6) {
   1751         sal_memcpy(l3cfg.l3c_sip6, ipmc->s_ip6_addr, BCM_IP6_ADDRLEN);
   1752         sal_memcpy(l3cfg.l3c_ip6, ipmc->mc_ip6_addr, BCM_IP6_ADDRLEN);
   1753         l3cfg.l3c_flags |= BCM_L3_IP6;
   1754         BCM_IF_ERROR_RETURN
   1755             (mbcm_driver[unit]->mbcm_l3_ip6_get(unit, &l3cfg));
   1756     } else {
   1757         l3cfg.l3c_src_ip_addr = ipmc->s_ip_addr;
   1758         l3cfg.l3c_ipmc_group = ipmc->mc_ip_addr;
   1759         BCM_IF_ERROR_RETURN
   1760             (mbcm_driver[unit]->mbcm_l3_ip4_get(unit, &l3cfg));
   1761     }
   1762 
   1763     return _bcm_tr_ipmc_replace(unit, ipmc, &l3cfg);
   1764 }
   1765 
   1766 /*
   1767  * Function:
   1768  *      bcm_tr_ipmc_write
   1769  * Purpose:
   1770  *      Overwrite an entry in the IPMC table.
   1771  * Parameters:
   1772  *      unit - StrataSwitch PCI device unit number (driver internal).
   1773  *      index - Table index to overwrite.
   1774  *      data - IPMC entry information.
   1775  * Returns:
   1776  *      BCM_E_XXX
   1777  */
   1778 int
   1779 bcm_tr_ipmc_write (int unit, int ipmc_id, bcm_ipmc_addr_t *ipmc)
   1780 {
   1781 
   1782     return (_tr_ipmc_write(unit, ipmc_id, ipmc));
   1783 }
   1784 
   1785 /*
   1786  * Function:
   1787  *      _bcm_tr_ipmc_delete
   1788  * Purpose:
   1789  *      Delete an entry from the IPMC table.
   1790  * Parameters:
   1791  *      unit - StrataSwitch PCI device unit number (driver internal).
   1792  *      data - IPMC entry information.
   1793  *      modify_l3entry_list - Control whether to modify IPMC group's linked
   1794  *                            list of L3 entries.
   1795  * Returns:
   1796  *      BCM_E_XXX
   1797  * Notes:
   1798  *      If BCM_IPMC_KEEP_ENTRY is true, the entry valid bit is cleared
   1799  *      but the entry is not deleted from the table.
   1800  */
   1801 
   1802 STATIC int
   1803 _bcm_tr_ipmc_delete(int unit, bcm_ipmc_addr_t *ipmc, int modify_l3entry_list)
   1804 {
   1805     _bcm_l3_cfg_t       l3cfg;
   1806     int                 ipmc_id;
   1807 #ifdef BCM_TRIDENT2_SUPPORT
   1808     int                 rp_id;
   1809 #endif /* BCM_TRIDENT2_SUPPORT */
   1810 
   1811     IPMC_INIT(unit);
   1812 
   1813     sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   1814     l3cfg.l3c_vid = ipmc->vid;
   1815     l3cfg.l3c_flags = BCM_L3_IPMC;
   1816     l3cfg.l3c_vrf = ipmc->vrf;
   1817     l3cfg.l3c_ing_intf = ipmc->ing_intf;
   1818     if (ipmc->flags & BCM_IPMC_L2) {
   1819         l3cfg.l3c_flags |= BCM_L3_L2ONLY;
   1820     }
   1821 #ifdef BCM_TRIDENT3_SUPPORT
   1822     if (soc_feature(unit, soc_feature_flex_flow)) {
   1823         l3cfg.l3c_rp_id = BCM_IPMC_RP_ID_INVALID;
   1824         l3cfg.l3c_flow_handle = ipmc->flow_handle;
   1825         l3cfg.l3c_flow_option_handle = ipmc->flow_option_handle;
   1826         l3cfg.l3c_num_of_fields = ipmc->num_logical_fields;
   1827         sal_memcpy(l3cfg.l3c_logical_fields, ipmc->logical_fields,
   1828                    ipmc->num_logical_fields*sizeof(bcm_flow_logical_field_t));
   1829     }
   1830 #endif /* BCM_TRIDENT3_SUPPORT */
   1831     if (ipmc->flags & BCM_IPMC_IP6) {
   1832         sal_memcpy(l3cfg.l3c_sip6, ipmc->s_ip6_addr, BCM_IP6_ADDRLEN);
   1833         sal_memcpy(l3cfg.l3c_ip6, ipmc->mc_ip6_addr, BCM_IP6_ADDRLEN);
   1834         l3cfg.l3c_flags |= BCM_L3_IP6;
   1835         BCM_IF_ERROR_RETURN(
   1836             mbcm_driver[unit]->mbcm_l3_ip6_get(unit, &l3cfg));
   1837     } else {
   1838         l3cfg.l3c_src_ip_addr = ipmc->s_ip_addr;
   1839         l3cfg.l3c_ipmc_group = ipmc->mc_ip_addr;
   1840         BCM_IF_ERROR_RETURN(
   1841             mbcm_driver[unit]->mbcm_l3_ip4_get(unit, &l3cfg));
   1842     }
   1843     ipmc_id = l3cfg.l3c_ipmc_ptr;
   1844 #ifdef BCM_TRIDENT2_SUPPORT
   1845     rp_id = l3cfg.l3c_rp_id;
   1846 #endif /* BCM_TRIDENT2_SUPPORT */
   1847 
   1848     if (!(ipmc->flags & BCM_IPMC_KEEP_ENTRY)) {
   1849         BCM_IF_ERROR_RETURN
   1850             (_bcm_tr_ipmc_del(unit, ipmc, modify_l3entry_list));
   1851 
   1852         bcm_xgs3_ipmc_id_free(unit, ipmc_id);
   1853         if (!IPMC_USED_ISSET(unit, ipmc_id)) {
   1854             /* Reference count should not be zero yet. */
   1855             return BCM_E_INTERNAL;
   1856         }
   1857 
   1858 #ifdef BCM_TRIDENT2_SUPPORT
   1859         if (soc_feature(unit, soc_feature_pim_bidir)) {
   1860             if (rp_id != BCM_IPMC_RP_ID_INVALID) {
   1861                 BCM_IF_ERROR_RETURN
   1862                     (bcm_td2_ipmc_rp_ref_count_decr(unit, rp_id));
   1863             }
   1864         }
   1865 #endif /* BCM_TRIDENT2_SUPPORT */
   1866     }
   1867 
   1868     return BCM_E_NONE;
   1869 }
   1870 
   1871 /*
   1872  * Function:
   1873  *      bcm_tr_ipmc_delete
   1874  * Purpose:
   1875  *      Delete an entry from the IPMC table.
   1876  * Parameters:
   1877  *      unit - StrataSwitch PCI device unit number (driver internal).
   1878  *      data - IPMC entry information.
   1879  * Returns:
   1880  *      BCM_E_XXX
   1881  * Notes:
   1882  *      If BCM_IPMC_KEEP_ENTRY is true, the entry valid bit is cleared
   1883  *      but the entry is not deleted from the table.
   1884  */
   1885 
   1886 int
   1887 bcm_tr_ipmc_delete(int unit, bcm_ipmc_addr_t *ipmc)
   1888 {
   1889     return _bcm_tr_ipmc_delete(unit, ipmc, TRUE);
   1890 }
   1891 
   1892 /*
   1893  * Function:
   1894  *      bcm_tr_ipmc_delete_all
   1895  * Purpose:
   1896  *      Delete all entries from the IPMC table.
   1897  * Parameters:
   1898  *      unit - StrataSwitch PCI device unit number (driver internal).
   1899  * Returns:
   1900  *      BCM_E_XXX
   1901  */
   1902 
   1903 int
   1904 bcm_tr_ipmc_delete_all(int unit)
   1905 {
   1906     int i, rv = BCM_E_NONE;
   1907     _bcm_esw_ipmc_l3entry_t *ipmc_l3entry;
   1908     _bcm_l3_cfg_t l3cfg;
   1909 
   1910     IPMC_INIT(unit);
   1911 
   1912     IPMC_LOCK(unit);
   1913     for (i = 0; i < IPMC_GROUP_NUM(unit); i++) {
   1914         if (IPMC_USED_ISSET(unit, i)) {
   1915             ipmc_l3entry = IPMC_GROUP_INFO(unit, i)->l3entry_list;
   1916             while (ipmc_l3entry != NULL) {
   1917                 sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   1918 
   1919 #ifdef BCM_TRIDENT3_SUPPORT
   1920                 if (soc_feature(unit, soc_feature_flex_flow)) {
   1921                     l3cfg.l3c_flow_handle = ipmc_l3entry->l3info.flow_handle;
   1922                     l3cfg.l3c_flow_option_handle = ipmc_l3entry->l3info.flow_option_handle;
   1923                     l3cfg.l3c_num_of_fields = ipmc_l3entry->l3info.num_logical_fields;
   1924                     sal_memcpy(l3cfg.l3c_logical_fields, ipmc_l3entry->l3info.logical_fields,
   1925                                ipmc_l3entry->l3info.num_logical_fields*sizeof(bcm_flow_logical_field_t));
   1926                 }
   1927 #endif
   1928                 l3cfg.l3c_vid = ipmc_l3entry->l3info.vid;
   1929                 l3cfg.l3c_flags = BCM_L3_IPMC;
   1930                 l3cfg.l3c_vrf = ipmc_l3entry->l3info.vrf;
   1931                 l3cfg.l3c_ing_intf = ipmc_l3entry->l3info.ing_intf;
   1932                 if(ipmc_l3entry->l3info.flags & BCM_L3_L2ONLY) {
   1933                     l3cfg.l3c_flags |= BCM_L3_L2ONLY;
   1934                 }
   1935                 if (ipmc_l3entry->l3info.flags & BCM_L3_IP6) {
   1936                     sal_memcpy(l3cfg.l3c_sip6, ipmc_l3entry->l3info.sip6, BCM_IP6_ADDRLEN);
   1937                     sal_memcpy(l3cfg.l3c_ip6, ipmc_l3entry->l3info.ip6, BCM_IP6_ADDRLEN);
   1938                     l3cfg.l3c_flags |= BCM_L3_IP6;
   1939                 } else {
   1940                     l3cfg.l3c_src_ip_addr = ipmc_l3entry->l3info.src_ip_addr;
   1941                     l3cfg.l3c_ipmc_group = ipmc_l3entry->l3info.ip_addr;
   1942                 }
   1943                 rv = bcm_xgs3_l3_del(unit, &l3cfg);
   1944                 if (rv < 0) {
   1945                     IPMC_UNLOCK(unit);
   1946                     return rv;
   1947                 }
   1948 #ifdef BCM_TRIDENT2_SUPPORT
   1949                 if (soc_feature(unit, soc_feature_pim_bidir)) {
   1950                     if (ipmc_l3entry->l3info.rp_id != BCM_IPMC_RP_ID_INVALID) {
   1951                         rv = bcm_td2_ipmc_rp_ref_count_decr(unit,
   1952                                 ipmc_l3entry->l3info.rp_id);
   1953                         if (rv < 0) {
   1954                             IPMC_UNLOCK(unit);
   1955                             return rv;
   1956                         }
   1957                     }
   1958                 }
   1959 #endif /* BCM_TRIDENT2_SUPPORT */
   1960                 IPMC_GROUP_INFO(unit, i)->l3entry_list = ipmc_l3entry->next;
   1961                 sal_free(ipmc_l3entry);
   1962                 ipmc_l3entry = IPMC_GROUP_INFO(unit, i)->l3entry_list;
   1963             }
   1964 
   1965             /* For IPMC groups that have non-zero reference counts,
   1966              * decrease reference count to 1, meaning the IPMC group
   1967              * is only referenced by bcm_multicast_egress APIs.
   1968              */
   1969             IPMC_USED_ONE(unit, i);
   1970         }
   1971     }
   1972 
   1973     IPMC_UNLOCK(unit);
   1974 
   1975     return rv;
   1976 }
   1977 
   1978 /*
   1979  * Function:
   1980  *      bcm_tr_ipmc_age
   1981  * Purpose:
   1982  *      Age out the ipmc entry by clearing the HIT bit when appropriate,
   1983  *      the ipmc entry itself is removed if HIT bit is not set.
   1984  * Parameters:
   1985  *      unit       -  (IN) BCM device number.
   1986  *      flags      -  (IN) The criteria used to age out ipmc table.
   1987  *                         IPv6/IPv4
   1988  *      age_cb     -  (IN) Call back routine.
   1989  *      user_data  -  (IN) User provided cookie for callback.
   1990  * Returns:
   1991  *      BCM_E_XXX
   1992  */
   1993 int
   1994 bcm_tr_ipmc_age(int unit, uint32 flags, bcm_ipmc_traverse_cb age_cb,
   1995                 void *user_data)
   1996 {
   1997     int idx;                   /* Ipmc table iteration index. */
   1998     bcm_ipmc_addr_t entry;     /* Ipmc entry iterator.        */
   1999     int rv = BCM_E_NONE;       /* Operation return status.    */
   2000 
   2001     ipmc_entry_t   ipmc_entry;
   2002 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT)
   2003     ipmc_1_entry_t ipmc_1_entry;
   2004 #endif
   2005     _bcm_esw_ipmc_l3entry_t *ipmc_l3entry;
   2006     _bcm_esw_ipmc_l3entry_t *prev_ipmc_l3entry = NULL;
   2007 
   2008     IPMC_INIT(unit);
   2009     IPMC_LOCK(unit);
   2010 
   2011     for (idx = 0; idx < IPMC_GROUP_NUM(unit); idx++) {
   2012         if (IPMC_USED_ISSET(unit, idx)) {
   2013 
   2014             rv = soc_mem_read(unit, L3_IPMCm, MEM_BLOCK_ANY, idx, &ipmc_entry);
   2015             if (BCM_FAILURE(rv)) {
   2016                 goto age_done;
   2017             }
   2018 
   2019 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT)
   2020             if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) {
   2021                 rv = soc_mem_read(unit, L3_IPMC_1m, MEM_BLOCK_ANY, idx, 
   2022                                   &ipmc_1_entry);
   2023                 if (BCM_FAILURE(rv)) {
   2024                     goto age_done;
   2025                 }
   2026             }
   2027 #endif /* BCM_TRIUMPH2_SUPPORT */
   2028 
   2029             ipmc_l3entry = IPMC_GROUP_INFO(unit, idx)->l3entry_list;
   2030             while (ipmc_l3entry != NULL) {
   2031                 sal_memset(&entry, 0, sizeof(bcm_ipmc_addr_t));
   2032 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT)
   2033                 if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) {
   2034                     rv = _tr2_ipmc_glp_get(unit, &entry, &ipmc_1_entry);
   2035                     if (BCM_FAILURE(rv)) {
   2036                         goto age_done;
   2037                     }
   2038                 }
   2039 #endif /* BCM_TRIUMPH2_SUPPORT */
   2040 #ifdef BCM_TOMAHAWK_SUPPORT
   2041                 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
   2042                     rv = _th_ipmc_info_get(unit, idx, &entry, &ipmc_entry,
   2043                                            ipmc_l3entry);
   2044                 } else
   2045 #endif /* BCM_TOMAHAWK_SUPPORT */
   2046                 {
   2047                     rv = _tr_ipmc_info_get(unit, idx, &entry, &ipmc_entry,
   2048                                            1, ipmc_l3entry);
   2049                 }
   2050                 
   2051                 if (BCM_FAILURE(rv)) {
   2052                     goto age_done;
   2053                 }
   2054 
   2055                 /* Make sure update only ipv4 or ipv6 entries. */
   2056                 if ((flags & BCM_IPMC_IP6) != (entry.flags & BCM_IPMC_IP6)) {
   2057                     prev_ipmc_l3entry = ipmc_l3entry;
   2058                     ipmc_l3entry = ipmc_l3entry->next;
   2059                     continue;
   2060                 }
   2061 
   2062                 if (entry.flags & BCM_IPMC_HIT) {
   2063                     _bcm_l3_cfg_t l3cfg;
   2064                     /* Clear hit bit on used entry (by doing a lookup !!) */
   2065                     sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   2066                     l3cfg.l3c_flags |= BCM_L3_HIT_CLEAR;
   2067                     l3cfg.l3c_vid = ipmc_l3entry->l3info.vid;
   2068                     l3cfg.l3c_flags |= BCM_L3_IPMC;
   2069                     l3cfg.l3c_vrf = ipmc_l3entry->l3info.vrf;
   2070                     l3cfg.l3c_vid = ipmc_l3entry->l3info.vid;
   2071                     l3cfg.l3c_ing_intf = ipmc_l3entry->l3info.ing_intf;
   2072                     if(ipmc_l3entry->l3info.flags & BCM_L3_L2ONLY) {
   2073                         l3cfg.l3c_flags |= BCM_L3_L2ONLY;
   2074                     }
   2075                     if (ipmc_l3entry->ip6) {
   2076                         sal_memcpy(l3cfg.l3c_sip6, &ipmc_l3entry->l3info.sip6, 
   2077                                    BCM_IP6_ADDRLEN);
   2078                         sal_memcpy(l3cfg.l3c_ip6, &ipmc_l3entry->l3info.ip6, 
   2079                                    BCM_IP6_ADDRLEN);
   2080                         l3cfg.l3c_flags |= BCM_L3_IP6;
   2081                         rv = (mbcm_driver[unit]->mbcm_l3_ip6_get(unit, &l3cfg));
   2082                     } else {
   2083                         l3cfg.l3c_src_ip_addr = ipmc_l3entry->l3info.src_ip_addr;
   2084                         l3cfg.l3c_ipmc_group = ipmc_l3entry->l3info.ipmc_group;
   2085                         rv = (mbcm_driver[unit]->mbcm_l3_ip4_get(unit, &l3cfg));
   2086                     }
   2087                     if (BCM_FAILURE(rv)) {
   2088                         goto age_done;
   2089                     }
   2090                     prev_ipmc_l3entry = ipmc_l3entry;
   2091                     ipmc_l3entry = ipmc_l3entry->next;
   2092                 } else {
   2093                     /* Delete IPMC L3 entry. Inhibit modification of IPMC group's
   2094                      * l3entry_list by _bcm_tr_ipmc_delete.
   2095                      */
   2096                     rv = _bcm_tr_ipmc_delete(unit, &entry, FALSE);
   2097                     if (BCM_FAILURE(rv)) {
   2098                         goto age_done;
   2099                     }
   2100 
   2101                     /* Delete from IPMC group's l3entry_list */
   2102                     if (ipmc_l3entry == IPMC_GROUP_INFO(unit, idx)->l3entry_list) {
   2103                         IPMC_GROUP_INFO(unit, idx)->l3entry_list = ipmc_l3entry->next;
   2104                         sal_free(ipmc_l3entry);
   2105                         ipmc_l3entry = IPMC_GROUP_INFO(unit, idx)->l3entry_list;
   2106                     } else {
   2107                         /* 
   2108                          * In the following line of code, Coverity thinks the
   2109                          * prev_ipmc_l3entry pointer may still be NULL when 
   2110                          * dereferenced. This situation will never occur because 
   2111                          * if ipmc_l3entry is not pointing to the head of the 
   2112                          * linked list, prev_ipmc_l3entry would not be NULL.
   2113                          */
   2114                         /* coverity[var_deref_op : FALSE] */
   2115                         prev_ipmc_l3entry->next = ipmc_l3entry->next;
   2116                         sal_free(ipmc_l3entry);
   2117                         ipmc_l3entry = prev_ipmc_l3entry->next;
   2118                     }
   2119 
   2120                     /* Invoke user callback. */
   2121                     if (NULL != age_cb) {
   2122                         _BCM_MULTICAST_GROUP_SET(entry.group,
   2123                                 _BCM_MULTICAST_TYPE_L3, entry.group);
   2124                         _BCM_MULTICAST_GROUP_SET(entry.group_l2,
   2125                                 _BCM_MULTICAST_TYPE_L3, entry.group_l2);
   2126                         rv = (*age_cb)(unit, &entry, user_data);
   2127 #ifdef BCM_CB_ABORT_ON_ERR
   2128                         if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   2129                             goto age_done;
   2130                         }
   2131 #endif
   2132                     }
   2133                 }
   2134             }
   2135         }
   2136     }
   2137 
   2138 age_done:
   2139     IPMC_UNLOCK(unit);
   2140     return (rv);
   2141 }
   2142 
   2143 /*
   2144  * Function:
   2145  *      bcm_tr_ipmc_traverse
   2146  * Purpose:
   2147  *      Go through all valid ipmc entries, and call the callback function
   2148  *      at each entry
   2149  * Parameters:
   2150  *      unit      - (IN) BCM device number.
   2151  *      flags     - (IN) The criteria used to age out ipmc table.
   2152  *      cb        - (IN) User supplied callback function.
   2153  *      user_data - (IN) User supplied cookie used in parameter
   2154  *                       in callback function.
   2155  * Returns:
   2156  *      BCM_E_XXX
   2157  */
   2158 int
   2159 bcm_tr_ipmc_traverse(int unit, uint32 flags, bcm_ipmc_traverse_cb cb,
   2160                      void *user_data)
   2161 {
   2162     int idx;                   /* Ipmc table iteration index. */
   2163     bcm_ipmc_addr_t entry;     /* Ipmc entry iterator.        */
   2164     int rv = BCM_E_NONE;       /* Operation return status.    */
   2165 
   2166     ipmc_entry_t   ipmc_entry;
   2167 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT)
   2168     ipmc_1_entry_t ipmc_1_entry;
   2169 #endif
   2170     _bcm_esw_ipmc_l3entry_t *ipmc_l3entry;
   2171 
   2172     IPMC_INIT(unit);
   2173     IPMC_LOCK(unit);
   2174 
   2175     for (idx = 0; idx < IPMC_GROUP_NUM(unit); idx++) {
   2176         if (IPMC_USED_ISSET(unit, idx)) {
   2177 
   2178             rv = soc_mem_read(unit, L3_IPMCm, MEM_BLOCK_ANY, idx, &ipmc_entry);
   2179             if (BCM_FAILURE(rv)) {
   2180                 goto traverse_done;
   2181             }
   2182 
   2183 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT)
   2184             if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) {
   2185                 rv = soc_mem_read(unit, L3_IPMC_1m, MEM_BLOCK_ANY, idx, 
   2186                         &ipmc_1_entry);
   2187                 if (BCM_FAILURE(rv)) {
   2188                     goto traverse_done;
   2189                 }
   2190             }
   2191 #endif /* BCM_TRIUMPH2_SUPPORT */
   2192 
   2193             ipmc_l3entry = IPMC_GROUP_INFO(unit, idx)->l3entry_list;
   2194             while (ipmc_l3entry != NULL) {
   2195                 sal_memset(&entry, 0, sizeof(bcm_ipmc_addr_t));
   2196 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_KATANA2_SUPPORT)
   2197                 if (SOC_MEM_IS_VALID(unit, L3_IPMC_1m)) {
   2198                     rv = _tr2_ipmc_glp_get(unit, &entry, &ipmc_1_entry);
   2199                     if (BCM_FAILURE(rv)) {
   2200                         goto traverse_done;
   2201                     }
   2202                 }
   2203 #endif /* BCM_TRIUMPH2_SUPPORT */
   2204 #ifdef BCM_TOMAHAWK_SUPPORT
   2205                 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
   2206                     rv = _th_ipmc_info_get(unit, idx, &entry, &ipmc_entry,
   2207                                            ipmc_l3entry);
   2208                 } else
   2209 #endif /* BCM_TOMAHAWK_SUPPORT */
   2210                 {
   2211                     rv = _tr_ipmc_info_get(unit, idx, &entry, &ipmc_entry,
   2212                                            1, ipmc_l3entry);
   2213                 }
   2214                 
   2215                 if (BCM_FAILURE(rv)) {
   2216                     goto traverse_done;
   2217                 }
   2218 
   2219                 /* Make sure update only ipv4 or ipv6 entries. */
   2220                 if ((flags & BCM_IPMC_IP6) != (entry.flags & BCM_IPMC_IP6)) {
   2221                     ipmc_l3entry = ipmc_l3entry->next;
   2222                     continue;
   2223                 }
   2224 
   2225                 /* Get the pointer to next ipmc_l3entry before callback,
   2226                  * since callback may delete the current ipmc_l3entry.
   2227                  */
   2228                 ipmc_l3entry = ipmc_l3entry->next;
   2229 
   2230                 /* Invoke user callback. */
   2231                 _BCM_MULTICAST_GROUP_SET(entry.group,
   2232                                 _BCM_MULTICAST_TYPE_L3, entry.group);
   2233                 _BCM_MULTICAST_GROUP_SET(entry.group_l2,
   2234                                 _BCM_MULTICAST_TYPE_L3, entry.group_l2);
   2235                 rv = (*cb)(unit, &entry, user_data);
   2236 #ifdef BCM_CB_ABORT_ON_ERR
   2237                 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   2238                     goto traverse_done;
   2239                 }
   2240 #endif
   2241             }
   2242         }
   2243     }
   2244 
   2245 traverse_done:
   2246     IPMC_UNLOCK(unit);
   2247     return (rv);
   2248 }
   2249 
   2250 /*
   2251  * Function:
   2252  *      bcm_tr_ipmc_enable
   2253  * Purpose:
   2254  *      Enable or disable IPMC chip functions.
   2255  * Parameters:
   2256  *      unit - Unit number
   2257  *      enable - TRUE to enable; FALSE to disable
   2258  * Returns:
   2259  *      BCM_E_XXX
   2260  */
   2261 
   2262 int
   2263 bcm_tr_ipmc_enable(int unit, int enable)
   2264 {
   2265     IPMC_INIT(unit);
   2266 
   2267     return _tr_ipmc_enable(unit, enable);
   2268 }
   2269 
   2270 
   2271 /*
   2272  * Function:
   2273  *      bcm_tr_ipmc_src_port_check
   2274  * Purpose:
   2275  *      Enable or disable Source Port checking in IPMC lookups.
   2276  * Parameters:
   2277  *      unit - Unit number
   2278  *      enable - TRUE to enable; FALSE to disable
   2279  * Returns:
   2280  *      BCM_E_XXX
   2281  */
   2282 
   2283 int
   2284 bcm_tr_ipmc_src_port_check(int unit, int enable)
   2285 {
   2286     IPMC_INIT(unit);
   2287 
   2288     return BCM_E_UNAVAIL;
   2289 }
   2290 
   2291 /*
   2292  * Function:
   2293  *      bcm_tr_ipmc_src_ip_search
   2294  * Purpose:
   2295  *      Enable or disable Source IP significance in IPMC lookups.
   2296  * Parameters:
   2297  *      unit - Unit number
   2298  *      enable - TRUE to enable; FALSE to disable
   2299  * Returns:
   2300  *      BCM_E_XXX
   2301  */
   2302 
   2303 int
   2304 bcm_tr_ipmc_src_ip_search(int unit, int enable)
   2305 {
   2306     IPMC_INIT(unit);
   2307 
   2308     if (enable) {
   2309         return BCM_E_NONE;  /* always on */
   2310     } else {
   2311         return BCM_E_FAIL;  /* cannot be disabled */
   2312     }
   2313 }
   2314 
   2315 /*
   2316  * Function:
   2317  *      bcm_tr_ipmc_egress_port_set
   2318  * Purpose:
   2319  *      Configure the IP Multicast egress properties
   2320  * Parameters:
   2321  *      unit - StrataSwitch PCI device unit number (driver internal).
   2322  *      port - port to config.
   2323  *      mac  - MAC address.
   2324  *      untag - 1: The IP multicast packet is transmitted as untagged packet.
   2325  *              0: The IP multicast packet is transmitted as tagged packet
   2326  *              with VLAN tag vid.
   2327  *      vid  - VLAN ID.
   2328  *      ttl  - 1 to disable the TTL decrement, 0 otherwise.
   2329  * Returns:
   2330  *      BCM_E_XXX
   2331  */
   2332 
   2333 int
   2334 bcm_tr_ipmc_egress_port_set(int unit, bcm_port_t port,
   2335                             const bcm_mac_t mac, int untag,
   2336                             bcm_vlan_t vid, int ttl)
   2337 {
   2338     uint32      cfg2;
   2339 
   2340     if (soc_feature(unit, soc_feature_no_egr_ipmc_cfg)) {
   2341         return BCM_E_UNAVAIL;
   2342     }
   2343 
   2344 #if defined(BCM_KATANA2_SUPPORT)
   2345     if ((soc_feature(unit, soc_feature_linkphy_coe) &&
   2346         SOC_PBMP_MEMBER(SOC_INFO(unit).linkphy_pp_port_pbm, port)) ||
   2347         (soc_feature(unit, soc_feature_subtag_coe) &&
   2348         SOC_PBMP_MEMBER(SOC_INFO(unit).subtag_pp_port_pbm, port)) ||
   2349         (soc_feature(unit, soc_feature_general_cascade) &&
   2350         SOC_PBMP_MEMBER(SOC_INFO(unit).general_pp_port_pbm, port))) {
   2351     } else
   2352 #endif
   2353     if (!IS_PORT(unit, port)) {
   2354         return BCM_E_BADID;
   2355     }
   2356 
   2357     if (!SOC_PBMP_PORT_VALID(port)) {
   2358         return BCM_E_BADID;
   2359     }
   2360     /* TD3TBD */
   2361     if (SOC_MEM_IS_VALID(unit, EGR_IPMC_CFG2m)) {
   2362         SOC_IF_ERROR_RETURN(READ_EGR_IPMC_CFG2m(unit, MEM_BLOCK_ANY, port, &cfg2));
   2363 
   2364         soc_mem_field32_set(unit, EGR_IPMC_CFG2m, &cfg2,
   2365                       UNTAGf, untag ? 1 : 0);
   2366         soc_mem_field32_set(unit, EGR_IPMC_CFG2m, &cfg2,
   2367                       VIDf, vid);
   2368 
   2369         
   2370         SOC_IF_ERROR_RETURN(WRITE_EGR_IPMC_CFG2m(unit, MEM_BLOCK_ANY, port, &cfg2));
   2371     } else if (SOC_REG_IS_VALID(unit, EGR_IPMC_CFG2r)) {
   2372         SOC_IF_ERROR_RETURN(READ_EGR_IPMC_CFG2r(unit, port, &cfg2));
   2373 
   2374         soc_reg_field_set(unit, EGR_IPMC_CFG2r, &cfg2,
   2375                       UNTAGf, untag ? 1 : 0);
   2376         soc_reg_field_set(unit, EGR_IPMC_CFG2r, &cfg2,
   2377                       VIDf, vid);
   2378 
   2379         
   2380         SOC_IF_ERROR_RETURN(WRITE_EGR_IPMC_CFG2r(unit, port, cfg2));
   2381     }
   2382 
   2383 
   2384     return BCM_E_NONE;
   2385 }
   2386 
   2387 /*
   2388  * Function:
   2389  *      bcm_tr_ipmc_egress_port_get
   2390  * Purpose:
   2391  *      Return the IP Multicast egress properties
   2392  * Parameters:
   2393  *      unit - StrataSwitch PCI device unit number (driver internal).
   2394  *      port - port to config.
   2395  *      mac - (OUT) MAC address.
   2396  *      untag - (OUT) 1: The IP multicast packet is transmitted as
   2397  *                       untagged packet.
   2398  *                    0: The IP multicast packet is transmitted as tagged
   2399  *                       packet with VLAN tag vid.
   2400  *      vid - (OUT) VLAN ID.
   2401  *      ttl_thresh - (OUT) Drop IPMC packets if TTL <= ttl_thresh.
   2402  * Returns:
   2403  *      BCM_E_XXX
   2404  */
   2405 
   2406 int
   2407 bcm_tr_ipmc_egress_port_get(int unit, bcm_port_t port, sal_mac_addr_t mac,
   2408                             int *untag, bcm_vlan_t *vid, int *ttl_thresh)
   2409 {
   2410     uint32              cfg2;
   2411 
   2412     if (soc_feature(unit, soc_feature_no_egr_ipmc_cfg)) {
   2413         return BCM_E_UNAVAIL;
   2414     }
   2415 
   2416 #if defined(BCM_KATANA2_SUPPORT)
   2417     if (IS_LP_PORT(unit, port) || IS_SUBTAG_PORT(unit, port)) {
   2418     } else
   2419 #endif
   2420     if (!SOC_PBMP_PORT_VALID(port) || !IS_PORT(unit, port)) {
   2421         return BCM_E_BADID;
   2422     }
   2423 
   2424 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   2425     if (soc_feature(unit, soc_feature_egr_ipmc_cfg2_is_memory)) {
   2426         SOC_IF_ERROR_RETURN(READ_EGR_IPMC_CFG2m(unit, MEM_BLOCK_ANY, port, &cfg2));
   2427 
   2428         *untag = soc_mem_field32_get(unit, EGR_IPMC_CFG2m, &cfg2,
   2429                 UNTAGf);
   2430         *vid = soc_mem_field32_get(unit, EGR_IPMC_CFG2m, &cfg2,
   2431                 VIDf);
   2432         *ttl_thresh = -1;
   2433 
   2434     } else
   2435 #endif
   2436     {
   2437         SOC_IF_ERROR_RETURN(READ_EGR_IPMC_CFG2r(unit, port, &cfg2));
   2438 
   2439         *untag = soc_reg_field_get(unit, EGR_IPMC_CFG2r, cfg2, UNTAGf);
   2440         *vid = soc_reg_field_get(unit, EGR_IPMC_CFG2r, cfg2, VIDf);
   2441         *ttl_thresh = -1;
   2442     }
   2443 
   2444     return BCM_E_NONE;
   2445 }
   2446 
   2447 #ifdef BCM_WARM_BOOT_SUPPORT
   2448 
   2449 /*
   2450  * Recover IPMC group count, IPMC group info, and PIM-BIDIR
   2451  * rendezvous point reference count by traversing IPMC address table
   2452  */
   2453 STATIC int
   2454 _bcm_tr_ipmc_table_recover(int unit)
   2455 {
   2456     int rv = BCM_E_NONE;
   2457     soc_mem_t v4mc_mem, v6mc_mem;
   2458     int v4mc_entry_size, v6mc_entry_size;
   2459     int v4mc_key_type, v6mc_key_type;
   2460     int key;
   2461     soc_field_t l3mc_index_field, rpe_field, l3mc_index2 = INVALIDf;
   2462     soc_field_t vrf_field, group_ip_field, source_ip_field;
   2463     soc_field_t l3_iif_field, pri_field, class_id_field, rpa_id_field;
   2464     soc_field_t source_ip_hi_field, source_ip_lo_field;
   2465     soc_field_t group_ip_hi_field = INVALIDf;
   2466     soc_field_t group_ip_lo_field = INVALIDf;
   2467 #ifdef BCM_TRIDENT2_SUPPORT
   2468     soc_field_t expect_l3_iif_field = INVALIDf;
   2469 #endif
   2470     int chunk_size, num_chunks, chunk_index;
   2471     int entry_index_min, entry_index_max;
   2472     uint8 *v4mc_buf = NULL;
   2473     uint8 *v6mc_buf = NULL;
   2474     int i;
   2475     uint32 *v4mc_entry;
   2476     uint32 *v6mc_entry;
   2477     int ipmc_ptr;
   2478     _bcm_l3_cfg_t l3cfg;
   2479     soc_field_t key_type_field;
   2480 
   2481     COMPILER_REFERENCE(rpa_id_field);
   2482 
   2483     if (SOC_MEM_IS_VALID(unit, L3_ENTRY_2m)) {
   2484         v4mc_mem = L3_ENTRY_2m;
   2485         v4mc_entry_size = sizeof(l3_entry_2_entry_t);
   2486         v4mc_key_type = 6;
   2487         l3mc_index_field = IPV4MC__L3MC_INDEXf;
   2488         rpe_field = IPV4MC__RPEf;
   2489         vrf_field = IPV4MC__VRF_IDf;
   2490         group_ip_field = IPV4MC__GROUP_IP_ADDRf;
   2491         source_ip_field = IPV4MC__SOURCE_IP_ADDRf;
   2492         l3_iif_field = IPV4MC__L3_IIFf;
   2493         pri_field = IPV4MC__PRIf;
   2494         class_id_field = IPV4MC__CLASS_IDf;
   2495         rpa_id_field = INVALIDf;
   2496     } else {
   2497         if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) {
   2498             v4mc_mem = L3_ENTRY_DOUBLEm;
   2499             v4mc_entry_size = sizeof(l3_entry_double_entry_t);
   2500         } else {
   2501             v4mc_mem = L3_ENTRY_IPV4_MULTICASTm;
   2502             v4mc_entry_size = sizeof(l3_entry_ipv4_multicast_entry_t);
   2503         }
   2504 #ifdef BCM_TRIDENT2_SUPPORT
   2505         if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
   2506             v4mc_key_type = TD2_L3_HASH_KEY_TYPE_V4MC;
   2507         } else
   2508 #endif /* BCM_TRIDENT2_SUPPORT */
   2509         {
   2510             /* coverity[mixed_enums] */
   2511             v4mc_key_type = TR_L3_HASH_KEY_TYPE_V4MC;
   2512         }
   2513 
   2514         if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit) ) {
   2515             v4mc_mem = L3_ENTRY_DOUBLEm;
   2516             v4mc_entry_size = sizeof(l3_entry_double_entry_t);
   2517 
   2518             if (SOC_IS_TRIDENT3X(unit)) {
   2519                 l3mc_index_field = IPV4MC__DESTINATIONf;
   2520             } else {
   2521                 l3mc_index_field = IPV4MC__L3MC_INDEXf;
   2522             }
   2523             rpe_field = IPV4MC__RPEf;
   2524             vrf_field = IPV4MC__VRF_IDf;
   2525             group_ip_field = IPV4MC__GROUP_IP_ADDRf;
   2526             source_ip_field = IPV4MC__SOURCE_IP_ADDRf;
   2527             l3_iif_field = IPV4MC__L3_IIFf;
   2528             pri_field = IPV4MC__PRIf;
   2529             class_id_field = IPV4MC__CLASS_IDf;
   2530             rpa_id_field = IPV4MC__RPA_IDf;
   2531         } else {
   2532             l3mc_index_field = L3MC_INDEXf;
   2533             rpe_field = RPEf;
   2534             vrf_field = VRF_IDf;
   2535             group_ip_field = GROUP_IP_ADDRf;
   2536             source_ip_field = SOURCE_IP_ADDRf;
   2537             l3_iif_field = L3_IIFf;
   2538             pri_field = PRIf;
   2539             class_id_field = CLASS_IDf;
   2540             rpa_id_field = RPA_IDf;
   2541         }
   2542         if (SOC_MEM_FIELD_VALID(unit, v4mc_mem, IPV4MC__L3MC_INDEX_FOR_L2_DISTRIBUTIONf)) {
   2543             l3mc_index2 = IPV4MC__L3MC_INDEX_FOR_L2_DISTRIBUTIONf;
   2544         }
   2545     }
   2546 
   2547     /* Traverse IPv4 multicast table in chunks to avoid BCM_E_MEMORY */
   2548     chunk_size = 1024;
   2549     num_chunks = (soc_mem_index_count(unit, v4mc_mem) + chunk_size - 1) /
   2550                  chunk_size;
   2551     v4mc_buf = soc_cm_salloc(unit, v4mc_entry_size * chunk_size,
   2552             "v4mc buf dma");
   2553     if (v4mc_buf == NULL) {
   2554         return BCM_E_MEMORY;
   2555     }
   2556     for (chunk_index = 0; chunk_index < num_chunks; chunk_index++) {
   2557         /* Read a chunk of entries */
   2558         entry_index_min = chunk_index * chunk_size;
   2559         entry_index_max = entry_index_min + chunk_size - 1;
   2560         if (entry_index_max > soc_mem_index_max(unit, v4mc_mem)) {
   2561             entry_index_max = soc_mem_index_max(unit, v4mc_mem);
   2562         }
   2563         rv = soc_mem_read_range(unit, v4mc_mem, MEM_BLOCK_ANY,
   2564                 entry_index_min, entry_index_max, v4mc_buf);
   2565         if (SOC_FAILURE(rv)) {
   2566             soc_cm_sfree(unit, v4mc_buf);
   2567             return rv;
   2568         }
   2569 
   2570         /* Read each entry of the chunk */
   2571         for (i = 0; i < (entry_index_max - entry_index_min + 1); i++) {
   2572             v4mc_entry = soc_mem_table_idx_to_pointer(unit, v4mc_mem,
   2573                     uint32 *, v4mc_buf, i);
   2574             if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) {
   2575                 key_type_field = KEY_TYPEf;
   2576             } else {
   2577                 key_type_field = KEY_TYPE_0f;
   2578             }
   2579             key = soc_mem_field32_get(unit, v4mc_mem,
   2580                                     v4mc_entry, key_type_field);
   2581             if (soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) && 
   2582                  soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) {
   2583                 if ((key != v4mc_key_type) 
   2584 #ifdef BCM_TRIDENT2_SUPPORT
   2585                         && (key != TD2_L3_HASH_KEY_TYPE_V4L2MC) 
   2586                         && (key != TD2_L3_HASH_KEY_TYPE_V4L2VPMC)
   2587 #endif                        
   2588                    ) {
   2589 
   2590                     continue;
   2591                 }
   2592             } else if (key != v4mc_key_type) {
   2593                 continue;
   2594             }
   2595             if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) {
   2596                 key_type_field = KEY_TYPEf;
   2597             } else {
   2598                 key_type_field = KEY_TYPE_1f;
   2599             }
   2600             key = soc_mem_field32_get(unit, v4mc_mem,
   2601                                     v4mc_entry, key_type_field);
   2602             if (soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) && 
   2603                  soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) {
   2604                 if ((key != v4mc_key_type) 
   2605 #ifdef BCM_TRIDENT2_SUPPORT
   2606                        && (key != TD2_L3_HASH_KEY_TYPE_V4L2MC) 
   2607                        && (key != TD2_L3_HASH_KEY_TYPE_V4L2VPMC)
   2608 #endif       
   2609                    ) {
   2610 
   2611                     continue;
   2612                 }
   2613             } else if (key != v4mc_key_type) {
   2614                 continue;
   2615             }
   2616 
   2617             /* Skip Invalid Entries */
   2618             if (SOC_IS_TRIDENT3X(unit)) {
   2619                 if ((soc_mem_field32_get(unit, v4mc_mem, v4mc_entry, BASE_VALID_0f) != 3) ||
   2620                     (soc_mem_field32_get(unit, v4mc_mem, v4mc_entry, BASE_VALID_1f) != 4)) {
   2621                     continue;
   2622                 }
   2623             } else if (SOC_IS_TOMAHAWK3(unit))  {
   2624                 if ((soc_mem_field32_get(unit, v4mc_mem, v4mc_entry, BASE_VALID_0f) != 1) ||
   2625                     (soc_mem_field32_get(unit, v4mc_mem, v4mc_entry, BASE_VALID_1f) != 7)) {
   2626                     continue;
   2627                 }
   2628            } else {
   2629                 if ((0 == soc_mem_field32_get(unit, v4mc_mem, v4mc_entry, VALID_0f)) ||
   2630                     (0 == soc_mem_field32_get(unit, v4mc_mem, v4mc_entry, VALID_1f))) {
   2631                     continue;
   2632                 }
   2633             }
   2634 
   2635             /* Update IPMC group count and IPMC group reference count */
   2636 #ifdef BCM_TRIDENT3_SUPPORT
   2637             if (SOC_IS_TRIDENT3X(unit)) {
   2638                 uint32 dtype;
   2639                 ipmc_ptr = soc_mem_field32_dest_get(unit, v4mc_mem, v4mc_entry, l3mc_index_field, &dtype);
   2640             } else
   2641 #endif
   2642             {
   2643                 ipmc_ptr = soc_mem_field32_get(unit, v4mc_mem, v4mc_entry,
   2644                         l3mc_index_field);
   2645             }
   2646             IPMC_USED_SET(unit, ipmc_ptr);
   2647 
   2648             /* Insert into IPMC group's linked list of L3 entries */
   2649             sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   2650             l3cfg.l3c_ing_intf = BCM_IF_INVALID;
   2651             l3cfg.l3c_flags |= BCM_L3_IPMC;
   2652             l3cfg.l3c_flags |=  BCM_L3_HIT;
   2653             if (soc_mem_field32_get(unit, v4mc_mem, v4mc_entry, rpe_field)) {
   2654                 l3cfg.l3c_flags |=  BCM_L3_RPE;
   2655             }
   2656             if (SOC_MEM_FIELD_VALID(unit, v4mc_mem, vrf_field)) {
   2657                 l3cfg.l3c_vrf = soc_mem_field32_get(unit, v4mc_mem,
   2658                         v4mc_entry, vrf_field);
   2659             }
   2660             l3cfg.l3c_ipmc_group = soc_mem_field32_get(unit, v4mc_mem,
   2661                     v4mc_entry, group_ip_field);
   2662             l3cfg.l3c_src_ip_addr = soc_mem_field32_get(unit, v4mc_mem,
   2663                     v4mc_entry, source_ip_field);
   2664             if (soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn)) {
   2665                 if (soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) {
   2666                     l3cfg.l3c_ing_intf = soc_mem_field32_get(unit, v4mc_mem,
   2667                             v4mc_entry, l3_iif_field);
   2668                 } else {
   2669                     l3cfg.l3c_vid = soc_mem_field32_get(unit, v4mc_mem,
   2670                             v4mc_entry, l3_iif_field);
   2671                     l3cfg.l3c_flags |=  BCM_L3_L2ONLY;
   2672                 } 
   2673             } else {
   2674                 l3cfg.l3c_vid = soc_mem_field32_get(unit, v4mc_mem,
   2675                         v4mc_entry, l3_iif_field);
   2676             }        
   2677             l3cfg.l3c_prio = soc_mem_field32_get(unit, v4mc_mem,
   2678                     v4mc_entry, pri_field);
   2679 #ifdef BCM_TRIDENT3_SUPPORT
   2680             if (SOC_IS_TRIDENT3X(unit)) {
   2681                 uint32 dtype;
   2682                 l3cfg.l3c_ipmc_ptr = soc_mem_field32_dest_get(unit,
   2683                                                               v4mc_mem, v4mc_entry,
   2684                                                               l3mc_index_field, &dtype);
   2685             } else
   2686 #endif
   2687             {
   2688                 l3cfg.l3c_ipmc_ptr = soc_mem_field32_get(unit, v4mc_mem,
   2689                         v4mc_entry, l3mc_index_field);
   2690             }
   2691             if (l3mc_index2 != INVALIDf) {
   2692                 l3cfg.l3c_ipmc_ptr_l2 = soc_mem_field32_get(unit, v4mc_mem,
   2693                         v4mc_entry, l3mc_index2);
   2694             }
   2695             l3cfg.l3c_lookup_class = soc_mem_field32_get(unit, v4mc_mem,
   2696                     v4mc_entry, class_id_field);
   2697 #ifdef BCM_TRIDENT2_SUPPORT
   2698             if (soc_mem_field_valid(unit, L3_ENTRY_IPV4_MULTICASTm, RPA_IDf) ||
   2699                 soc_mem_field_valid(unit, L3_ENTRY_DOUBLEm,rpa_id_field)) {
   2700                 int iif_fld = EXPECTED_L3_IIFf;
   2701 
   2702 #ifdef BCM_TRIDENT3_SUPPORT
   2703                 if (SOC_IS_TRIDENT3X(unit)) {
   2704                     iif_fld = IPV4MC__EXPECTED_L3_IIFf;
   2705                 }
   2706 #endif /* BCM_TRIDENT3_SUPPORT */
   2707 
   2708                 l3cfg.l3c_rp_id = soc_mem_field32_get(unit, v4mc_mem,
   2709                         v4mc_entry, rpa_id_field);
   2710                 if (l3cfg.l3c_rp_id == 0 && (l3cfg.l3c_vid != 0 ||
   2711                             soc_mem_field32_get(unit, v4mc_mem, v4mc_entry,
   2712                                 iif_fld) != 0)) {
   2713                     /* If RPA_ID field value is 0, it could mean (1) this IPMC
   2714                      * entry is not a PIM-BIDIR entry, or (2) this entry is a
   2715                      * PIM-BIDIR entry and is associated with rendezvous point
   2716                      * 0. If either the L3 IIF in the key or the expected L3
   2717                      * IIF in the data is not zero, this entry is not a
   2718                      * PIM-BIDIR entry.
   2719                      */ 
   2720                     l3cfg.l3c_rp_id = BCM_IPMC_RP_ID_INVALID;
   2721                 } else {
   2722                     /* Recover rendezvous point's reference count */
   2723                     rv = bcm_td2_ipmc_rp_ref_count_recover(unit,
   2724                             l3cfg.l3c_rp_id);
   2725                     if (BCM_FAILURE(rv)) {
   2726                         soc_cm_sfree(unit, v4mc_buf);
   2727                         return rv;
   2728                     }
   2729                 }
   2730             }
   2731 #endif /* BCM_TRIDENT2_SUPPORT */
   2732             rv = _bcm_tr_ipmc_l3entry_list_add(unit, ipmc_ptr, &l3cfg);
   2733             if (BCM_FAILURE(rv)) {
   2734                 soc_cm_sfree(unit, v4mc_buf);
   2735                 return rv;
   2736             }
   2737         }
   2738     }
   2739     soc_cm_sfree(unit, v4mc_buf);
   2740 
   2741     /*
   2742      * Deal with IPv6 multicast table now
   2743      */
   2744     if (SOC_MEM_IS_VALID(unit, L3_ENTRY_4m)) {
   2745         v6mc_mem = L3_ENTRY_4m;
   2746         v6mc_entry_size = sizeof(l3_entry_4_entry_t);
   2747         v6mc_key_type = 7;
   2748         l3mc_index_field = IPV6MC__L3MC_INDEXf;
   2749         rpe_field = IPV6MC__RPEf;
   2750         vrf_field = IPV6MC__VRF_IDf;
   2751         source_ip_hi_field = IPV6MC__SOURCE_IP_ADDR_UPR_64f;
   2752         source_ip_lo_field = IPV6MC__SOURCE_IP_ADDR_LWR_64f;
   2753         l3_iif_field = IPV6MC__L3_IIFf;
   2754         pri_field = IPV6MC__PRIf;
   2755         class_id_field = IPV6MC__CLASS_IDf;
   2756         rpa_id_field = INVALIDf;
   2757     } else {
   2758         v6mc_mem = L3_ENTRY_IPV6_MULTICASTm;
   2759         v6mc_entry_size = sizeof(l3_entry_ipv6_multicast_entry_t);
   2760 #ifdef BCM_TRIDENT2_SUPPORT
   2761         if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWKX(unit)) {
   2762             v6mc_key_type = TD2_L3_HASH_KEY_TYPE_V6MC;
   2763         } else
   2764 #endif /* BCM_TRIDENT2_SUPPORT */
   2765         {
   2766             /* coverity[mixed_enums] */
   2767             v6mc_key_type = TR_L3_HASH_KEY_TYPE_V6MC;
   2768         }
   2769 
   2770         if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) {
   2771             v6mc_mem = L3_ENTRY_QUADm;
   2772             v6mc_entry_size = sizeof(l3_entry_quad_entry_t);
   2773             l3mc_index_field = IPV6MC__DESTINATIONf;
   2774             rpe_field = IPV6MC__RPEf;
   2775             vrf_field = IPV6MC__VRF_IDf;
   2776             source_ip_hi_field = IPV6MC__SOURCE_IP_ADDR_UPR_64f;
   2777             source_ip_lo_field = IPV6MC__SOURCE_IP_ADDR_LWR_64f;
   2778             l3_iif_field = IPV6MC__L3_IIFf;
   2779             pri_field = IPV6MC__PRIf;
   2780             class_id_field = IPV6MC__CLASS_IDf;
   2781             rpa_id_field = IPV6MC__RPA_IDf;
   2782             group_ip_hi_field = IPV6MC__GROUP_IP_ADDR_UPR_56f;
   2783             group_ip_lo_field = IPV6MC__GROUP_IP_ADDR_LWR_64f;
   2784 #ifdef BCM_TRIDENT2_SUPPORT
   2785             expect_l3_iif_field = IPV6MC__EXPECTED_L3_IIFf;
   2786 #endif
   2787         } else {
   2788             l3mc_index_field = L3MC_INDEXf;
   2789             rpe_field = RPEf;
   2790             vrf_field = VRF_IDf;
   2791             source_ip_hi_field = SOURCE_IP_ADDR_UPR_64f;
   2792             source_ip_lo_field = SOURCE_IP_ADDR_LWR_64f;
   2793             l3_iif_field = L3_IIFf;
   2794             pri_field = PRIf;
   2795             class_id_field = CLASS_IDf;
   2796             rpa_id_field = RPA_IDf;
   2797             group_ip_hi_field = GROUP_IP_ADDR_UPR_56f;
   2798             group_ip_lo_field = GROUP_IP_ADDR_LWR_64f;
   2799 #ifdef BCM_TRIDENT2_SUPPORT
   2800             expect_l3_iif_field = EXPECTED_L3_IIFf;
   2801 #endif
   2802         }
   2803         if (SOC_MEM_FIELD_VALID(unit, v6mc_mem, IPV6MC__L3MC_INDEX_FOR_L2_DISTRIBUTIONf)) {
   2804             l3mc_index2 = IPV6MC__L3MC_INDEX_FOR_L2_DISTRIBUTIONf;
   2805         }
   2806     }
   2807 
   2808     /* Traverse IPv6 multicast table in chunks to avoid BCM_E_MEMORY */
   2809     chunk_size = 1024;
   2810     num_chunks = (soc_mem_index_count(unit, v6mc_mem) + chunk_size - 1) /
   2811                  chunk_size;
   2812     v6mc_buf = soc_cm_salloc(unit, v6mc_entry_size * chunk_size,
   2813             "v6mc buf dma");
   2814     if (v6mc_buf == NULL) {
   2815         return BCM_E_MEMORY;
   2816     }
   2817     for (chunk_index = 0; chunk_index < num_chunks; chunk_index++) {
   2818         /* Read a chunk of entries */
   2819         entry_index_min = chunk_index * chunk_size;
   2820         entry_index_max = entry_index_min + chunk_size - 1;
   2821         if (entry_index_max > soc_mem_index_max(unit, v6mc_mem)) {
   2822             entry_index_max = soc_mem_index_max(unit, v6mc_mem);
   2823         }
   2824         rv = soc_mem_read_range(unit, v6mc_mem, MEM_BLOCK_ANY,
   2825                 entry_index_min, entry_index_max, v6mc_buf);
   2826         if (SOC_FAILURE(rv)) {
   2827             soc_cm_sfree(unit, v6mc_buf);
   2828             return rv;
   2829         }
   2830 
   2831         /* Read each entry of the chunk */
   2832         for (i = 0; i < (entry_index_max - entry_index_min + 1); i++) {
   2833             v6mc_entry = soc_mem_table_idx_to_pointer(unit, v6mc_mem,
   2834                     uint32 *, v6mc_buf, i);
   2835             if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) {
   2836                 key_type_field = KEY_TYPEf;
   2837             } else {
   2838                 key_type_field = KEY_TYPE_0f;
   2839             }
   2840             key = soc_mem_field32_get(unit, v6mc_mem,
   2841                                     v6mc_entry, key_type_field);
   2842             if (soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) &&
   2843                  soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) {
   2844                 if ((key != v6mc_key_type)
   2845 #ifdef BCM_TRIDENT2_SUPPORT
   2846                         && (key != TD2_L3_HASH_KEY_TYPE_V6L2MC)
   2847                         && (key != TD2_L3_HASH_KEY_TYPE_V6L2VPMC)
   2848 #endif
   2849                    ) {
   2850 
   2851                     continue;
   2852                 }
   2853             } else if (key != v6mc_key_type) {
   2854                 continue;
   2855             }
   2856 
   2857             if (!SOC_IS_TRIDENT3X(unit)) {
   2858                 if (SOC_IS_TOMAHAWK3(unit)) {
   2859                     key = soc_mem_field32_get(unit, v6mc_mem,
   2860                                             v6mc_entry, KEY_TYPEf);
   2861                 } else {
   2862                     key = soc_mem_field32_get(unit, v6mc_mem,
   2863                                             v6mc_entry, KEY_TYPE_1f);
   2864                 }
   2865                 if (soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) &&
   2866                      soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) {
   2867                     if ((key != v6mc_key_type)
   2868 #ifdef BCM_TRIDENT2_SUPPORT
   2869                             && (key != TD2_L3_HASH_KEY_TYPE_V6L2MC)
   2870                             && (key != TD2_L3_HASH_KEY_TYPE_V6L2VPMC)
   2871 #endif
   2872                        ) {
   2873 
   2874                         continue;
   2875                     }
   2876                 } else if (key != v6mc_key_type) {
   2877                     continue;
   2878                 }
   2879 
   2880                 if (!SOC_IS_TOMAHAWK3(unit)) {
   2881                     key = soc_mem_field32_get(unit, v6mc_mem,
   2882                                             v6mc_entry, KEY_TYPE_2f);
   2883                 }
   2884 
   2885                 if (soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) &&
   2886                      soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) {
   2887                     if ((key != v6mc_key_type)
   2888 #ifdef BCM_TRIDENT2_SUPPORT
   2889                             && (key != TD2_L3_HASH_KEY_TYPE_V6L2MC)
   2890                             && (key != TD2_L3_HASH_KEY_TYPE_V6L2VPMC)
   2891 #endif
   2892                        ) {
   2893 
   2894                         continue;
   2895                     }
   2896                 } else if (key != v6mc_key_type) {
   2897                     continue;
   2898                 }
   2899 
   2900                 if (!SOC_IS_TOMAHAWK3(unit)) {
   2901                     key = soc_mem_field32_get(unit, v6mc_mem,
   2902                                             v6mc_entry, KEY_TYPE_3f);
   2903                 }
   2904                 if (soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn) &&
   2905                      soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) {
   2906                     if ((key != v6mc_key_type)
   2907 #ifdef BCM_TRIDENT2_SUPPORT
   2908                             && (key != TD2_L3_HASH_KEY_TYPE_V6L2MC)
   2909                             && (key != TD2_L3_HASH_KEY_TYPE_V6L2VPMC)
   2910 #endif
   2911                        ) {
   2912 
   2913                         continue;
   2914                     }
   2915                 } else if (key != v6mc_key_type) {
   2916                     continue;
   2917                 }
   2918             }
   2919 
   2920             /* Skip Invalid Entries */
   2921             if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWK3(unit)) {
   2922                 if ((soc_mem_field32_get(unit, v6mc_mem, v6mc_entry, BASE_VALID_0f) != 5) ||
   2923                     (soc_mem_field32_get(unit, v6mc_mem, v6mc_entry, BASE_VALID_1f) != 6) ||
   2924                     (soc_mem_field32_get(unit, v6mc_mem, v6mc_entry, BASE_VALID_2f) != 6) ||
   2925                     (soc_mem_field32_get(unit, v6mc_mem, v6mc_entry, BASE_VALID_3f) != 7)) {
   2926                     continue;
   2927                 }
   2928             } else {
   2929                 if ((0 == soc_mem_field32_get(unit, v6mc_mem, v6mc_entry, VALID_0f)) ||
   2930                     (0 == soc_mem_field32_get(unit, v6mc_mem, v6mc_entry, VALID_1f)) ||
   2931                     (0 == soc_mem_field32_get(unit, v6mc_mem, v6mc_entry, VALID_2f)) ||
   2932                     (0 == soc_mem_field32_get(unit, v6mc_mem, v6mc_entry, VALID_3f))) {
   2933                     continue;
   2934                 }
   2935             }
   2936 
   2937             /* Update IPMC group count and IPMC group reference count */
   2938 #ifdef BCM_TRIDENT3_SUPPORT
   2939             if (soc_feature(unit, soc_feature_generic_dest)) {
   2940                 uint32 dtype;
   2941                 ipmc_ptr = soc_mem_field32_dest_get(unit, v6mc_mem, v6mc_entry,
   2942                                                       l3mc_index_field, &dtype);
   2943             } else
   2944 #endif
   2945             {
   2946                 ipmc_ptr = soc_mem_field32_get(unit, v6mc_mem, v6mc_entry,
   2947                                                                l3mc_index_field);
   2948             }
   2949             IPMC_USED_SET(unit, ipmc_ptr);
   2950 
   2951             /* Insert into IPMC group's linked list of L3 entries */
   2952             sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   2953             l3cfg.l3c_ing_intf = BCM_IF_INVALID;
   2954             l3cfg.l3c_flags |= BCM_IPMC_IP6;
   2955             l3cfg.l3c_flags |= BCM_L3_IPMC;
   2956             l3cfg.l3c_flags |=  BCM_L3_HIT;
   2957             l3cfg.l3c_flags |= BCM_L3_IP6;
   2958 
   2959             if (soc_mem_field32_get(unit, v6mc_mem, v6mc_entry, rpe_field)) {
   2960                 l3cfg.l3c_flags |= BCM_L3_RPE;
   2961             }
   2962             if (SOC_MEM_FIELD_VALID(unit, v6mc_mem, vrf_field)) {
   2963                 l3cfg.l3c_vrf = soc_mem_field32_get(unit, v6mc_mem,
   2964                         v6mc_entry, vrf_field);
   2965             }
   2966             if (SOC_MEM_IS_VALID(unit, L3_ENTRY_4m)) {
   2967                 soc_mem_ip6_addr_get(unit, v6mc_mem, v6mc_entry, 
   2968                         IPV6MC__GROUP_IP_ADDR_LWR_96f, l3cfg.l3c_ip6, 
   2969                         SOC_MEM_IP6_LOWER_96BIT);
   2970                 soc_mem_ip6_addr_get(unit, v6mc_mem, v6mc_entry, 
   2971                         IPV6MC__GROUP_IP_ADDR_UPR_24f, l3cfg.l3c_ip6, 
   2972                         SOC_MEM_IP6_BITS_119_96);
   2973             } else {
   2974                 soc_mem_ip6_addr_get(unit, v6mc_mem, v6mc_entry, 
   2975                         group_ip_lo_field, l3cfg.l3c_ip6,
   2976                         SOC_MEM_IP6_LOWER_ONLY);
   2977                 soc_mem_ip6_addr_get(unit, v6mc_mem, v6mc_entry, 
   2978                         group_ip_hi_field, l3cfg.l3c_ip6,
   2979                         SOC_MEM_IP6_UPPER_ONLY);
   2980             }
   2981             l3cfg.l3c_ip6[0] = 0xff;    /* Set entry to multicast*/
   2982 
   2983             if (SOC_MEM_IS_VALID(unit, L3_ENTRY_QUADm)) {
   2984                 soc_mem_ip6_addr_get(unit, v6mc_mem, v6mc_entry,
   2985                         IPV6MC__SOURCE_IP_ADDR_BITS_31_0f, l3cfg.l3c_sip6,
   2986                         SOC_MEM_IP6_BITS_31_0);
   2987                 soc_mem_ip6_addr_get(unit, v6mc_mem, v6mc_entry,
   2988                         IPV6MC__SOURCE_IP_ADDR_BITS_63_32f, l3cfg.l3c_sip6,
   2989                         SOC_MEM_IP6_BITS_63_32);
   2990             } else {
   2991                 soc_mem_ip6_addr_get(unit, v6mc_mem, v6mc_entry,
   2992                         source_ip_lo_field, l3cfg.l3c_sip6,
   2993                         SOC_MEM_IP6_LOWER_ONLY);
   2994             }
   2995             soc_mem_ip6_addr_get(unit, v6mc_mem, v6mc_entry, 
   2996                     source_ip_hi_field, l3cfg.l3c_sip6,
   2997                     SOC_MEM_IP6_UPPER_ONLY);
   2998            
   2999             if (soc_feature(unit, soc_feature_ipmc_l2_use_vlan_vpn)) {
   3000                 if (soc_property_get(unit, spn_IPMC_L2_USE_VLAN_VPN, 0)) {
   3001                     l3cfg.l3c_vid = soc_mem_field32_get(unit, v6mc_mem,
   3002                                               v6mc_entry, l3_iif_field);
   3003                     l3cfg.l3c_flags |=  BCM_L3_L2ONLY;
   3004                 } else {
   3005                     l3cfg.l3c_ing_intf = soc_mem_field32_get(unit, v6mc_mem,
   3006                                                    v6mc_entry, l3_iif_field);
   3007                 }
   3008             } else {
   3009                 l3cfg.l3c_vid = soc_mem_field32_get(unit, v6mc_mem,
   3010                                           v6mc_entry, l3_iif_field);
   3011             }
   3012 
   3013             l3cfg.l3c_prio = soc_mem_field32_get(unit, v6mc_mem,
   3014                     v6mc_entry, pri_field);
   3015             l3cfg.l3c_ipmc_ptr = ipmc_ptr;
   3016             if (l3mc_index2 != INVALIDf) {
   3017                 l3cfg.l3c_ipmc_ptr_l2 = soc_mem_field32_get(unit, v6mc_mem,
   3018                         v6mc_entry, l3mc_index2);
   3019             }
   3020             l3cfg.l3c_lookup_class = soc_mem_field32_get(unit, v6mc_mem,
   3021                     v6mc_entry, class_id_field);
   3022 #ifdef BCM_TRIDENT2_SUPPORT
   3023             if ((soc_mem_field_valid(unit, L3_ENTRY_IPV6_MULTICASTm, RPA_IDf)) ||
   3024                 (soc_mem_field_valid(unit, L3_ENTRY_QUADm, rpa_id_field))) {
   3025                 l3cfg.l3c_rp_id = soc_mem_field32_get(unit, v6mc_mem,
   3026                         v6mc_entry, rpa_id_field);
   3027                 if (l3cfg.l3c_rp_id == 0 && (l3cfg.l3c_vid != 0 ||
   3028                             soc_mem_field32_get(unit, v6mc_mem, v6mc_entry,
   3029                                 expect_l3_iif_field) != 0)) {
   3030                     /* If RPA_ID field value is 0, it could mean (1) this IPMC
   3031                      * entry is not a PIM-BIDIR entry, or (2) this entry is a
   3032                      * PIM-BIDIR entry and is associated with rendezvous point
   3033                      * 0. If either the L3 IIF in the key or the expected L3
   3034                      * IIF in the data is not zero, this entry is not a
   3035                      * PIM-BIDIR entry.
   3036                      */ 
   3037                     l3cfg.l3c_rp_id = BCM_IPMC_RP_ID_INVALID;
   3038                 } else {
   3039                     /* Update rendezvous point's reference count */
   3040                     rv = bcm_td2_ipmc_rp_ref_count_recover(unit,
   3041                             l3cfg.l3c_rp_id);
   3042                     if (BCM_FAILURE(rv)) {
   3043                         soc_cm_sfree(unit, v6mc_buf);
   3044                         return rv;
   3045                     }
   3046                 }
   3047             }
   3048 #endif /* BCM_TRIDENT2_SUPPORT */
   3049             rv = _bcm_tr_ipmc_l3entry_list_add(unit, ipmc_ptr, &l3cfg);
   3050             if (BCM_FAILURE(rv)) {
   3051                 soc_cm_sfree(unit, v6mc_buf);
   3052                 return rv;
   3053             }
   3054         }
   3055     }
   3056     soc_cm_sfree(unit, v6mc_buf);
   3057 
   3058 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   3059     if (soc_feature(unit, soc_feature_ipmc_defip)) {
   3060         BCM_IF_ERROR_RETURN(bcm_td2p_defip_ipmc_count_update(unit));
   3061     }
   3062 #endif
   3063 
   3064     return rv;
   3065 }
   3066 
   3067 /*
   3068  * Reload IPMC state on TR class of devices
   3069  */
   3070 int
   3071 _bcm_tr_ipmc_reinit(int unit)
   3072 {
   3073     _bcm_esw_ipmc_t *info = IPMC_INFO(unit);
   3074     int rv = BCM_E_NONE;
   3075     int i;
   3076     uint8 flags;
   3077     int l3_min, l3_max, l3_ipmc_tbl_sz;
   3078     uint8 *l3_ipmc_table = NULL;
   3079     _bcm_esw_ipmc_l3entry_t *ipmc_l3entry;
   3080     ipmc_entry_t *l3_ipmc_entry;
   3081 
   3082     info->ipmc_group_info = NULL;
   3083 
   3084     IPMC_GROUP_NUM(unit) = soc_mem_index_count(unit, L3_IPMCm);
   3085 #if defined(BCM_TRIUMPH3_SUPPORT)
   3086     if (soc_feature(unit, soc_feature_static_repl_head_alloc)) {
   3087         soc_info_t *si;
   3088         int member_count;
   3089         int port, phy_port, mmu_port;
   3090 
   3091         /* Each replication group is statically allocated a region
   3092          * in REPL_HEAD table. The size of the region depends on the
   3093          * maximum number of valid ports. Thus, the max number of
   3094          * replication groups is limited to number of REPL_HEAD entries
   3095          * divided by the max number of valid ports.
   3096          */
   3097         si = &SOC_INFO(unit);
   3098         member_count = 0;
   3099         PBMP_ITER(SOC_CONTROL(unit)->repl_eligible_pbmp, port) {
   3100             phy_port = si->port_l2p_mapping[port];
   3101             mmu_port = si->port_p2m_mapping[phy_port];
   3102             if ((mmu_port == 57) || (mmu_port == 59) || (mmu_port == 61) || (mmu_port == 62)) {
   3103                 /* No replication on MMU ports 57, 59, 61 and 62 */
   3104                 continue;
   3105             }
   3106             member_count++;
   3107         }
   3108         if (member_count > 0) {
   3109             IPMC_GROUP_NUM(unit) =
   3110                 soc_mem_index_count(unit, MMU_REPL_HEAD_TBLm) / member_count;
   3111             if (IPMC_GROUP_NUM(unit) > soc_mem_index_count(unit, L3_IPMCm)) {
   3112                 IPMC_GROUP_NUM(unit) = soc_mem_index_count(unit, L3_IPMCm);
   3113             }
   3114         }
   3115     } 
   3116 #endif /* BCM_TRIUMPH3_SUPPORT */
   3117 
   3118 #ifdef BCM_BRADLEY_SUPPORT
   3119     if (!SOC_IS_MONTEREY(unit)) {
   3120         if (SOC_REG_FIELD_VALID(unit, MC_CONTROL_5r, SHARED_TABLE_IPMC_SIZEf)) {
   3121             int ipmc_base, ipmc_size;
   3122 
   3123             SOC_IF_ERROR_RETURN
   3124                 (soc_hbx_ipmc_size_get(unit, &ipmc_base, &ipmc_size));
   3125 
   3126             if (IPMC_GROUP_NUM(unit) > ipmc_size) {
   3127                 /* Reduce to fix allocated table space */
   3128                 IPMC_GROUP_NUM(unit) = ipmc_size;
   3129             }
   3130         }
   3131     }
   3132 #endif /* BCM_BRADLEY_SUPPORT */
   3133 
   3134     info->ipmc_count = 0;
   3135 
   3136     info->ipmc_group_info =
   3137         sal_alloc(IPMC_GROUP_NUM(unit) * sizeof(_bcm_esw_ipmc_group_info_t),
   3138                   "IPMC group info");
   3139     if (info->ipmc_group_info == NULL) {
   3140         rv = BCM_E_MEMORY;
   3141         goto ret_err;
   3142     }
   3143     sal_memset(info->ipmc_group_info, 0, 
   3144                IPMC_GROUP_NUM(unit) * sizeof(_bcm_esw_ipmc_group_info_t));
   3145 
   3146 #ifdef BCM_TRIDENT2_SUPPORT
   3147     if (soc_feature(unit, soc_feature_pim_bidir)) {
   3148         rv = bcm_td2_ipmc_pim_bidir_init(unit);
   3149         if (BCM_FAILURE(rv)) {
   3150             goto ret_err;
   3151         }
   3152     }
   3153 #endif /* BCM_TRIDENT2_SUPPORT */
   3154 
   3155     /* Traverse IPMC address table to recover IPMC group count,
   3156      * IPMC group info, and PIM-BIDIR rendezvous point reference count.
   3157      */
   3158     rv = _bcm_tr_ipmc_table_recover(unit);
   3159     if (BCM_FAILURE(rv)) {
   3160         goto ret_err;
   3161     }
   3162 
   3163     /* Recover multicast mode from HW cache */
   3164     rv = _bcm_esw_ipmc_repl_wb_flags_get(unit,
   3165                                          _BCM_IPMC_WB_MULTICAST_MODE,
   3166                                          &flags);
   3167     if (flags) {
   3168         /*
   3169          * Increase reference count for all defined mulitcast groups now
   3170          */
   3171         l3_min = soc_mem_index_min(unit, L3_IPMCm);
   3172         l3_max = soc_mem_index_max(unit, L3_IPMCm);
   3173         l3_ipmc_tbl_sz = sizeof(ipmc_entry_t) * \
   3174             (l3_max - l3_min + 1);
   3175         l3_ipmc_table = soc_cm_salloc(unit, l3_ipmc_tbl_sz,
   3176                                       "L3 ipmc tbl dma");
   3177         if (l3_ipmc_table == NULL) {
   3178             rv = BCM_E_MEMORY;
   3179             goto ret_err;
   3180         }
   3181         if ((rv = soc_mem_read_range(unit, L3_IPMCm,
   3182                                      MEM_BLOCK_ANY,
   3183                                      l3_min, l3_max, l3_ipmc_table)) < 0) {
   3184             soc_cm_sfree(unit, l3_ipmc_table);
   3185             goto ret_err;
   3186         }
   3187 
   3188         for (i = l3_min; i <= l3_max; i++) {
   3189 #if defined(BCM_XGS3_SWITCH_SUPPORT) && defined(INCLUDE_L3)
   3190             if (SOC_IS_XGS3_SWITCH(unit) && !(SOC_IS_KATANAX(unit)) && i == 0) {
   3191                 /* reserve L3_IPMC entry 0 for default behavior */
   3192                 /* for Katana and Katana2 0 and 1 get reserved from inside 
   3193                 * bcm_tr2_ipmc_repl_init() and
   3194                 * bcm_kt2_ipmc_repl_init
   3195                 */ 
   3196                 IPMC_USED_SET(unit, i);
   3197                 continue;
   3198             }
   3199 #endif
   3200             l3_ipmc_entry = soc_mem_table_idx_to_pointer(unit,
   3201                                                          L3_IPMCm,
   3202                                                          ipmc_entry_t *,
   3203                                                          l3_ipmc_table, i);
   3204             if (0 == soc_L3_IPMCm_field32_get(unit, l3_ipmc_entry,
   3205                                               VALIDf)) {
   3206                 continue;
   3207             }
   3208         
   3209             /* It's a multicast group we need to note. */
   3210             IPMC_USED_SET(unit, i);
   3211         }
   3212         soc_cm_sfree(unit, l3_ipmc_table);
   3213     }
   3214 
   3215     /*
   3216      * Recover replication state
   3217      */
   3218 #if defined(BCM_TRIUMPH3_SUPPORT) 
   3219     if (SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT2X(unit)) {
   3220         rv = _bcm_tr3_ipmc_repl_reload(unit);
   3221     } else
   3222     #if defined(BCM_TOMAHAWK_SUPPORT)
   3223     if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
   3224         rv = _bcm_th_ipmc_repl_reload(unit);
   3225     } else
   3226     #endif /* BCM_TOMAHAWK_SUPPORT */
   3227 #endif /* BCM_TRIUMPH3_SUPPORT */
   3228 #ifdef BCM_SABER2_SUPPORT
   3229  if (SOC_IS_SABER2(unit)) {
   3230         rv = _bcm_sb2_ipmc_repl_reload(unit);
   3231     } else
   3232 #endif /* BCM_SABER2_SUPPORT */
   3233 
   3234 #ifdef BCM_KATANA2_SUPPORT
   3235  if (SOC_IS_KATANA2(unit)) {
   3236         rv = _bcm_kt2_ipmc_repl_reload(unit);
   3237     } else
   3238 #endif /* BCM_KATANA2_SUPPORT */
   3239 #ifdef BCM_TRIUMPH2_SUPPORT
   3240     if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 
   3241             SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) ||
   3242             SOC_IS_KATANA(unit)) {
   3243         rv = _bcm_tr2_ipmc_repl_reload(unit);
   3244     } else
   3245 #endif /* BCM_TRIUMPH2_SUPPORT */
   3246     {
   3247         rv = _bcm_xgs3_ipmc_repl_reload(unit);
   3248     }
   3249 
   3250 ret_err:
   3251     if (BCM_FAILURE(rv)) {
   3252 
   3253         if (info->ipmc_group_info != NULL) {
   3254             for (i = 0; i < IPMC_GROUP_NUM(unit); i++) {
   3255                 ipmc_l3entry = IPMC_GROUP_INFO(unit, i)->l3entry_list;
   3256                 while (ipmc_l3entry != NULL) {
   3257                     IPMC_GROUP_INFO(unit, i)->l3entry_list = ipmc_l3entry->next;
   3258                     sal_free(ipmc_l3entry);
   3259                     ipmc_l3entry = IPMC_GROUP_INFO(unit, i)->l3entry_list;
   3260                 }
   3261             }
   3262             sal_free(info->ipmc_group_info);
   3263             info->ipmc_group_info = NULL;
   3264         }
   3265     } else {
   3266         info->ipmc_initialized = TRUE;
   3267     }
   3268 
   3269     return rv;
   3270 }
   3271 #endif /* BCM_WARM_BOOT_SUPPORT */
   3272 
   3273 #ifndef BCM_SW_STATE_DUMP_DISABLE
   3274 /*
   3275  * Function:
   3276  *     _bcm_tr_ipmc_sw_dump
   3277  * Purpose:
   3278  *     Displays IPMC information maintained by software.
   3279  * Parameters:
   3280  *     unit - Device unit number
   3281  * Returns:
   3282  *     None
   3283  */
   3284 void
   3285 _bcm_tr_ipmc_sw_dump(int unit)
   3286 {
   3287     int                   i, j;
   3288     _bcm_esw_ipmc_t      *ipmc_info;
   3289     _bcm_esw_ipmc_l3entry_t *ipmc_l3entry;
   3290 
   3291     /*
   3292      * xgs3_ipmc_info
   3293      */
   3294 
   3295     ipmc_info = IPMC_INFO(unit);
   3296 
   3297     LOG_CLI((BSL_META_U(unit,
   3298                         "  XGS3 IPMC Info -\n")));
   3299     LOG_CLI((BSL_META_U(unit,
   3300                         "    Init        : %d\n"), ipmc_info->ipmc_initialized));
   3301     LOG_CLI((BSL_META_U(unit,
   3302                         "    Size        : %d\n"), IPMC_GROUP_NUM(unit)));
   3303     LOG_CLI((BSL_META_U(unit,
   3304                         "    Count       : %d\n"), ipmc_info->ipmc_count));
   3305 
   3306     LOG_CLI((BSL_META_U(unit,
   3307                         "    Alloc index :")));
   3308     if (ipmc_info->ipmc_group_info != NULL) {
   3309         for (i = 0, j = 0; i < IPMC_GROUP_NUM(unit); i++) {
   3310             /* If not set, skip print */
   3311             if (!IPMC_USED_ISSET(unit, i)) {
   3312                 continue;
   3313             }
   3314             if (!(j % 10)) {
   3315                 LOG_CLI((BSL_META_U(unit,
   3316                                     "\n    ")));
   3317             }
   3318             LOG_CLI((BSL_META_U(unit,
   3319                                 "  %5d"), i));
   3320             j++;
   3321         }
   3322     }
   3323     LOG_CLI((BSL_META_U(unit,
   3324                         "\n")));
   3325 
   3326     LOG_CLI((BSL_META_U(unit,
   3327                         "    Reference count (index:value) :")));
   3328     if (ipmc_info->ipmc_group_info != NULL) {
   3329         for (i = 0, j = 0; i < IPMC_GROUP_NUM(unit); i++) {
   3330             if (!IPMC_USED_ISSET(unit, i)) {
   3331                 continue;
   3332             }
   3333             if (!(j % 4)) {
   3334                 LOG_CLI((BSL_META_U(unit,
   3335                                     "\n    ")));
   3336             }
   3337             LOG_CLI((BSL_META_U(unit,
   3338                                 "  %5d:%-5d"), i, IPMC_GROUP_INFO(unit, i)->ref_count));
   3339             j++;
   3340         }
   3341     }
   3342     LOG_CLI((BSL_META_U(unit,
   3343                         "\n")));
   3344 
   3345     LOG_CLI((BSL_META_U(unit,
   3346                         "    IP6 (index:value) :")));
   3347     if (ipmc_info->ipmc_group_info != NULL) {
   3348         for (i = 0, j = 0; i < IPMC_GROUP_NUM(unit); i++) {
   3349             ipmc_l3entry = IPMC_GROUP_INFO(unit, i)->l3entry_list;
   3350             while (ipmc_l3entry != NULL) {
   3351                 if (ipmc_l3entry->ip6 == 1) {
   3352                     if (!(j % 4)) {
   3353                         LOG_CLI((BSL_META_U(unit,
   3354                                             "\n    ")));
   3355                     }
   3356                     LOG_CLI((BSL_META_U(unit,
   3357                                         "  %5d:%-5d"), i, ipmc_l3entry->ip6));
   3358                     j++;
   3359                 }
   3360                 ipmc_l3entry = ipmc_l3entry->next;
   3361             }
   3362         }
   3363     }
   3364     LOG_CLI((BSL_META_U(unit,
   3365                         "\n")));
   3366     LOG_CLI((BSL_META_U(unit,
   3367                         "    Group (G1:G2) :")));
   3368     if (ipmc_info->ipmc_group_info != NULL) {
   3369         for (i = 0, j = 0; i < IPMC_GROUP_NUM(unit); i++) {
   3370             ipmc_l3entry = IPMC_GROUP_INFO(unit, i)->l3entry_list;
   3371             while (ipmc_l3entry != NULL) {
   3372                 if (!(j % 4)) {
   3373                     LOG_CLI((BSL_META_U(unit,
   3374                                         "\n    ")));
   3375                 }
   3376                 LOG_CLI((BSL_META_U(unit, "  %4d:%-4d"),
   3377                     ipmc_l3entry->l3info.ipmc_ptr,
   3378                     ipmc_l3entry->l3info.ipmc_ptr_l2));
   3379                 j++;
   3380                 ipmc_l3entry = ipmc_l3entry->next;
   3381             }
   3382         }
   3383     }
   3384     LOG_CLI((BSL_META_U(unit,
   3385                         "\n")));
   3386 
   3387 
   3388 #ifdef BCM_TRIDENT2_SUPPORT
   3389     if (soc_feature(unit, soc_feature_pim_bidir)) {
   3390         _bcm_td2_ipmc_pim_bidir_sw_dump(unit);
   3391     }
   3392 #endif /* BCM_TRIDENT2_SUPPORT */
   3393 
   3394     /* IPMC replication info is elsewhere */
   3395 #if defined(BCM_TOMAHAWK_SUPPORT)
   3396     if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
   3397         _bcm_th_ipmc_repl_sw_dump(unit);
   3398     } else
   3399 #endif /* BCM_TOMAHAWK_SUPPORT */
   3400 #if defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_KATANA2_SUPPORT)
   3401     if (SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT2X(unit) || SOC_IS_KATANA2(unit)) {
   3402         _bcm_tr3_ipmc_repl_sw_dump(unit);
   3403     } else
   3404 #endif /* BCM_TRIUMPH3_SUPPORT */
   3405 #ifdef BCM_TRIUMPH2_SUPPORT
   3406     if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 
   3407             SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) ||
   3408             SOC_IS_KATANA(unit)) {
   3409         _bcm_tr2_ipmc_repl_sw_dump(unit);
   3410     } else
   3411 #endif /* BCM_TRIUMPH2_SUPPORT */
   3412     {
   3413         _bcm_xgs3_ipmc_repl_sw_dump(unit);
   3414     }
   3415 
   3416     return;
   3417 }
   3418 #endif /* BCM_SW_STATE_DUMP_DISABLE */
   3419 
   3420 #endif  /* INCLUDE_L3 */
   3421 
   3422 int _bcm_tr_firebolt_ipmc_not_empty;