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

multicast.c (312269B)


      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:    multicast.c
      8  * Purpose: Manages multicast functions
      9  */
     10 #include <shared/bsl.h>
     11 
     12 #include <sal/core/libc.h>
     13 #include <sal/core/time.h>
     14 #include <soc/defs.h>
     15 #include <soc/drv.h>
     16 #include <soc/scache.h>
     17 #include <soc/util.h>
     18 #if defined(BCM_BRADLEY_SUPPORT)
     19 #include <soc/bradley.h>
     20 #endif /* BCM_BRADLEY_SUPPORT */
     21 #include <bcm/l2.h>
     22 #include <bcm/port.h>
     23 #include <bcm/error.h>
     24 #include <bcm/multicast.h>
     25 
     26 #include <bcm_int/esw/mbcm.h>
     27 #include <bcm_int/esw/firebolt.h>
     28 #include <bcm_int/common/multicast.h>
     29 #include <bcm_int/esw/multicast.h>
     30 #include <bcm_int/esw/ipmc.h>
     31 #include <bcm_int/esw/switch.h>
     32 #if defined(BCM_TRX_SUPPORT)
     33 #include <bcm_int/esw/triumph.h>
     34 #include <bcm_int/esw/trx.h>
     35 #endif /* BCM_TRX_SUPPORT */
     36 #if defined(BCM_TRIUMPH2_SUPPORT)
     37 #include <bcm_int/esw/triumph2.h>
     38 #endif /* BCM_TRIUMPH2_SUPPORT */
     39 #if defined(BCM_TRIDENT_SUPPORT)
     40 #include <bcm_int/esw/trident.h>
     41 #endif /* BCM_TRIDENT_SUPPORT */
     42 #if defined(BCM_KATANA_SUPPORT)
     43 #include <bcm_int/esw/katana.h>
     44 #include <soc/katana2.h>
     45 #endif /* BCM_KATANA_SUPPORT */
     46 #if defined(BCM_TRIDENT2_SUPPORT)
     47 #include <bcm_int/esw/trident2.h>
     48 #endif /* BCM_TRIDENT2_SUPPORT */
     49 #if defined(BCM_HGPROXY_COE_SUPPORT)
     50 #include <bcm_int/esw/xgs5.h>
     51 #include <bcm_int/esw/subport.h>
     52 #endif /* BCM_HGPROXY_COE_SUPPORT */
     53 #if defined(BCM_KATANA2_SUPPORT)
     54 #include <bcm_int/esw/katana2.h>
     55 #include <bcm_int/esw/subport.h>
     56 #endif /* BCM_KATANA2_SUPPORT */
     57 #if defined(BCM_TOMAHAWK_SUPPORT)
     58 #include <bcm_int/esw/tomahawk.h>
     59 #endif /* BCM_TOMAHAWK_SUPPORT */
     60 #if defined(BCM_TOMAHAWK3_SUPPORT)
     61 #include <bcm_int/esw/tomahawk3.h>
     62 #include <soc/flexport/tomahawk3_mmu_flexport.h>
     63 #endif /* BCM_TOMAHAWK3_SUPPORT */
     64 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
     65 #include <bcm_int/esw/trident2plus.h>
     66 #endif /* BCM_TRIDENT2PLUS_SUPPORT */
     67 #if defined(BCM_GREYHOUND2_SUPPORT)
     68 #include <bcm_int/esw/greyhound2.h>
     69 #endif /* BCM_GREYHOUND2_SUPPORT */
     70 #ifdef BCM_TRIDENT3_SUPPORT
     71 #include <soc/esw/cancun.h>
     72 #include <soc/esw/cancun_enums.h>
     73 #endif /* BCM_TRIDENT3_SUPPORT */
     74 
     75 #include <bcm_int/esw_dispatch.h>
     76 #include <bcm_int/esw/virtual.h>
     77 #include <bcm_int/esw/xgs3.h>
     78 #include <bcm_int/esw/stack.h>
     79 #include <bcm_int/esw/trunk.h>
     80 #include <bcm_int/api_xlate_port.h>
     81 #include <bcm_int/esw/triumph3.h>
     82 #include<bcm_int/esw/saber2.h> 
     83 
     84 #define _BCM_MULTICAST_MTU_TABLE_OFFSET(unit) \
     85         ((SOC_IS_HURRICANEX(unit) || SOC_IS_GREYHOUND(unit) || \
     86           SOC_IS_METROLITE(unit) || SOC_IS_GREYHOUND2(unit)) ? 512 : \
     87           SOC_IS_TRIDENT2PLUS(unit) ? 12288 : SOC_IS_MONTEREY(unit) ? 2048 : \
     88           (SOC_IS_TRIDENT3(unit) || SOC_IS_MAVERICK2(unit)) ? 16384 : \
     89           SOC_IS_APACHE(unit) ? 12288 : 8192)
     90 #define _BCM_TR3_MULTICAST_MTU_TABLE_OFFSET(unit) (SOC_IS_HELIX4(unit) ? 12288 : 16384)
     91 
     92 #ifdef BCM_WARM_BOOT_SUPPORT
     93 static int multicast_mode_set[BCM_MAX_NUM_UNITS];
     94 #endif /* BCM_WARM_BOOT_SUPPORT */
     95 
     96 #define _BCM_MULTICAST_L2_OR_FABRIC(_unit_, _group_) \
     97         (_BCM_MULTICAST_IS_L2(_group_) || SOC_IS_XGS3_FABRIC(_unit_))
     98 
     99 #ifdef	BCM_XGS3_FABRIC_SUPPORT
    100 typedef struct _bcm_fabric_multicast_info_s {
    101     int         mcast_size;
    102     int         ipmc_size;
    103     uint32      *mcast_used;
    104 } _bcm_fabric_multicast_info_t;
    105 
    106 static _bcm_fabric_multicast_info_t _bcm_fabric_mc_info[BCM_MAX_NUM_UNITS];
    107 uint8 *_fabric_multicast_ipmc_group_types[BCM_MAX_NUM_UNITS];
    108 
    109 STATIC int
    110 _bcm_esw_multicast_egress_get(int unit, bcm_multicast_t group, int port_max,
    111                               bcm_gport_t *port_array,
    112                               bcm_if_t *encap_id_array,
    113                               int *port_count);
    114 STATIC int
    115 _bcm_esw_multicast_egress_set(int unit, bcm_multicast_t group, int port_count,
    116                             bcm_gport_t *port_array, bcm_if_t *encap_id_array);
    117 
    118 #ifdef BCM_WARM_BOOT_SUPPORT
    119 /* Warm boot scache version to store
    120  * _fabric_multicast_ipmc_group_types array information.
    121  */
    122 #define BCM_FABRIC_IPMC_WB_VERSION_1_0     SOC_SCACHE_VERSION(1,0)
    123 #define BCM_FABRIC_IPMC_WB_DEFAULT_VERSION BCM_FABRIC_IPMC_WB_VERSION_1_0
    124 #endif
    125 
    126 #define BCM_FABRIC_MCAST_BASE(unit) (0)
    127 #define BCM_FABRIC_MCAST_MAX(unit) (_bcm_fabric_mc_info[unit].mcast_size - 1)
    128 #define BCM_FABRIC_IPMC_BASE(unit) (_bcm_fabric_mc_info[unit].mcast_size)
    129 #define BCM_FABRIC_IPMC_MAX(unit) \
    130         (_bcm_fabric_mc_info[unit].mcast_size + \
    131          _bcm_fabric_mc_info[unit].ipmc_size - 1)
    132 #define BCM_FABRIC_MC_USED_BITMAP(unit) \
    133         (_bcm_fabric_mc_info[unit].mcast_used)
    134 #endif	/* BCM_XGS3_FABRIC_SUPPORT */
    135 
    136 #if defined(BCM_FIREBOLT_SUPPORT) || defined(BCM_SCORPION_SUPPORT)
    137 /* Cache of MTU profile size regs */
    138 STATIC soc_profile_reg_t *_bcm_mtu_profile[BCM_MAX_NUM_UNITS];
    139 #endif
    140 
    141 
    142 #if defined(BCM_KATANA_SUPPORT)
    143 STATIC int
    144 _bcm_esw_multicast_egress_subscriber_delete_all(int unit, bcm_multicast_t group);
    145 extern int _bcm_kt_hw_to_sw_queue(int unit, int *queue_array, bcm_port_t *port);
    146 #endif
    147 STATIC int multicast_initialized[BCM_MAX_NUM_UNITS];
    148 #define MULTICAST_INIT_CHECK(unit) \
    149     if (!multicast_initialized[unit]) { \
    150         return BCM_E_INIT; \
    151     }
    152 
    153 int
    154 _bcm_esw_multicast_flags_to_group_type(uint32 flags)
    155 {
    156     int group_type = 0;
    157 
    158     if (flags & BCM_MULTICAST_TYPE_L2) {
    159         group_type = _BCM_MULTICAST_TYPE_L2;
    160     } else if (flags & BCM_MULTICAST_TYPE_L3){
    161         group_type = _BCM_MULTICAST_TYPE_L3;
    162     } else if (flags & BCM_MULTICAST_TYPE_VPLS){
    163         group_type = _BCM_MULTICAST_TYPE_VPLS;
    164     } else if (flags & BCM_MULTICAST_TYPE_SUBPORT){
    165         group_type = _BCM_MULTICAST_TYPE_SUBPORT;
    166     } else if (flags & BCM_MULTICAST_TYPE_MIM){
    167         group_type = _BCM_MULTICAST_TYPE_MIM;
    168     } else if (flags & BCM_MULTICAST_TYPE_WLAN){
    169         group_type = _BCM_MULTICAST_TYPE_WLAN;
    170     } else if (flags & BCM_MULTICAST_TYPE_VLAN) { 
    171         group_type = _BCM_MULTICAST_TYPE_VLAN;
    172     } else if (flags & BCM_MULTICAST_TYPE_TRILL) {
    173         group_type = _BCM_MULTICAST_TYPE_TRILL;
    174     } else if (flags & BCM_MULTICAST_TYPE_NIV) {
    175         group_type = _BCM_MULTICAST_TYPE_NIV;
    176     } else if (flags & BCM_MULTICAST_TYPE_EGRESS_OBJECT) {
    177         group_type = _BCM_MULTICAST_TYPE_EGRESS_OBJECT;
    178     } else if (flags & BCM_MULTICAST_TYPE_L2GRE) {
    179         group_type = _BCM_MULTICAST_TYPE_L2GRE;
    180     } else if (flags & BCM_MULTICAST_TYPE_VXLAN) {
    181         group_type = _BCM_MULTICAST_TYPE_VXLAN;
    182     } else if (flags & BCM_MULTICAST_TYPE_FLOW) {
    183         group_type = _BCM_MULTICAST_TYPE_FLOW;
    184     } else if (flags & BCM_MULTICAST_TYPE_EXTENDER) {
    185         group_type = _BCM_MULTICAST_TYPE_EXTENDER;
    186     }/* Else default to 0 above */
    187 
    188     return group_type;
    189 }
    190 
    191 uint32
    192 _bcm_esw_multicast_group_type_to_flags(int group_type)
    193 {
    194     uint32 flags = 0;
    195 
    196     switch (group_type) {
    197     case _BCM_MULTICAST_TYPE_L2:
    198         flags = BCM_MULTICAST_TYPE_L2;
    199         break;
    200     case _BCM_MULTICAST_TYPE_L3:
    201         flags = BCM_MULTICAST_TYPE_L3;
    202         break;
    203     case _BCM_MULTICAST_TYPE_VPLS:
    204         flags = BCM_MULTICAST_TYPE_VPLS;
    205         break;
    206     case _BCM_MULTICAST_TYPE_SUBPORT:
    207         flags = BCM_MULTICAST_TYPE_SUBPORT;
    208         break;
    209     case _BCM_MULTICAST_TYPE_MIM:
    210         flags = BCM_MULTICAST_TYPE_MIM;
    211         break;
    212     case _BCM_MULTICAST_TYPE_WLAN:
    213         flags = BCM_MULTICAST_TYPE_WLAN;
    214         break;
    215     case _BCM_MULTICAST_TYPE_VLAN:
    216         flags = BCM_MULTICAST_TYPE_VLAN;
    217         break;
    218     case _BCM_MULTICAST_TYPE_TRILL:
    219         flags = BCM_MULTICAST_TYPE_TRILL;
    220         break;
    221     case _BCM_MULTICAST_TYPE_NIV:
    222         flags = BCM_MULTICAST_TYPE_NIV;
    223         break;
    224     case _BCM_MULTICAST_TYPE_EGRESS_OBJECT:
    225         flags = BCM_MULTICAST_TYPE_EGRESS_OBJECT;
    226         break;
    227     case _BCM_MULTICAST_TYPE_L2GRE:
    228         flags = BCM_MULTICAST_TYPE_L2GRE;
    229         break;
    230     case _BCM_MULTICAST_TYPE_VXLAN:
    231         flags = BCM_MULTICAST_TYPE_VXLAN;
    232         break;
    233     case _BCM_MULTICAST_TYPE_FLOW:
    234         flags = BCM_MULTICAST_TYPE_FLOW;
    235         break;
    236     case _BCM_MULTICAST_TYPE_EXTENDER:
    237         flags = BCM_MULTICAST_TYPE_EXTENDER;
    238         break;
    239 
    240     default:
    241         /* flags defaults to 0 above */
    242         break;
    243     }
    244 
    245     return flags;
    246 }
    247 
    248 #ifdef BCM_XGS3_FABRIC_SUPPORT
    249 /*
    250  * Function:
    251  *      _bcm_esw_fabric_multicast_param_check
    252  * Purpose:
    253  *      Validate fabric multicast parameters and adjust HW index.
    254  * Parameters:
    255  *      unit       - (IN)   Device Number
    256  *      group      - (IN) Multicast group ID.
    257  *      mc_id      - (IN/OUT)   multicast index.
    258  * Returns:
    259  *      BCM_E_XXX
    260  */
    261 STATIC int
    262 _bcm_esw_fabric_multicast_param_check(int unit, bcm_multicast_t group,
    263                                       int *mc_index)
    264 {
    265     if (_BCM_MULTICAST_IS_L2(group)) {
    266         /* L2 multicast groups start at index 1 */
    267         if ((*mc_index < BCM_FABRIC_MCAST_BASE(unit)) ||
    268             (*mc_index > BCM_FABRIC_MCAST_MAX(unit))) {
    269             return BCM_E_PARAM;
    270         }
    271     } else if (_BCM_MULTICAST_IS_SET(group)) {
    272         /* Non-L2 groups are offset */
    273         *mc_index += BCM_FABRIC_IPMC_BASE(unit);
    274         if ((*mc_index < BCM_FABRIC_IPMC_BASE(unit)) ||
    275             (*mc_index > BCM_FABRIC_IPMC_MAX(unit))) {
    276             return BCM_E_PARAM;
    277         }
    278     } else {
    279         return BCM_E_PARAM;
    280     }
    281     if (!SHR_BITGET(BCM_FABRIC_MC_USED_BITMAP(unit), *mc_index)) {
    282         return BCM_E_NOT_FOUND;
    283     }
    284     return BCM_E_NONE;
    285 }
    286 #endif	/* BCM_XGS3_FABRIC_SUPPORT */
    287 
    288 /*
    289  * Function:
    290  *      _bcm_esw_multicast_ipmc_read
    291  * Purpose:
    292  *      Read L3 multicast distribuition ports.
    293  * Parameters:
    294  *      unit       - (IN)   Device Number
    295  *      ipmc_id    - (IN)   IPMC index.
    296  *      l2_pbmp    - (IN)   L2 distribution ports.
    297  *      l3_pbmp    - (IN)   L3 distribuition port. 
    298  * Returns:
    299  *      BCM_E_XXX
    300  */
    301 int
    302 _bcm_esw_multicast_ipmc_read(int unit, int ipmc_id, bcm_pbmp_t *l2_pbmp,
    303                              bcm_pbmp_t *l3_pbmp)
    304 {
    305     uint32 entry[SOC_MAX_MEM_FIELD_WORDS];  /* hw entry bufffer. */
    306 
    307     /* Input parameters check. */
    308     if ((NULL == l2_pbmp) || (NULL == l3_pbmp)) {
    309         return (BCM_E_PARAM);
    310     }
    311 
    312     /* Table index sanity check. */
    313     if ((ipmc_id < soc_mem_index_min(unit, L3_IPMCm)) ||
    314         (ipmc_id > soc_mem_index_max(unit, L3_IPMCm))) {
    315         return BCM_E_PARAM;
    316     }
    317 
    318     /* Read L3 ipmc table. */
    319     BCM_IF_ERROR_RETURN(soc_mem_read(unit, L3_IPMCm, MEM_BLOCK_ANY,
    320                                      ipmc_id, entry));
    321 
    322     /* If entry is invalid - clear L2 & L3 bitmaps. */
    323     if (soc_mem_field32_get(unit, L3_IPMCm, entry, VALIDf) == 0) {
    324         BCM_PBMP_CLEAR(*l2_pbmp);
    325         BCM_PBMP_CLEAR(*l3_pbmp);
    326         return (BCM_E_NONE);
    327     }
    328     /* Extract L2 & L3 bitmaps. */
    329     soc_mem_pbmp_field_get(unit, L3_IPMCm, entry, L2_BITMAPf, l2_pbmp);
    330     soc_mem_pbmp_field_get(unit, L3_IPMCm, entry, L3_BITMAPf, l3_pbmp);
    331 
    332     return (BCM_E_NONE);
    333 }
    334 
    335 /*
    336  * Function:
    337  *      _bcm_esw_multicast_ipmc_write
    338  * Purpose:
    339  *      Write L3 multicast distribuition ports.
    340  * Parameters:
    341  *      unit       - (IN)   Device Number
    342  *      ipmc_id    - (IN)   IPMC index.
    343  *      l2_pbmp    - (IN)   L2 distribution ports.
    344  *      l3_pbmp    - (IN)   L3 distribuition port. 
    345  *      valid      - (IN)   Distribuition is valid bit.
    346  * Returns:
    347  *      BCM_E_XXX
    348  */
    349 int
    350 _bcm_esw_multicast_ipmc_write(int unit, int ipmc_id, bcm_pbmp_t l2_pbmp,
    351                               bcm_pbmp_t l3_pbmp, int valid)
    352 {
    353     uint32 entry[SOC_MAX_MEM_FIELD_WORDS];  /* hw entry bufffer. */
    354     int rv;
    355 #if defined(BCM_KATANA_SUPPORT)
    356     int remap_id = 0;
    357 #endif
    358 
    359     sal_memset(&entry, 0, sizeof(ipmc_entry_t));
    360 
    361     /* Currently there is no need to invalidate distribution. */
    362     if (0 == valid) {
    363         BCM_PBMP_CLEAR(l2_pbmp);
    364         BCM_PBMP_CLEAR(l3_pbmp);
    365     }
    366 
    367     /* Table index sanity check. */
    368     if ((ipmc_id < soc_mem_index_min(unit, L3_IPMCm)) ||
    369         (ipmc_id > soc_mem_index_max(unit, L3_IPMCm))) {
    370         return BCM_E_PARAM;
    371     }
    372 
    373     /* Read / Modify / Write section. */
    374     soc_mem_lock(unit, L3_IPMCm);
    375     rv = soc_mem_read(unit, L3_IPMCm, MEM_BLOCK_ANY, ipmc_id, entry);
    376     if (BCM_SUCCESS(rv)) {
    377 #if defined(BCM_KATANA_SUPPORT)
    378         if (SOC_IS_KATANAX(unit)) {
    379             remap_id = soc_mem_field32_get(unit, L3_IPMCm, entry,
    380                                     MMU_MC_REDIRECTION_PTRf);
    381             if (soc_mem_field32_get(unit, L3_IPMCm, entry, VALIDf) == 0 || !valid) {
    382                 /* Invalid entry, flush */
    383                 sal_memset(&entry, 0, sizeof(ipmc_entry_t)); 
    384                 if (remap_id) {
    385                      soc_mem_field32_set(unit, L3_IPMCm, entry,
    386                                     MMU_MC_REDIRECTION_PTRf, remap_id);
    387                 }
    388             } 
    389             soc_mem_field32_set(unit, L3_IPMCm, entry, VALIDf, valid);
    390             if ((0 == soc_mem_field32_get(unit, L3_IPMCm, entry,
    391                                           MMU_MC_REDIRECTION_PTRf))) {
    392                 soc_mem_field32_set(unit, L3_IPMCm, entry,
    393                                     MMU_MC_REDIRECTION_PTRf, ipmc_id);
    394             }
    395         } else
    396 #endif
    397         {
    398             if (soc_mem_field32_get(unit, L3_IPMCm, entry, VALIDf) == 0 || !valid) {
    399                 /* Invalid entry, flush */
    400                 sal_memset(&entry, 0, sizeof(ipmc_entry_t));
    401             }
    402             soc_mem_field32_set(unit, L3_IPMCm, entry, VALIDf, valid); 
    403         }
    404     }
    405 
    406     soc_mem_pbmp_field_set(unit, L3_IPMCm, entry, L2_BITMAPf, &l2_pbmp);
    407     soc_mem_pbmp_field_set(unit, L3_IPMCm, entry, L3_BITMAPf, &l3_pbmp);
    408 
    409 #if defined(BCM_TRIDENT3_SUPPORT)
    410     if (SOC_MEM_FIELD_VALID(unit, L3_IPMCm, L2_L3f) &&
    411         BCM_PBMP_NOT_NULL(l3_pbmp)) {
    412         uint32 cancun_ver;
    413 
    414         BCM_IF_ERROR_RETURN(soc_cancun_version_get(unit, &cancun_ver));
    415 
    416         if (cancun_ver < SOC_CANCUN_VERSION_DEF_5_3_2) {
    417             soc_mem_field32_set(unit, L3_IPMCm, entry, L2_L3f, 1);
    418         }
    419     }
    420 #endif
    421 
    422     rv = soc_mem_write(unit, L3_IPMCm, MEM_BLOCK_ALL, ipmc_id, &entry);
    423 
    424     soc_mem_unlock(unit, L3_IPMCm);
    425 
    426 #if defined(BCM_BRADLEY_SUPPORT)
    427     if (BCM_SUCCESS(rv) && (SOC_IS_HBX(unit) || SOC_IS_TD_TT(unit)) &&
    428         !(soc_feature(unit, soc_feature_l2mc_table_no_shared_ipmc))) {
    429         /* On these devices, the Higig packets use the L2MC table with
    430          * IPMC offset to get the L2 bitmap. */
    431         int		mc_base, mc_size, mc_index;
    432         l2mc_entry_t	l2mc;
    433 
    434         SOC_IF_ERROR_RETURN
    435             (soc_hbx_ipmc_size_get(unit, &mc_base, &mc_size));
    436         /* coverity[check_after_sink] */
    437         if (ipmc_id < 0 || ipmc_id > mc_size) {
    438             return BCM_E_PARAM;
    439         }
    440         mc_index = ipmc_id + mc_base;
    441 
    442         soc_mem_lock(unit, L2MCm);
    443         if (!valid) {
    444             rv = WRITE_L2MCm(unit, MEM_BLOCK_ALL, mc_index,
    445                     soc_mem_entry_null(unit, L2MCm));
    446         } else {
    447             rv = READ_L2MCm(unit, MEM_BLOCK_ANY, mc_index, &l2mc);
    448             if (rv >= 0) {
    449                 soc_mem_pbmp_field_set(unit, L2MCm, &l2mc,
    450                         PORT_BITMAPf, &l2_pbmp);
    451                 soc_mem_field32_set(unit, L2MCm, &l2mc, VALIDf, 1);
    452                 rv = WRITE_L2MCm(unit, MEM_BLOCK_ALL, mc_index, &l2mc);
    453             }
    454         }
    455         soc_mem_unlock(unit, L2MCm);
    456     }
    457 #endif /* BCM_BRADLEY_SUPPORT */
    458 
    459     return rv;
    460 }
    461 
    462 /*
    463  * Function:
    464  *      _bcm_esw_ipmc_egress_intf_add
    465  * Purpose:
    466  *      Helper function to add ipmc egress interface on different devices.
    467  * Parameters:
    468  *      unit       - (IN)  Device Number
    469  *      ipmc_id    - (IN)  ipmc id
    470  *      port       - (IN)  Port number
    471  *      nh_index   - (IN)  Next Hop index
    472  *      is_l3      - (IN)  Indicates if multicast group type is IPMC.
    473  * Returns:
    474  *      BCM_E_XXX
    475  */
    476 int
    477 _bcm_esw_ipmc_egress_intf_add(int unit, int ipmc_id, bcm_port_t port,
    478                           int nh_index, int is_l3)
    479 {
    480 #if defined (INCLUDE_L3)
    481 #if defined(BCM_TOMAHAWK3_SUPPORT)
    482     if (SOC_IS_TOMAHAWK3(unit)) {
    483         uint16 dev_id;
    484         uint8 rev_id;
    485         int local_port, intf_max, port_intf_count;
    486         int rv = BCM_E_NONE;
    487         int alloc_size;
    488         bcm_if_t *port_intf_array = NULL;
    489         bcm_pbmp_t l2_pbmp, l3_pbmp, pbmp_all;
    490         soc_info_t *si = &SOC_INFO(unit);
    491         uint32 itm_map = si->itm_map;
    492         int itm;
    493         bcm_pbmp_t link_bmap;
    494         uint32 entry[SOC_MAX_MEM_FIELD_WORDS];
    495 
    496         soc_cm_get_id(unit, &dev_id, &rev_id);
    497         if (rev_id != BCM56980_A0_REV_ID && dev_id != BCM56983_DEVICE_ID) {
    498             intf_max = TH3_IPMC_MAX_INTF_COUNT;
    499 
    500             /*Allocate intf array for intfs*/
    501             alloc_size = intf_max * sizeof(bcm_if_t);
    502             port_intf_array = sal_alloc(alloc_size, "IPMC group, port intfs array");
    503             if (port_intf_array == NULL) {
    504                 return BCM_E_MEMORY;
    505             }
    506             BCM_PBMP_CLEAR(pbmp_all);
    507             BCM_PBMP_ASSIGN(pbmp_all, PBMP_ALL(unit));
    508             PBMP_ITER(pbmp_all, local_port) {
    509                 if (!IS_LB_PORT(unit, local_port)) {
    510                     port_intf_count = 0;
    511                     /* retrieve the interface id array for the {group, port} */
    512                     rv = bcm_esw_ipmc_egress_intf_get(unit, ipmc_id, local_port,
    513                             intf_max, port_intf_array, &port_intf_count);
    514                     if (rv != BCM_E_NONE) {
    515                         sal_free(port_intf_array);
    516                         return rv;
    517                     }
    518                     if ((local_port == port) && (port_intf_count < intf_max)) {
    519                         /* Current port is the port for new encap id addition */
    520                         /* Current interface list doesnt have all the interface
    521                          * ids */
    522                         port_intf_array[port_intf_count] = nh_index;
    523                         port_intf_count++;
    524                     }
    525                     /* Add the new port, intf list to group 0*/
    526                     if (port_intf_count > 0) {
    527                         rv = _bcm_esw_ipmc_egress_intf_set(unit, 0, local_port,
    528                                 port_intf_count, port_intf_array, 1, FALSE);
    529                         if (rv != BCM_E_NONE) {
    530                             sal_free(port_intf_array);
    531                             return rv;
    532                         }
    533                     }
    534                 }
    535             }
    536             /* Free memory for interface array as it is not needed further*/
    537             sal_free(port_intf_array);
    538             /* Add port 158 to IP's  EPC_LINK_BMAP */
    539             soc_mem_lock(unit, EPC_LINK_BMAPm);
    540             rv = soc_mem_read(unit, EPC_LINK_BMAPm, MEM_BLOCK_ANY, 0, entry);
    541             if (rv != BCM_E_NONE) {
    542                 soc_mem_unlock(unit, EPC_LINK_BMAPm);
    543                 return rv;
    544             }
    545             soc_mem_pbmp_field_get(unit, EPC_LINK_BMAPm, entry, PORT_BITMAPf,
    546                     &link_bmap);
    547             BCM_PBMP_PORT_ADD(link_bmap, 158);
    548             soc_mem_pbmp_field_set(unit, EPC_LINK_BMAPm, entry, PORT_BITMAPf,
    549                     &link_bmap);
    550             rv = soc_mem_write(unit, EPC_LINK_BMAPm, MEM_BLOCK_ALL, 0, &entry);
    551             soc_mem_unlock(unit, EPC_LINK_BMAPm);
    552             if (rv != BCM_E_NONE) {
    553                 return rv;
    554             }
    555 
    556             /* Add port 158 to IP's  ING_DEST_PORT_ENABLE */
    557             soc_mem_lock(unit, ING_DEST_PORT_ENABLEm);
    558             rv = soc_mem_read(unit, ING_DEST_PORT_ENABLEm, MEM_BLOCK_ANY,
    559                                      0, entry);
    560             if (rv != BCM_E_NONE) {
    561                 soc_mem_unlock(unit, ING_DEST_PORT_ENABLEm);
    562                 return rv;
    563             }
    564             soc_mem_pbmp_field_get(unit, ING_DEST_PORT_ENABLEm, entry, PORT_BITMAPf,
    565                     &link_bmap);
    566             BCM_PBMP_PORT_ADD(link_bmap, 158);
    567             soc_mem_pbmp_field_set(unit, ING_DEST_PORT_ENABLEm, entry, PORT_BITMAPf,
    568                     &link_bmap);
    569             rv = soc_mem_write(unit, ING_DEST_PORT_ENABLEm, MEM_BLOCK_ALL, 0,
    570                         &entry);
    571             soc_mem_unlock(unit, ING_DEST_PORT_ENABLEm);
    572             if (rv != BCM_E_NONE) {
    573                 return rv;
    574             }
    575             /* Add port 158 to the IPMC_L3_BITMAP  */
    576             soc_mem_lock(unit, L3_IPMCm);
    577             rv = _bcm_esw_multicast_ipmc_read(unit, ipmc_id, &l2_pbmp, &l3_pbmp);
    578             if (rv != BCM_E_NONE) {
    579                 return rv;
    580             }
    581             BCM_PBMP_PORT_ADD(l3_pbmp, 158);
    582             rv = _bcm_esw_multicast_ipmc_write(unit, ipmc_id, l2_pbmp,
    583                                                l3_pbmp, TRUE);
    584             soc_mem_unlock(unit, L3_IPMCm);
    585 
    586             if (rv != BCM_E_NONE) {
    587                 return rv;
    588             }
    589             if (!SAL_BOOT_SIMULATION) {
    590                 /* mmu rqe Flush*/
    591                 for (itm = 0; itm < NUM_ITM(unit); itm++) {
    592                     if (itm_map & (1 << itm)) {
    593                         /* Issue RQE flush twice per each ITM*/
    594                        rv = soc_tomahawk3_mmu_rqe_port_flush(unit, itm, 1);
    595                        if (rv != BCM_E_NONE) {
    596                            return rv;
    597                        }
    598                        rv = soc_tomahawk3_mmu_rqe_port_flush(unit, itm, 2);
    599                        if (rv != BCM_E_NONE) {
    600                            return rv;
    601                        }
    602                     }
    603                 }
    604             }
    605             /* Update the repl group to add new repl_id to the port*/
    606             BCM_IF_ERROR_RETURN(_bcm_th_ipmc_egress_intf_add(unit, ipmc_id, port,
    607                         nh_index, is_l3));
    608 
    609              /* Remove port 158 from the IPMC_L3_BITMAP  */
    610             soc_mem_lock(unit, L3_IPMCm);
    611             rv = _bcm_esw_multicast_ipmc_read(unit, ipmc_id, &l2_pbmp, &l3_pbmp);
    612             if (rv != BCM_E_NONE) {
    613                 soc_mem_unlock(unit, L3_IPMCm);
    614                 return rv;
    615             }
    616             BCM_PBMP_PORT_REMOVE(l3_pbmp, 158);
    617             rv = _bcm_esw_multicast_ipmc_write(unit, ipmc_id, l2_pbmp,
    618                                                l3_pbmp, TRUE);
    619             soc_mem_unlock(unit, L3_IPMCm);
    620             if (rv != BCM_E_NONE) {
    621                 return rv;
    622             }
    623 
    624             /* Remove port 158 from IP's EPC_LINK_BMAP */
    625             soc_mem_lock(unit, EPC_LINK_BMAPm);
    626             rv = soc_mem_read(unit, EPC_LINK_BMAPm, MEM_BLOCK_ANY, 0, entry);
    627             if (rv != BCM_E_NONE) {
    628                 soc_mem_unlock(unit, EPC_LINK_BMAPm);
    629                 return rv;
    630             }
    631             soc_mem_pbmp_field_get(unit, EPC_LINK_BMAPm, entry, PORT_BITMAPf,
    632                     &link_bmap);
    633             BCM_PBMP_PORT_REMOVE(link_bmap, 158);
    634             soc_mem_pbmp_field_set(unit, EPC_LINK_BMAPm, entry, PORT_BITMAPf,
    635                     &link_bmap);
    636             rv = soc_mem_write(unit, EPC_LINK_BMAPm, MEM_BLOCK_ALL, 0,
    637                         &entry);
    638             soc_mem_unlock(unit, EPC_LINK_BMAPm);
    639             if (rv != BCM_E_NONE) {
    640                 return rv;
    641             }
    642 
    643             /* Remove port 158 from IP's  ING_DEST_PORT_ENABLE */
    644             soc_mem_lock(unit, ING_DEST_PORT_ENABLEm);
    645             rv = soc_mem_read(unit, ING_DEST_PORT_ENABLEm, MEM_BLOCK_ANY,
    646                                      0, entry);
    647             if (rv != BCM_E_NONE) {
    648                 soc_mem_unlock(unit, ING_DEST_PORT_ENABLEm);
    649                 return rv;
    650             }
    651             soc_mem_pbmp_field_get(unit, ING_DEST_PORT_ENABLEm, entry, PORT_BITMAPf,
    652                     &link_bmap);
    653             BCM_PBMP_PORT_REMOVE(link_bmap, 158);
    654             soc_mem_pbmp_field_set(unit, ING_DEST_PORT_ENABLEm, entry, PORT_BITMAPf,
    655                     &link_bmap);
    656             rv = soc_mem_write(unit, ING_DEST_PORT_ENABLEm, MEM_BLOCK_ALL, 0,
    657                         &entry);
    658             soc_mem_unlock(unit, ING_DEST_PORT_ENABLEm);
    659             if (rv != BCM_E_NONE) {
    660                 return rv;
    661             }
    662 
    663 
    664             if (!SAL_BOOT_SIMULATION) {
    665                 /* mmu rqe Flush*/
    666                 for (itm = 0; itm < NUM_ITM(unit); itm++) {
    667                     if (itm_map & (1 << itm)) {
    668                         /* Issue RQE flush twice per each ITM*/
    669                        rv = soc_tomahawk3_mmu_rqe_port_flush(unit, itm, 1);
    670                        if (rv != BCM_E_NONE) {
    671                            return rv;
    672                        }
    673                        rv = soc_tomahawk3_mmu_rqe_port_flush(unit, itm, 2);
    674                        if (rv != BCM_E_NONE) {
    675                            return rv;
    676                        }
    677                     }
    678                 }
    679             }
    680 
    681             /* reset programming in repl group 0*/
    682             PBMP_ITER(pbmp_all, local_port) {
    683                 if (!IS_LB_PORT(unit, local_port)) {
    684                     rv = _bcm_esw_ipmc_egress_intf_set(unit, 0, local_port, 0,
    685                             NULL, 1, FALSE);
    686                     if (rv != BCM_E_NONE) {
    687                             return rv;
    688                     }
    689                 }
    690             }
    691 
    692             return rv;
    693 
    694         } else {
    695             return _bcm_th_ipmc_egress_intf_add(unit, ipmc_id, port, nh_index,
    696                                              is_l3);
    697         }
    698     }
    699 #endif /* BCM_TOMAHAWK3_SUPPORT*/
    700 #if defined(BCM_TOMAHAWK_SUPPORT)
    701     if ((SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) &&
    702             !(SOC_IS_TOMAHAWK3(unit))) {
    703         return _bcm_th_ipmc_egress_intf_add(unit, ipmc_id, port, nh_index,
    704                                              is_l3);
    705     }
    706 #endif /* BCM_TOMAHAWK_SUPPORT */
    707 #if defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_KATANA2_SUPPORT)
    708     if (SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT2X(unit) ||
    709         SOC_IS_KATANA2(unit)) {
    710         return _bcm_tr3_ipmc_egress_intf_add(unit, ipmc_id, port, nh_index,
    711                                              is_l3);
    712     }
    713 #endif /* BCM_TRIUMPH3_SUPPORT */
    714 #if defined(BCM_TRIUMPH2_SUPPORT) 
    715     if (SOC_IS_TRIUMPH2(unit) || SOC_IS_VALKYRIE2(unit) ||
    716         SOC_IS_APOLLO(unit) || SOC_IS_TD_TT(unit) ||
    717         SOC_IS_KATANA(unit)) {
    718         return _bcm_tr2_ipmc_egress_intf_add(unit, ipmc_id, port, nh_index);
    719     }
    720 #endif
    721 #if defined(BCM_FIREBOLT_SUPPORT)
    722     return _bcm_fb_ipmc_egress_intf_add(unit, ipmc_id, port, nh_index, is_l3);
    723 #endif /* BCM_FIREBOLT_SUPPORT */
    724 #endif /* INCLUDE_L3 */
    725     return BCM_E_UNAVAIL;
    726 }
    727 
    728 
    729 /*
    730  * Function:
    731  *      _bcm_esw_ipmc_egress_intf_delete
    732  * Purpose:
    733  *      Helper function to delete ipmc egress interface on different devices.
    734  * Parameters:
    735  *      unit       - (IN)   Device Number
    736  *      ipmc_id    - (IN)   ipmc id
    737  *      port       - (IN)  Port number
    738  *      if_max     - (IN)  Maximal interface
    739  *      nh_index   - (IN)  Next Hop index
    740  *      is_l3      - (IN)  Indicates if multicast group type is IPMC.
    741  * Returns:
    742  *      BCM_E_XXX
    743  */
    744 int _bcm_esw_ipmc_egress_intf_delete(int unit, int ipmc_id,
    745                                  bcm_port_t port, int if_max,
    746                                  int nh_index, int is_l3)
    747 {
    748 #if defined (INCLUDE_L3)
    749 #if defined(BCM_TOMAHAWK3_SUPPORT)
    750     if (SOC_IS_TOMAHAWK3(unit)) {
    751         uint16 dev_id;
    752         uint8 rev_id;
    753         int local_port, intf_max, port_intf_count;
    754         int rv = BCM_E_NONE;
    755         int alloc_size;
    756         bcm_if_t *port_intf_array = NULL;
    757         bcm_pbmp_t l2_pbmp, l3_pbmp, pbmp_all;
    758         soc_info_t *si = &SOC_INFO(unit);
    759         uint32 itm_map = si->itm_map;
    760         int itm, intf_loop, intf_del_idx = -1;
    761         bcm_pbmp_t link_bmap;
    762         uint32 entry[SOC_MAX_MEM_FIELD_WORDS];
    763 
    764         soc_cm_get_id(unit, &dev_id, &rev_id);
    765         if (rev_id != BCM56980_A0_REV_ID) {
    766             intf_max = TH3_IPMC_MAX_INTF_COUNT;
    767 
    768             /*Allocate intf array for intfs*/
    769             alloc_size = intf_max * sizeof(bcm_if_t);
    770             port_intf_array = sal_alloc(alloc_size, "IPMC group, port intfs array");
    771             if (port_intf_array == NULL) {
    772                 return BCM_E_MEMORY;
    773             }
    774             BCM_PBMP_CLEAR(pbmp_all);
    775             BCM_PBMP_ASSIGN(pbmp_all, PBMP_ALL(unit));
    776             PBMP_ITER(pbmp_all, local_port) {
    777                 if (!IS_LB_PORT(unit, local_port)) {
    778                     port_intf_count = 0;
    779                     /* retrieve the interface id array for the {group, port} */
    780                     rv = bcm_esw_ipmc_egress_intf_get(unit, ipmc_id, local_port,
    781                             intf_max, port_intf_array, &port_intf_count);
    782                     if (rv != BCM_E_NONE) {
    783                         sal_free(port_intf_array);
    784                         return rv;
    785                     }
    786                     if (local_port == port) {
    787                         /* Current port is the port for new encap id removal */
    788                         for (intf_loop = 0; intf_loop < port_intf_count;
    789                                 intf_loop++) {
    790                             if (port_intf_array[intf_loop] == nh_index) {
    791                                 intf_del_idx = intf_loop;
    792                                 break;
    793                             }
    794                         }
    795                         if (intf_del_idx != -1) {
    796                             for (intf_loop = intf_del_idx;
    797                                     intf_loop < port_intf_count;
    798                                     intf_loop++) {
    799                                 port_intf_array[intf_loop] =
    800                                     port_intf_array[(intf_loop + 1)];
    801                             }
    802                             port_intf_count--;
    803                         }
    804                     }
    805                     if (port_intf_count > 0) {
    806                         rv = _bcm_esw_ipmc_egress_intf_set(unit, 0, local_port,
    807                                 port_intf_count, port_intf_array, 1, FALSE);
    808                         if (rv != BCM_E_NONE) {
    809                             sal_free(port_intf_array);
    810                             return rv;
    811                         }
    812                     }
    813                 }
    814             }
    815             /*Free memory reserved for interafce array*/
    816             sal_free(port_intf_array);
    817                         /* Add port 158 to IP's  EPC_LINK_BMAP */
    818             soc_mem_lock(unit, EPC_LINK_BMAPm);
    819             rv = soc_mem_read(unit, EPC_LINK_BMAPm, MEM_BLOCK_ANY, 0, entry);
    820             if (rv != BCM_E_NONE) {
    821                 soc_mem_unlock(unit, EPC_LINK_BMAPm);
    822                 return rv;
    823             }
    824             soc_mem_pbmp_field_get(unit, EPC_LINK_BMAPm, entry, PORT_BITMAPf,
    825                     &link_bmap);
    826             BCM_PBMP_PORT_ADD(link_bmap, 158);
    827             soc_mem_pbmp_field_set(unit, EPC_LINK_BMAPm, entry, PORT_BITMAPf,
    828                     &link_bmap);
    829             rv = soc_mem_write(unit, EPC_LINK_BMAPm, MEM_BLOCK_ALL, 0, &entry);
    830             soc_mem_unlock(unit, EPC_LINK_BMAPm);
    831             if (rv != BCM_E_NONE) {
    832                 return rv;
    833             }
    834 
    835             /* Add port 158 to IP's  ING_DEST_PORT_ENABLE */
    836             soc_mem_lock(unit, ING_DEST_PORT_ENABLEm);
    837             rv = soc_mem_read(unit, ING_DEST_PORT_ENABLEm, MEM_BLOCK_ANY,
    838                                      0, entry);
    839             if (rv != BCM_E_NONE) {
    840                 soc_mem_unlock(unit, ING_DEST_PORT_ENABLEm);
    841                 return rv;
    842             }
    843             soc_mem_pbmp_field_get(unit, ING_DEST_PORT_ENABLEm, entry, PORT_BITMAPf,
    844                     &link_bmap);
    845             BCM_PBMP_PORT_ADD(link_bmap, 158);
    846             soc_mem_pbmp_field_set(unit, ING_DEST_PORT_ENABLEm, entry, PORT_BITMAPf,
    847                     &link_bmap);
    848             rv = soc_mem_write(unit, ING_DEST_PORT_ENABLEm, MEM_BLOCK_ALL, 0,
    849                         &entry);
    850             soc_mem_unlock(unit, ING_DEST_PORT_ENABLEm);
    851             if (rv != BCM_E_NONE) {
    852                 return rv;
    853             }
    854             /* Add port 158 to the IPMC_L3_BITMAP  */
    855             soc_mem_lock(unit, L3_IPMCm);
    856             rv = _bcm_esw_multicast_ipmc_read(unit, ipmc_id, &l2_pbmp, &l3_pbmp);
    857             if (rv != BCM_E_NONE) {
    858                 soc_mem_unlock(unit, L3_IPMCm);
    859                 return rv;
    860             }
    861             BCM_PBMP_PORT_ADD(l3_pbmp, 158);
    862             rv = _bcm_esw_multicast_ipmc_write(unit, ipmc_id, l2_pbmp,
    863                                                l3_pbmp, TRUE);
    864             soc_mem_unlock(unit, L3_IPMCm);
    865 
    866             if (rv != BCM_E_NONE) {
    867                 return rv;
    868             }
    869             if (!SAL_BOOT_SIMULATION) {
    870                 /* mmu rqe Flush*/
    871                 for (itm = 0; itm < NUM_ITM(unit); itm++) {
    872                     if (itm_map & (1 << itm)) {
    873                         /* Issue RQE flush twice per each ITM*/
    874                        rv = soc_tomahawk3_mmu_rqe_port_flush(unit, itm, 1);
    875                        if (rv != BCM_E_NONE) {
    876                            return rv;
    877                        }
    878                        rv = soc_tomahawk3_mmu_rqe_port_flush(unit, itm, 2);
    879                        if (rv != BCM_E_NONE) {
    880                            return rv;
    881                        }
    882                     }
    883                 }
    884             }
    885             /* Update the repl group to add new repl_id to the port*/
    886             BCM_IF_ERROR_RETURN(_bcm_th_ipmc_egress_intf_delete(unit, ipmc_id,
    887                         port, intf_max, nh_index, is_l3));
    888 
    889              /* Remove port 158 from the IPMC_L3_BITMAP  */
    890             soc_mem_lock(unit, L3_IPMCm);
    891             rv = _bcm_esw_multicast_ipmc_read(unit, ipmc_id, &l2_pbmp, &l3_pbmp);
    892             if (rv != BCM_E_NONE) {
    893                 soc_mem_unlock(unit, L3_IPMCm);
    894                 return rv;
    895             }
    896             BCM_PBMP_PORT_REMOVE(l3_pbmp, 158);
    897             rv = _bcm_esw_multicast_ipmc_write(unit, ipmc_id, l2_pbmp,
    898                                                l3_pbmp, TRUE);
    899             soc_mem_unlock(unit, L3_IPMCm);
    900             if (rv != BCM_E_NONE) {
    901                 return rv;
    902             }
    903             /* Remove port 158 from IP's EPC_LINK_BMAP */
    904             soc_mem_lock(unit, EPC_LINK_BMAPm);
    905             rv = soc_mem_read(unit, EPC_LINK_BMAPm, MEM_BLOCK_ANY, 0, entry);
    906             if (rv != BCM_E_NONE) {
    907                 soc_mem_unlock(unit, EPC_LINK_BMAPm);
    908                 return rv;
    909             }
    910             soc_mem_pbmp_field_get(unit, EPC_LINK_BMAPm, entry, PORT_BITMAPf,
    911                     &link_bmap);
    912             BCM_PBMP_PORT_REMOVE(link_bmap, 158);
    913             soc_mem_pbmp_field_set(unit, EPC_LINK_BMAPm, entry, PORT_BITMAPf,
    914                     &link_bmap);
    915             rv = soc_mem_write(unit, EPC_LINK_BMAPm, MEM_BLOCK_ALL, 0,
    916                         &entry);
    917             soc_mem_unlock(unit, EPC_LINK_BMAPm);
    918             if (rv != BCM_E_NONE) {
    919                 return rv;
    920             }
    921 
    922             /* Remove port 158 from IP's  ING_DEST_PORT_ENABLE */
    923             soc_mem_lock(unit, ING_DEST_PORT_ENABLEm);
    924             rv = soc_mem_read(unit, ING_DEST_PORT_ENABLEm, MEM_BLOCK_ANY,
    925                                      0, entry);
    926             if (rv != BCM_E_NONE) {
    927                 soc_mem_unlock(unit, ING_DEST_PORT_ENABLEm);
    928                 return rv;
    929             }
    930             soc_mem_pbmp_field_get(unit, ING_DEST_PORT_ENABLEm, entry, PORT_BITMAPf,
    931                     &link_bmap);
    932             BCM_PBMP_PORT_REMOVE(link_bmap, 158);
    933             soc_mem_pbmp_field_set(unit, ING_DEST_PORT_ENABLEm, entry, PORT_BITMAPf,
    934                     &link_bmap);
    935             rv = soc_mem_write(unit, ING_DEST_PORT_ENABLEm, MEM_BLOCK_ALL, 0,
    936                         &entry);
    937             soc_mem_unlock(unit, ING_DEST_PORT_ENABLEm);
    938             if (rv != BCM_E_NONE) {
    939                 return rv;
    940             }
    941 
    942             if (!SAL_BOOT_SIMULATION) {
    943                 /* mmu rqe Flush*/
    944                 for (itm = 0; itm < NUM_ITM(unit); itm++) {
    945                     if (itm_map & (1 << itm)) {
    946                         /* Issue RQE flush twice per each ITM*/
    947                        rv = soc_tomahawk3_mmu_rqe_port_flush(unit, itm, 1);
    948                        if (rv != BCM_E_NONE) {
    949                            return rv;
    950                        }
    951                        rv = soc_tomahawk3_mmu_rqe_port_flush(unit, itm, 2);
    952                        if (rv != BCM_E_NONE) {
    953                            return rv;
    954                        }
    955                     }
    956                 }
    957             }
    958             /* reset programming in repl group 0*/
    959             PBMP_ITER(pbmp_all, local_port) {
    960                 if (!IS_LB_PORT(unit, local_port)) {
    961                     rv = _bcm_esw_ipmc_egress_intf_set(unit, 0, local_port, 0,
    962                             NULL, 1, FALSE);
    963                     if (rv != BCM_E_NONE) {
    964                             return rv;
    965                     }
    966                 }
    967             }
    968 
    969             return rv;
    970 
    971         } else {
    972             return _bcm_th_ipmc_egress_intf_delete(unit, ipmc_id, port,
    973                     if_max, nh_index, is_l3);
    974         }
    975     }
    976 #endif /* BCM_TOMAHAWK3_SUPPORT*/
    977 
    978 #if defined(BCM_TOMAHAWK_SUPPORT)
    979     if ((SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) &&
    980             (!SOC_IS_TOMAHAWK3(unit))) {
    981         return _bcm_th_ipmc_egress_intf_delete(unit, ipmc_id, port,
    982                                                 if_max, nh_index, is_l3);
    983     }
    984 #endif /* BCM_TOMAHAWK_SUPPORT */
    985 #if defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_KATANA2_SUPPORT)
    986     if (SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT2X(unit) ||
    987         SOC_IS_KATANA2(unit))     {
    988         return _bcm_tr3_ipmc_egress_intf_delete(unit, ipmc_id, port,
    989                                                 if_max, nh_index, is_l3);
    990     }
    991 #endif /* BCM_TRIUMPH3_SUPPORT */
    992 #if defined(BCM_TRIUMPH2_SUPPORT) 
    993     if (SOC_IS_TRIUMPH2(unit) || SOC_IS_VALKYRIE2(unit) ||
    994         SOC_IS_APOLLO(unit) || SOC_IS_TD_TT(unit) || SOC_IS_KATANA(unit)) {
    995         return _bcm_tr2_ipmc_egress_intf_delete(unit, ipmc_id, port, 
    996                                                 if_max, nh_index);
    997     }
    998 #endif
    999 #if defined(BCM_FIREBOLT_SUPPORT)
   1000     return _bcm_fb_ipmc_egress_intf_delete(unit, ipmc_id, port,
   1001                                            if_max, nh_index, is_l3);
   1002 #endif /* BCM_FIREBOLT_SUPPORT */
   1003  #endif /* INCLUDE_L3 */
   1004     return BCM_E_UNAVAIL;
   1005 }
   1006 
   1007 #ifdef BCM_WARM_BOOT_SUPPORT
   1008 #ifdef BCM_XGS3_FABRIC_SUPPORT
   1009 /*
   1010  * Function:
   1011  *      _bcm_fabric_multicast_sync
   1012  * Purpose:
   1013  *      Record Fabric's Multicast module persistent info for Level 2 Warm Boot
   1014  * Parameters:
   1015  *      unit - Device number.
   1016  * Returns:
   1017  *      BCM_E_XXX
   1018  */
   1019 int
   1020 _bcm_fabric_multicast_sync(int unit)
   1021 {
   1022     int ipmc_mem_size = 0, ipmc_base, alloc_size;
   1023     soc_scache_handle_t scache_handle;
   1024     uint8               *multicast_scache;
   1025 
   1026     if (SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) {
   1027         return BCM_E_NONE;
   1028     }
   1029 
   1030     SOC_IF_ERROR_RETURN
   1031         (soc_hbx_ipmc_size_get(unit, &ipmc_base, &ipmc_mem_size));
   1032 
   1033     alloc_size = ipmc_mem_size * sizeof(uint8);
   1034 
   1035     SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_MULTICAST, 0);
   1036     BCM_IF_ERROR_RETURN
   1037         (_bcm_esw_scache_ptr_get(unit, scache_handle, FALSE,
   1038                                  0,
   1039                                  &multicast_scache,
   1040                                  BCM_FABRIC_IPMC_WB_DEFAULT_VERSION, NULL));
   1041 
   1042     if (_fabric_multicast_ipmc_group_types[unit] != NULL) {
   1043         sal_memcpy(multicast_scache, _fabric_multicast_ipmc_group_types[unit],
   1044                 alloc_size);
   1045     }
   1046 
   1047     return BCM_E_NONE;
   1048 }
   1049 #endif
   1050 /*
   1051  * Function:
   1052  *      _bcm_esw_multicast_sync
   1053  * Purpose:
   1054  *      Record Multicast module persisitent info for Level 2 Warm Boot
   1055  * Parameters:
   1056  *      unit - StrataSwitch unit number.
   1057  * Returns:
   1058  *      BCM_E_XXX
   1059  */
   1060 int
   1061 _bcm_esw_multicast_sync(int unit)
   1062 {
   1063 #ifdef BCM_XGS3_FABRIC_SUPPORT
   1064     if(SOC_IS_XGS3_FABRIC(unit)){
   1065         return _bcm_fabric_multicast_sync(unit);
   1066     }
   1067 #endif
   1068 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3)
   1069     if (SOC_IS_TRX(unit) && !SOC_IS_XGS3_FABRIC(unit)) {
   1070         return _bcm_trx_multicast_sync(unit);
   1071     }
   1072 #endif /* BCM_TRX_SUPPORT && INCLUDE_L3 */
   1073     return BCM_E_NONE;
   1074 }
   1075 #endif /* BCM_WARM_BOOT_SUPPORT */
   1076 
   1077 
   1078 #if defined(BCM_XGS3_SWITCH_SUPPORT) 
   1079 
   1080 /*
   1081  * Function:
   1082  *      _bcm_esw_multicast_l2_add
   1083  * Purpose:
   1084  *      Helper function to add a port to L2 multicast group
   1085  * Parameters:
   1086  *      unit      - (IN) Device Number
   1087  *      group     - (IN) Multicast group ID
   1088  *      port      - (IN) GPORT Identifier
   1089  *      encap_id  - (IN) Encap ID.
   1090  * Returns:
   1091  *      BCM_E_XXX
   1092  */
   1093 STATIC int 
   1094 _bcm_esw_multicast_l2_add(int unit, bcm_multicast_t group, 
   1095                           bcm_port_t port, bcm_if_t encap_id)
   1096 {
   1097     l2mc_entry_t    l2mc_entry;
   1098     bcm_pbmp_t      l2_pbmp;
   1099     int             mc_index, gport_id, modid_local, idx, trunk_local_ports = 0;
   1100     bcm_module_t    mod_out;
   1101     bcm_port_t      port_out;
   1102 #if defined(BCM_ESW_SUPPORT) && (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS)
   1103     bcm_port_t      local_trunk_member_ports[SOC_MAX_NUM_PP_PORTS] = {0};
   1104     int             max_num_ports = SOC_MAX_NUM_PP_PORTS;
   1105 #else
   1106     bcm_port_t      local_trunk_member_ports[SOC_MAX_NUM_PORTS] = {0};
   1107     int             max_num_ports = SOC_MAX_NUM_PORTS;
   1108 #endif
   1109     bcm_trunk_t     trunk_id;
   1110 #if defined(BCM_KATANA2_SUPPORT)
   1111     int is_local_subport = FALSE, pp_port;
   1112 #endif
   1113  
   1114     modid_local = 0;
   1115 
   1116     mc_index = _BCM_MULTICAST_ID_GET(group);
   1117 
   1118     /* Table index sanity check. */
   1119 #ifdef BCM_XGS3_FABRIC_SUPPORT
   1120     if (SOC_IS_XGS3_FABRIC(unit)) {
   1121         BCM_IF_ERROR_RETURN
   1122             (_bcm_esw_fabric_multicast_param_check(unit, group, &mc_index));
   1123     } else
   1124 #endif /* BCM_XGS3_FABRIC_SUPPORT */
   1125     if ((mc_index < 0) ||
   1126         (mc_index >= soc_mem_index_count(unit, L2MCm))) {
   1127         return BCM_E_PARAM;
   1128     }
   1129 
   1130     BCM_IF_ERROR_RETURN
   1131         (_bcm_esw_gport_resolve(unit, port, &mod_out, &port_out,
   1132                                 &trunk_id, &gport_id)); 
   1133 
   1134 #if defined(BCM_KATANA2_SUPPORT)
   1135     if (soc_feature(unit, soc_feature_linkphy_coe) ||
   1136         soc_feature(unit, soc_feature_subtag_coe)) {
   1137         if (BCM_GPORT_IS_SET(port) &&
   1138             _BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit, port)) {
   1139             if (_bcm_kt2_mod_is_coe_mod_check(unit, mod_out) == BCM_E_NONE) {
   1140                 pp_port = BCM_GPORT_SUBPORT_PORT_GET(port);
   1141                 if (_bcm_kt2_is_pp_port_linkphy_subtag(unit, pp_port)) {
   1142                     is_local_subport = TRUE;
   1143                 }
   1144             }
   1145             if (is_local_subport == FALSE) {
   1146                 return BCM_E_PORT;
   1147             }
   1148         }
   1149     }
   1150     if (is_local_subport) {
   1151         port_out = pp_port;
   1152     } else
   1153 #endif
   1154 
   1155     if (BCM_TRUNK_INVALID != trunk_id) {
   1156         BCM_IF_ERROR_RETURN(
   1157             _bcm_esw_trunk_local_members_get(unit, trunk_id, 
   1158                                              max_num_ports,
   1159                                              local_trunk_member_ports, 
   1160                                              &trunk_local_ports));
   1161         /* Convertion of system ports to physical ports done in */
   1162         /* _bcm_esw_multicast_trunk_members_setup */
   1163     } else {
   1164         BCM_IF_ERROR_RETURN(
   1165             _bcm_esw_modid_is_local(unit, mod_out, &modid_local));
   1166         if (TRUE != modid_local) {
   1167             /* Only add this to replication set if destination is local */
   1168             return BCM_E_PORT;
   1169         }
   1170         /* Convert system port to physical port */
   1171         if (soc_feature(unit, soc_feature_sysport_remap)) {
   1172             BCM_XLATE_SYSPORT_S2P(unit, &port_out);
   1173         }
   1174     }
   1175 
   1176     /* Add the port to the L2MC port bitmap */
   1177     BCM_IF_ERROR_RETURN
   1178         (soc_mem_read(unit, L2MCm, MEM_BLOCK_ANY, mc_index, &l2mc_entry));
   1179 
   1180     soc_mem_pbmp_field_get(unit, L2MCm, &l2mc_entry, PORT_BITMAPf,
   1181                            &l2_pbmp);
   1182 
   1183     if (BCM_TRUNK_INVALID != trunk_id) {
   1184         for (idx = 0; idx < trunk_local_ports; idx++) {
   1185             BCM_PBMP_PORT_ADD(l2_pbmp, local_trunk_member_ports[idx]);
   1186         }
   1187     } else {
   1188         BCM_PBMP_PORT_ADD(l2_pbmp, port_out);
   1189     }
   1190     soc_mem_pbmp_field_set(unit, L2MCm, &l2mc_entry, PORT_BITMAPf, &l2_pbmp);
   1191 
   1192     return soc_mem_write(unit, L2MCm, MEM_BLOCK_ALL, mc_index, &l2mc_entry);
   1193 }
   1194 
   1195 /*
   1196  * Function:
   1197  *      _bcm_esw_multicast_l2_delete
   1198  * Purpose:
   1199  *      Helper function to delete a port from L2 multicast group
   1200  * Parameters:
   1201  *      unit      - (IN) Device Number
   1202  *      group     - (IN) Multicast group ID
   1203  *      port      - (IN) GPORT Identifier
   1204  *      encap_id  - (IN) Encap ID.
   1205  * Returns:
   1206  *      BCM_E_XXX
   1207  */
   1208 STATIC int 
   1209 _bcm_esw_multicast_l2_delete(int unit, bcm_multicast_t group, 
   1210                              bcm_port_t port, bcm_if_t encap_id)
   1211 {
   1212     l2mc_entry_t    l2mc_entry;
   1213     bcm_pbmp_t      l2_pbmp;
   1214     int             mc_index, gport_id, modid_local, idx, trunk_local_ports = 0;
   1215     bcm_module_t    mod_out;
   1216     bcm_port_t      port_out;
   1217 #if defined(BCM_ESW_SUPPORT) && (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS)
   1218     bcm_port_t      local_trunk_member_ports[SOC_MAX_NUM_PP_PORTS] = {0};
   1219     int             max_num_ports = SOC_MAX_NUM_PP_PORTS;
   1220 #else
   1221     bcm_port_t      local_trunk_member_ports[SOC_MAX_NUM_PORTS] = {0};
   1222     int             max_num_ports = SOC_MAX_NUM_PORTS;
   1223 #endif
   1224     bcm_trunk_t     trunk_id;
   1225 #if defined(BCM_KATANA2_SUPPORT)
   1226     int is_local_subport = FALSE, pp_port;
   1227 #endif
   1228 
   1229     modid_local = 0;
   1230     mc_index = _BCM_MULTICAST_ID_GET(group);
   1231 
   1232 #ifdef BCM_XGS3_FABRIC_SUPPORT
   1233     if (SOC_IS_XGS3_FABRIC(unit)) {
   1234         BCM_IF_ERROR_RETURN
   1235             (_bcm_esw_fabric_multicast_param_check(unit, group, &mc_index));
   1236     } else
   1237 #endif /* BCM_XGS3_FABRIC_SUPPORT */
   1238     if ((mc_index < 0) ||
   1239         (mc_index >= soc_mem_index_count(unit, L2MCm))) {
   1240         return BCM_E_PARAM;
   1241     }
   1242 
   1243     BCM_IF_ERROR_RETURN
   1244         (_bcm_esw_gport_resolve(unit, port, &mod_out, &port_out, 
   1245                                 &trunk_id, &gport_id)); 
   1246 
   1247 #if defined(BCM_KATANA2_SUPPORT)
   1248     if (soc_feature(unit, soc_feature_linkphy_coe) ||
   1249         soc_feature(unit, soc_feature_subtag_coe)) {
   1250         if (BCM_GPORT_IS_SET(port) &&
   1251             _BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit, port)) {
   1252             if (_bcm_kt2_mod_is_coe_mod_check(unit, mod_out) == BCM_E_NONE) {
   1253                 pp_port = BCM_GPORT_SUBPORT_PORT_GET(port);
   1254                 if (_bcm_kt2_is_pp_port_linkphy_subtag(unit, pp_port)) {
   1255                         is_local_subport = TRUE;
   1256                 }
   1257             }
   1258             if (is_local_subport == FALSE) {
   1259                 return BCM_E_PORT;
   1260             }
   1261         }
   1262     }
   1263     if (is_local_subport) {
   1264         port_out = pp_port;
   1265     } else
   1266 #endif
   1267 
   1268     if (BCM_TRUNK_INVALID != trunk_id) {
   1269         BCM_IF_ERROR_RETURN(
   1270             _bcm_esw_trunk_local_members_get(unit, trunk_id, 
   1271                                              max_num_ports,
   1272                                              local_trunk_member_ports, 
   1273                                              &trunk_local_ports));
   1274         /* Convertion of system ports to physical ports done in */
   1275         /* _bcm_esw_trunk_local_members_get */
   1276     } else {
   1277         BCM_IF_ERROR_RETURN(
   1278             _bcm_esw_modid_is_local(unit, mod_out, &modid_local));
   1279         if (TRUE != modid_local) {
   1280             /* Only add this to replication set if destination is local */
   1281             return BCM_E_PORT;
   1282         }
   1283         /* Convert system port to physical port */
   1284         if (soc_feature(unit, soc_feature_sysport_remap)) {
   1285             BCM_XLATE_SYSPORT_S2P(unit, &port_out);
   1286         }
   1287     }
   1288 
   1289     /* Delete the port from the L2MC port bitmap */
   1290     BCM_IF_ERROR_RETURN
   1291         (soc_mem_read(unit, L2MCm, MEM_BLOCK_ANY, mc_index, &l2mc_entry));
   1292 
   1293     soc_mem_pbmp_field_get(unit, L2MCm, &l2mc_entry, PORT_BITMAPf,
   1294                            &l2_pbmp);
   1295 
   1296 
   1297     if (BCM_TRUNK_INVALID != trunk_id) {
   1298         for (idx = 0; idx < trunk_local_ports; idx++) {
   1299             BCM_PBMP_PORT_REMOVE(l2_pbmp, local_trunk_member_ports[idx]);
   1300         }
   1301     } else {
   1302         BCM_PBMP_PORT_REMOVE(l2_pbmp, port_out);
   1303     }
   1304     soc_mem_pbmp_field_set(unit, L2MCm, &l2mc_entry, PORT_BITMAPf, &l2_pbmp);
   1305 
   1306     return soc_mem_write(unit, L2MCm, MEM_BLOCK_ALL, mc_index, &l2mc_entry);
   1307 }
   1308 
   1309 #if (defined(BCM_TRX_SUPPORT) || defined(BCM_XGS3_SWITCH_SUPPORT)) && defined(INCLUDE_L3) 
   1310 /*
   1311  * Function:
   1312  *      _bcm_esw_multicast_l2_get
   1313  * Purpose:
   1314  *      Helper function to get ports that are part of L2 multicast 
   1315  * Parameters: 
   1316  *      unit           - (IN) Device Number
   1317  *      mc_index       - (IN) Multicast index
   1318  *      port_max       - (IN) Number of entries in "port_array"
   1319  *      port_array     - (OUT) List of ports
   1320  *      encap_id_array - (OUT) List of encap identifiers
   1321  *      port_count     - (OUT) Actual number of ports returned
   1322  * Returns:
   1323  *      BCM_E_XXX
   1324  * Notes:
   1325  *      If the input parameter port_max = 0, return in the output parameter
   1326  *      port_count the total number of ports/encapsulation IDs in the 
   1327  *      specified multicast group's replication list.
   1328  */
   1329 
   1330 STATIC int     
   1331 _bcm_esw_multicast_l2_get(int unit, bcm_multicast_t group, int port_max,
   1332                              bcm_gport_t *port_array, bcm_if_t *encap_id_array, 
   1333                              int *port_count)
   1334 {
   1335     int             mc_index, i, rv;
   1336     l2mc_entry_t    l2mc_entry;
   1337     bcm_pbmp_t      l2_pbmp;
   1338     bcm_port_t      port_iter;
   1339 
   1340     i = 0;
   1341     rv = BCM_E_NONE;
   1342 
   1343     mc_index = _BCM_MULTICAST_ID_GET(group);
   1344 
   1345 #ifdef BCM_XGS3_FABRIC_SUPPORT
   1346     if (SOC_IS_XGS3_FABRIC(unit)) {
   1347         BCM_IF_ERROR_RETURN
   1348             (_bcm_esw_fabric_multicast_param_check(unit, group, &mc_index));
   1349     } else
   1350 #endif /* BCM_XGS3_FABRIC_SUPPORT */
   1351     if ((mc_index < 0) ||
   1352         (mc_index >= soc_mem_index_count(unit, L2MCm))) {
   1353         return BCM_E_PARAM;
   1354     }
   1355 
   1356     soc_mem_lock(unit, L2MCm);
   1357     rv = soc_mem_read(unit, L2MCm, MEM_BLOCK_ANY, mc_index, &l2mc_entry);
   1358     soc_mem_unlock(unit, L2MCm);
   1359     BCM_IF_ERROR_RETURN(rv);
   1360 
   1361     soc_mem_pbmp_field_get(unit, L2MCm, &l2mc_entry, PORT_BITMAPf, &l2_pbmp);
   1362     PBMP_ITER(l2_pbmp, port_iter) {
   1363         if ((port_max > 0) && (i >= port_max)) {
   1364             break;
   1365         }
   1366         if (NULL != port_array) {
   1367 #if defined(BCM_KATANA2_SUPPORT)
   1368             /* For KT2, pp_port >=42 are used for LinkPHY/SubportPktTag subport.
   1369              * Get the subport info associated with the pp_port and form the subport_gport 
   1370              * subport gport should be returned in the port_array for pp_port >=42*/
   1371 
   1372             if (_bcm_kt2_is_pp_port_linkphy_subtag(unit, port_iter)) {
   1373                 _BCM_KT2_SUBPORT_PORT_ID_SET(port_array[i], port_iter);
   1374                 if (BCM_PBMP_MEMBER(
   1375                     SOC_INFO(unit).linkphy_pp_port_pbm, port_iter)) {
   1376                     _BCM_KT2_SUBPORT_PORT_TYPE_SET(port_array[i],
   1377                         _BCM_KT2_SUBPORT_TYPE_LINKPHY);
   1378                 } else if (BCM_PBMP_MEMBER(
   1379                     SOC_INFO(unit).subtag_pp_port_pbm, port_iter)) {
   1380                     _BCM_KT2_SUBPORT_PORT_TYPE_SET(port_array[i],
   1381                         _BCM_KT2_SUBPORT_TYPE_SUBTAG);
   1382                 } else {
   1383                     return BCM_E_PORT;
   1384                 }
   1385             } else
   1386 #endif /* BCM_KATANA2_SUPPORT */
   1387             {
   1388                 BCM_IF_ERROR_RETURN
   1389                 (bcm_esw_port_gport_get(unit, port_iter, (port_array + i)));
   1390             }
   1391         }
   1392 
   1393         if (NULL != encap_id_array) {
   1394             encap_id_array[i] = BCM_IF_INVALID;
   1395         }
   1396         i++;
   1397     }
   1398     *port_count = i;
   1399     return BCM_E_NONE;
   1400 }
   1401 #endif /* #if (defined(BCM_TRX_SUPPORT) || defined(BCM_XGS3_SWITCH_SUPPORT)) && defined(INCLUDE_L3) */
   1402 
   1403 /*
   1404  * Function:
   1405  *      _bcm_esw_multicast_l2_create
   1406  * Purpose:
   1407  *      Helper function to allocate a multicast group index for l2
   1408  * Parameters:
   1409  *      unit       - (IN)   Device Number
   1410  *      flags      - (IN)   BCM_MULTICAST_*
   1411  *      group      - (OUT)  Group ID
   1412  * Returns:
   1413  *      BCM_E_XXX
   1414  */
   1415 STATIC int
   1416 _bcm_esw_multicast_l2_create(int unit, uint32 flags, bcm_multicast_t *group)
   1417 {
   1418     int             mc_index;
   1419     int             is_set = FALSE;
   1420     l2mc_entry_t    l2mc_entry;
   1421 
   1422     if (flags & BCM_MULTICAST_WITH_ID) {
   1423         if (_BCM_MULTICAST_IS_SET(*group) && !_BCM_MULTICAST_IS_L2(*group)) {
   1424             /* Group ID doesn't match creation flag type */
   1425             return BCM_E_PARAM;
   1426         }
   1427         mc_index = _BCM_MULTICAST_ID_GET(*group);
   1428         if ((mc_index < 0) ||
   1429             (mc_index >= soc_mem_index_count(unit, L2MCm))) {
   1430             return BCM_E_PARAM;
   1431         }
   1432 
   1433         BCM_IF_ERROR_RETURN(_bcm_xgs3_l2mc_index_is_set(unit, mc_index, &is_set));
   1434         if (is_set) {
   1435             return BCM_E_EXISTS;
   1436         }
   1437         
   1438         BCM_IF_ERROR_RETURN(_bcm_xgs3_l2mc_id_alloc(unit, mc_index));
   1439     } else {
   1440         BCM_IF_ERROR_RETURN(_bcm_xgs3_l2mc_free_index(unit, &mc_index));
   1441     }
   1442     sal_memset(&l2mc_entry, 0, sizeof(l2mc_entry));
   1443     soc_mem_field32_set(unit, L2MCm, &l2mc_entry, VALIDf, 1);
   1444     BCM_IF_ERROR_RETURN(
   1445         soc_mem_write(unit, L2MCm, MEM_BLOCK_ALL, mc_index, &l2mc_entry));
   1446     _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_L2, mc_index);
   1447 
   1448     return BCM_E_NONE;
   1449 }
   1450 
   1451 /*
   1452  * Function:
   1453  *      _bcm_esw_multicast_l2_destroy
   1454  * Purpose:
   1455  *      Helper function to destroy L2 multicast 
   1456  * Parameters: 
   1457  *      unit           - (IN) Device Number
   1458  *      group          - (IN) Multicast group to destroy
   1459  * Returns:
   1460  *      BCM_E_XXX
   1461  */
   1462 
   1463 STATIC int     
   1464 _bcm_esw_multicast_l2_destroy(int unit, bcm_multicast_t group)
   1465 {
   1466     int         mc_index;
   1467 #if defined(BCM_TSN_SR_SUPPORT)
   1468     int l2mc_index;
   1469     bcm_port_t l2mc_port;
   1470     sr_port_table_entry_t sr_port_entry;
   1471     sr_lport_tab_entry_t sr_lport_entry;
   1472 #endif /* BCM_TSN_SR_SUPPORT */
   1473     mc_index = _BCM_MULTICAST_ID_GET(group);
   1474 
   1475     if ((mc_index < 0) ||
   1476         (mc_index >= soc_mem_index_count(unit, L2MCm))) {
   1477         return BCM_E_PARAM;
   1478     }
   1479 
   1480     /* Clear the HW entry */
   1481     BCM_IF_ERROR_RETURN(
   1482         soc_mem_write(unit, L2MCm, MEM_BLOCK_ALL, 
   1483                       mc_index, soc_mem_entry_null(unit, L2MCm)));
   1484 
   1485 #if defined(BCM_TSN_SR_SUPPORT)
   1486     /* Clear L2MC for related SR ports if mc_index matches */
   1487     if (soc_feature(unit, soc_feature_tsn_sr)) {
   1488         int sr_lport_idx;
   1489         bcm_module_t my_modid = -1;
   1490         int src_trk_idx = 0; /* Source Trunk table index.*/
   1491         uint32 mem_entry[SOC_MAX_MEM_WORDS];
   1492 
   1493         BCM_IF_ERROR_RETURN(
   1494             bcm_esw_stk_my_modid_get(unit, &my_modid));
   1495 
   1496         BCM_PBMP_ITER(PBMP_ALL(unit), l2mc_port) {
   1497             BCM_IF_ERROR_RETURN(
   1498                 soc_mem_read(unit, SR_PORT_TABLEm, MEM_BLOCK_ANY,
   1499                              l2mc_port, &sr_port_entry));
   1500             l2mc_index = soc_mem_field32_get(unit, SR_PORT_TABLEm,
   1501                                              &sr_port_entry, L2MCf);
   1502             if (l2mc_index == mc_index) {
   1503                 soc_mem_field32_set(unit, SR_PORT_TABLEm, &sr_port_entry,
   1504                                     L2MCf, 0x0);
   1505                 BCM_IF_ERROR_RETURN(
   1506                     soc_mem_write(unit, SR_PORT_TABLEm, MEM_BLOCK_ALL,
   1507                                   l2mc_port, &sr_port_entry));
   1508             }
   1509 
   1510             BCM_IF_ERROR_RETURN(
   1511                 _bcm_esw_src_mod_port_table_index_get(unit, my_modid,
   1512                                                       l2mc_port, &src_trk_idx));
   1513             BCM_IF_ERROR_RETURN(
   1514                 soc_mem_read(unit, SOURCE_TRUNK_MAP_TABLEm, MEM_BLOCK_ANY,
   1515                              src_trk_idx, mem_entry));
   1516 
   1517             sr_lport_idx = soc_mem_field32_get(unit, SOURCE_TRUNK_MAP_TABLEm,
   1518                                                mem_entry, LPORT_PROFILE_IDXf);
   1519 
   1520             BCM_IF_ERROR_RETURN(
   1521                 soc_mem_read(unit, SR_LPORT_TABm, MEM_BLOCK_ANY,
   1522                              sr_lport_idx, &sr_lport_entry));
   1523             l2mc_index = soc_mem_field32_get(unit, SR_LPORT_TABm,
   1524                                              &sr_lport_entry, L2MCf);
   1525             if (l2mc_index == mc_index) {
   1526                 soc_mem_field32_set(unit, SR_LPORT_TABm, &sr_lport_entry,
   1527                                     L2MCf, 0x0);
   1528                 BCM_IF_ERROR_RETURN(
   1529                     soc_mem_write(unit, SR_LPORT_TABm, MEM_BLOCK_ALL,
   1530                                   sr_lport_idx, &sr_lport_entry));
   1531             }
   1532         }
   1533     }
   1534 #endif /* BCM_TSN_SR_SUPPORT */
   1535 
   1536     /* Free the L2MC index */
   1537     return _bcm_xgs3_l2mc_id_free(unit, mc_index);
   1538 }
   1539 
   1540 #if defined (INCLUDE_L3)
   1541 
   1542 /*
   1543  * Function:
   1544  *      _bcm_esw_multicast_egress_mapped_trunk_member_find
   1545  * Purpose:
   1546  *      Find the trunk member the encap id resides on.
   1547  * Parameters:
   1548  *      unit  - (IN) Device Number
   1549  *      group - (IN) Multicast group ID
   1550  *      port  - (IN) GPORT ID
   1551  *      encap_id - (IN) Encap identifiers
   1552  *      trunk_member - (OUT) Trunk member the encap id resides on
   1553  * Returns:
   1554  *      BCM_E_XXX
   1555  */
   1556 STATIC int
   1557 _bcm_esw_multicast_egress_mapped_trunk_member_find(int unit,
   1558         bcm_multicast_t group, bcm_gport_t port, bcm_if_t encap_id,
   1559         bcm_gport_t *trunk_member)
   1560 {
   1561     int rv = BCM_E_NONE;
   1562     bcm_trunk_t trunk_id;
   1563     bcm_trunk_info_t tinfo;
   1564 #if defined(BCM_ESW_SUPPORT) && (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS)
   1565     bcm_port_t      local_trunk_port_array[SOC_MAX_NUM_PP_PORTS];
   1566     int             max_num_ports = SOC_MAX_NUM_PP_PORTS;
   1567 #else
   1568     bcm_port_t      local_trunk_port_array[SOC_MAX_NUM_PORTS];
   1569     int             max_num_ports = SOC_MAX_NUM_PORTS;
   1570 #endif
   1571     int num_local_trunk_ports;
   1572     int port_count;
   1573     bcm_gport_t *port_array;
   1574     bcm_if_t *encap_id_array;
   1575     int match;
   1576     int i, j;
   1577     bcm_port_t local_port;
   1578     int mc_index;
   1579 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
   1580     int is_local_subport = FALSE;
   1581 #endif
   1582     if (NULL == trunk_member) {
   1583         return BCM_E_PARAM;
   1584     }
   1585 
   1586     *trunk_member = port;
   1587 
   1588     if (0 == _BCM_MULTICAST_IS_L3(group)) {
   1589         /* Software trunk resolution is available only for IPMC groups */
   1590         return BCM_E_NONE;
   1591     }
   1592     mc_index = _BCM_MULTICAST_ID_GET(group);
   1593     if ((mc_index < 0) || (mc_index >= soc_mem_index_count(unit, L3_IPMCm))) {
   1594         return BCM_E_PARAM;
   1595     }
   1596 
   1597     if (!BCM_GPORT_IS_TRUNK(port)) {
   1598         return BCM_E_NONE;
   1599     }
   1600 
   1601     if (BCM_IF_INVALID == encap_id) {
   1602         return BCM_E_NONE;
   1603     }
   1604 
   1605     /* Get trunk property and local member ports */
   1606     trunk_id = BCM_GPORT_TRUNK_GET(port);
   1607     BCM_IF_ERROR_RETURN
   1608         (bcm_esw_trunk_get(unit, trunk_id, &tinfo, 0, NULL, NULL));
   1609     if (!(tinfo.flags & BCM_TRUNK_FLAG_IPMC_CLEAVE)) {
   1610         return BCM_E_NONE;
   1611     }
   1612     BCM_IF_ERROR_RETURN(_bcm_esw_trunk_local_members_get(unit, trunk_id,
   1613                 max_num_ports, local_trunk_port_array,
   1614                 &num_local_trunk_ports));
   1615 
   1616     /* Get all ports and encap_ids of the multicast group */
   1617     BCM_IF_ERROR_RETURN(bcm_esw_multicast_egress_get(unit, group, 0,
   1618                 NULL, NULL, &port_count));
   1619     if (0 == port_count) {
   1620         return BCM_E_NOT_FOUND;
   1621     }
   1622     port_array = sal_alloc(sizeof(bcm_gport_t) * port_count, "port_array");
   1623     if (NULL == port_array) {
   1624         return BCM_E_MEMORY;
   1625     }
   1626     encap_id_array = sal_alloc(sizeof(bcm_if_t) * port_count, "encap_id_array");
   1627     if (NULL == encap_id_array) {
   1628         sal_free(port_array);
   1629         return BCM_E_MEMORY;
   1630     }
   1631     rv = bcm_esw_multicast_egress_get(unit, group, port_count,
   1632             port_array, encap_id_array, &port_count);
   1633     if (BCM_FAILURE(rv)) {
   1634         sal_free(port_array);
   1635         sal_free(encap_id_array);
   1636         return rv;
   1637     }
   1638 
   1639     /* Search for the trunk member the encap id resides on */
   1640     match = FALSE;
   1641     for (i = 0; i < port_count; i++) {
   1642         if (encap_id == encap_id_array[i]) {
   1643 
   1644 #if defined(BCM_HGPROXY_COE_SUPPORT)
   1645         if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   1646             BCM_GPORT_IS_SET(port_array[i]) &&
   1647             _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) {
   1648             is_local_subport = TRUE;
   1649             _bcmi_coe_subport_physical_port_get(unit, port_array[i],
   1650                                                       &local_port);
   1651         } else 
   1652 #endif
   1653 
   1654 #if defined(BCM_KATANA2_SUPPORT)
   1655         if (soc_feature(unit, soc_feature_linkphy_coe) ||
   1656             soc_feature(unit, soc_feature_subtag_coe)) {
   1657             if (BCM_GPORT_IS_SET(port_array[i]) &&
   1658                 _BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit,
   1659                 port_array[i])) {
   1660                 is_local_subport = TRUE;
   1661                 local_port = _BCM_KT2_SUBPORT_PORT_ID_GET(port_array[i]);
   1662             }
   1663         }
   1664 #endif
   1665 
   1666 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
   1667             if (is_local_subport) {
   1668                 /* Local subport assigned above */
   1669             } else
   1670 #endif
   1671             {
   1672                 rv = bcm_esw_port_local_get(unit, port_array[i], &local_port);
   1673                 if (BCM_FAILURE(rv)) {
   1674                     sal_free(port_array);
   1675                     sal_free(encap_id_array);
   1676                     return rv;
   1677                 }
   1678             }
   1679             for (j = 0; j < num_local_trunk_ports; j++) {
   1680                 if (local_trunk_port_array[j] == local_port) {
   1681                     match = TRUE;
   1682                     break;
   1683                 } 
   1684             }
   1685             if (match) {
   1686                 break;
   1687             }
   1688         }
   1689     }
   1690 
   1691     if (match) {
   1692         *trunk_member = port_array[i];
   1693     } else {
   1694         rv = BCM_E_NOT_FOUND;
   1695     }
   1696 
   1697     sal_free(port_array);
   1698     sal_free(encap_id_array);
   1699     return rv;
   1700 }
   1701 
   1702 /*
   1703  * Function:
   1704  *      _bcm_esw_multicast_egress_encap_id_to_trunk_member_map
   1705  * Purpose:
   1706  *      Maps encap id to a trunk group member. This is performed
   1707  *      if (1) the given group is an IPMC group, (2) the port in port_array is 
   1708  *      a trunk gport, and (3) IPMC trunk resolution is disabled for that trunk
   1709  *      group in hardware by setting the BCM_TRUNK_FLAG_IPMC_CLEAVE flag in
   1710  *      bcm_trunk_info_t. The hash fields used for trunk group member
   1711  *      selection are specified by ipmc_psc field in bcm_trunk_info_t.
   1712  *      The valid values for ipmc_psc are BCM_TRUNK_PSC_IPSA, IPDA, EGRESS_VID,
   1713  *      and RANDOM.
   1714  * Parameters:
   1715  *      unit       - (IN) Device Number
   1716  *      group      - (IN) Multicast group ID
   1717  *      port_count     - (IN) Number of ports in replication list
   1718  *      port_array     - (IN) List of GPORT Identifiers
   1719  *      encap_id_array - (IN) List of encap identifiers
   1720  *      mapped_port_array - (OUT) List of mapped GPORT identifiers
   1721  * Returns:
   1722  *      BCM_E_XXX
   1723  */
   1724 STATIC int
   1725 _bcm_esw_multicast_egress_encap_id_to_trunk_member_map(int unit,
   1726         bcm_multicast_t group, int port_count,
   1727         bcm_gport_t *port_array, bcm_if_t *encap_id_array,
   1728         bcm_gport_t *mapped_port_array)
   1729 {
   1730     int rv = BCM_E_NONE;
   1731     bcm_ipmc_addr_t ipmc_data;
   1732     uint8 *hash_key = NULL;
   1733     uint8 *hash_key_ptr = NULL;
   1734     int hash_key_size, max_hash_key_size;
   1735     int i, j;
   1736     bcm_trunk_t trunk_id;
   1737     bcm_trunk_info_t tinfo;
   1738 #if defined(BCM_ESW_SUPPORT) && (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS)
   1739         bcm_port_t      local_trunk_port_array[SOC_MAX_NUM_PP_PORTS];
   1740         int             max_num_ports = SOC_MAX_NUM_PP_PORTS;
   1741 #else
   1742         bcm_port_t      local_trunk_port_array[SOC_MAX_NUM_PORTS];
   1743         int             max_num_ports = SOC_MAX_NUM_PORTS;
   1744 #endif
   1745     int num_local_trunk_ports;
   1746     bcm_l3_intf_t l3_intf;
   1747     uint32 hash;
   1748     bcm_port_t mapped_port;
   1749     int mc_index;
   1750     int random_num;
   1751     int optimize_for_space;
   1752     bcm_if_t *temp_encap_array = NULL;
   1753     int *sublist_id_array = NULL;
   1754     int temp_encap_count;
   1755     int sublist_max, sublist_count = 0;
   1756     int first_free_sublist_id, next_free_sublist_id;
   1757     int selected_sublist_id;
   1758     int sublist0_trunk_member_index;
   1759     int trunk_member_index;
   1760     int temp_encap_index;
   1761 
   1762     if (port_count < 0) {
   1763         return BCM_E_PARAM;
   1764     }
   1765 
   1766     if (0 == port_count) {
   1767         /* Nothing to do */
   1768         return BCM_E_NONE;
   1769     }
   1770 
   1771     if (NULL == port_array) {
   1772         return BCM_E_PARAM;
   1773     }
   1774 
   1775     /* Copy port_array to mapped_port_array */
   1776     sal_memcpy(mapped_port_array, port_array,
   1777             sizeof(bcm_gport_t) * port_count);
   1778 
   1779     if (0 == _BCM_MULTICAST_IS_L3(group)) {
   1780         /* Software trunk resolution is available only for IPMC groups */
   1781         return BCM_E_NONE;
   1782     }
   1783     mc_index = _BCM_MULTICAST_ID_GET(group);
   1784     if ((mc_index < 0) || (mc_index >= soc_mem_index_count(unit, L3_IPMCm))) {
   1785         return BCM_E_PARAM;
   1786     }
   1787 
   1788     if (NULL == encap_id_array) {
   1789         /* For IPMC groups, encap_id_array should not be NULL */
   1790         return BCM_E_PARAM;
   1791     }
   1792 
   1793     /* Allocate hash key. The hash key contains at most two IPv6 address,
   1794      * a VLAN ID, and a random integer.
   1795      */
   1796     max_hash_key_size = 2 * sizeof(bcm_ip6_t) + sizeof(bcm_vlan_t) +
   1797                         sizeof(int);
   1798     hash_key = sal_alloc(max_hash_key_size, "hash key");
   1799     if (NULL == hash_key) {
   1800         return BCM_E_MEMORY;
   1801     }
   1802     sal_memset(hash_key, 0, max_hash_key_size);
   1803 
   1804     /* Iterate through mapped_port_array */
   1805     for (i = 0; i < port_count; i++) {
   1806         if (!BCM_GPORT_IS_TRUNK(mapped_port_array[i])) {
   1807             continue;
   1808         }
   1809 
   1810         if (BCM_IF_INVALID == encap_id_array[i]) {
   1811             continue;
   1812         }
   1813 
   1814         trunk_id = BCM_GPORT_TRUNK_GET(mapped_port_array[i]);
   1815         rv = bcm_esw_trunk_get(unit, trunk_id, &tinfo, 0, NULL, NULL);
   1816         if (BCM_FAILURE(rv)) {
   1817             goto done;
   1818         }
   1819         if (!(tinfo.flags & BCM_TRUNK_FLAG_IPMC_CLEAVE)) {
   1820             /* IPMC trunk resolution is enabled in hardware,
   1821              * do not perform software trunk resolution.
   1822              */
   1823             continue;
   1824         }
   1825 
   1826         /* Get local members of the trunk group */
   1827         rv = _bcm_esw_trunk_local_members_get(unit, trunk_id,
   1828                 max_num_ports, local_trunk_port_array,
   1829                 &num_local_trunk_ports);
   1830         if (BCM_FAILURE(rv)) {
   1831             goto done;
   1832         }
   1833 
   1834         /* Compute hash */
   1835 
   1836         sal_memset(hash_key, 0, max_hash_key_size);
   1837         hash_key_ptr = hash_key;
   1838 
   1839         if ((tinfo.ipmc_psc & BCM_TRUNK_PSC_IPSA) ||
   1840                 (tinfo.ipmc_psc & BCM_TRUNK_PSC_IPDA)) {
   1841             bcm_ipmc_addr_t_init(&ipmc_data);
   1842             rv = bcm_esw_ipmc_get_by_index(unit, _BCM_MULTICAST_ID_GET(group),
   1843                     &ipmc_data);
   1844             if (BCM_FAILURE(rv)) {
   1845                 goto done;
   1846             }
   1847             if (ipmc_data.flags & BCM_IPMC_IP6) {
   1848                 if (tinfo.ipmc_psc & BCM_TRUNK_PSC_IPSA) {
   1849                     sal_memcpy(hash_key_ptr, &ipmc_data.s_ip6_addr,
   1850                             sizeof(ipmc_data.s_ip6_addr));
   1851                     hash_key_ptr += sizeof(ipmc_data.s_ip6_addr);
   1852                 }
   1853                 if (tinfo.ipmc_psc & BCM_TRUNK_PSC_IPDA) {
   1854                     sal_memcpy(hash_key_ptr, &ipmc_data.mc_ip6_addr,
   1855                             sizeof(ipmc_data.mc_ip6_addr));
   1856                     hash_key_ptr += sizeof(ipmc_data.mc_ip6_addr);
   1857                 }
   1858             } else {
   1859                 if (tinfo.ipmc_psc & BCM_TRUNK_PSC_IPSA) {
   1860                     sal_memcpy(hash_key_ptr, &ipmc_data.s_ip_addr,
   1861                             sizeof(ipmc_data.s_ip_addr));
   1862                     hash_key_ptr += sizeof(ipmc_data.s_ip_addr);
   1863                 }
   1864                 if (tinfo.ipmc_psc & BCM_TRUNK_PSC_IPDA) {
   1865                     sal_memcpy(hash_key_ptr, &ipmc_data.mc_ip_addr,
   1866                             sizeof(ipmc_data.mc_ip_addr));
   1867                     hash_key_ptr += sizeof(ipmc_data.mc_ip_addr);
   1868                 }
   1869             }
   1870         }
   1871 
   1872         if (tinfo.ipmc_psc & BCM_TRUNK_PSC_EGRESS_VID) {
   1873             if (!BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, encap_id_array[i])) {
   1874                 bcm_l3_intf_t_init(&l3_intf);
   1875                 l3_intf.l3a_intf_id = encap_id_array[i];
   1876                 rv = bcm_esw_l3_intf_get(unit, &l3_intf);
   1877                 if (BCM_FAILURE(rv)) {
   1878                     goto done;
   1879                 }
   1880                 sal_memcpy(hash_key_ptr, &l3_intf.l3a_vid,
   1881                         sizeof(bcm_vlan_t));
   1882                 hash_key_ptr += sizeof(bcm_vlan_t);
   1883             }
   1884         }
   1885 
   1886         if (tinfo.ipmc_psc & BCM_TRUNK_PSC_RANDOM) {
   1887             random_num = sal_time_usecs();
   1888             sal_memcpy(hash_key_ptr, &random_num, sizeof(int));
   1889             hash_key_ptr += sizeof(int);
   1890         }
   1891 
   1892         hash_key_size = hash_key_ptr - hash_key;
   1893         if (hash_key_size > 0) {
   1894             hash = _shr_crc32(0, hash_key, hash_key_size);
   1895         } else {
   1896             hash = 0;
   1897         }
   1898 
   1899         optimize_for_space = FALSE;
   1900 #if defined(BCM_TRIUMPH2_SUPPORT) 
   1901         if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 
   1902                 SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) ||
   1903                 SOC_IS_KATANA(unit)) {
   1904             int available_percent, threshold;
   1905 
   1906             rv = bcm_esw_switch_control_get(unit,
   1907                     bcmSwitchIpmcReplicationAvailabilityThreshold, &threshold);
   1908             if (BCM_FAILURE(rv)) {
   1909                 goto done;
   1910             }
   1911             if (threshold > 0) {
   1912                 rv = bcm_tr2_ipmc_repl_availability_get(unit, &available_percent);
   1913                 if (BCM_FAILURE(rv)) {
   1914                     goto done;
   1915                 }
   1916                 if (available_percent < threshold) {
   1917                     /* IPMC replication table available space has fallen below the
   1918                      * configured threshold. Conservation of IPMC replication table
   1919                      * space now takes precedence over hashing when assigning encap 
   1920                      * ids to trunk members.
   1921                      */
   1922                     optimize_for_space = TRUE;
   1923                 }
   1924             }
   1925         } 
   1926 #endif  /* BCM_TRIUMPH2_SUPPORT */
   1927 
   1928         if (!optimize_for_space) {
   1929             mapped_port = local_trunk_port_array[hash % num_local_trunk_ports];
   1930             rv = bcm_esw_port_gport_get(unit, mapped_port,
   1931                     &mapped_port_array[i]);
   1932             if (BCM_FAILURE(rv)) {
   1933                 goto done;
   1934             }
   1935             continue;
   1936         } 
   1937 
   1938         /* Assign encap ids to trunk members with conservation of IPMC
   1939          * replication table space as highest priority.
   1940          * First, gather all encap ids with the same trunk ID as the
   1941          * current trunk group.
   1942          */
   1943 
   1944         if (NULL == temp_encap_array) {
   1945             temp_encap_array = sal_alloc(sizeof(bcm_if_t) * port_count,
   1946                     "temp encap array");
   1947             if (NULL == temp_encap_array) {
   1948                 rv = BCM_E_MEMORY;
   1949                 goto done;
   1950             }
   1951         }
   1952         sal_memset(temp_encap_array, 0, sizeof(bcm_if_t) * port_count);
   1953 
   1954         if (NULL == sublist_id_array) {
   1955             sublist_id_array = sal_alloc(sizeof(int) * port_count,
   1956                     "sublist id array");
   1957             if (NULL == sublist_id_array) {
   1958                 rv = BCM_E_MEMORY;
   1959                 goto done;
   1960             }
   1961         }
   1962         sal_memset(sublist_id_array, 0, sizeof(int) * port_count);
   1963 
   1964         temp_encap_count = 0;
   1965         for (j = i; j < port_count; j++) {
   1966             if (!BCM_GPORT_IS_TRUNK(mapped_port_array[j])) {
   1967                 continue;
   1968             }
   1969             if (BCM_IF_INVALID == encap_id_array[j]) {
   1970                 continue;
   1971             }
   1972             if (BCM_GPORT_TRUNK_GET(mapped_port_array[j]) != trunk_id) {
   1973                 continue;
   1974             }
   1975             temp_encap_array[temp_encap_count++] = encap_id_array[j];
   1976         }
   1977 
   1978         /* Split the current trunk group's list of encap ids into sublists,
   1979          * such that the sublists match existing replication lists,
   1980          * enabling sharing of IPMC replication table entries.
   1981          * It's not necessary to generate more sublists than there are
   1982          * trunk members, since mapping multiple sublists to a trunk member
   1983          * would effectively join those sublists.
   1984          */
   1985 
   1986         sublist_max = num_local_trunk_ports;
   1987         for (j = 0; j < temp_encap_count; j++) {
   1988             /* Initialize each encap id's sublist id to be
   1989              * the invalid value of sublist_max.
   1990              */
   1991             sublist_id_array[j] = sublist_max;
   1992         }
   1993 
   1994 #if defined(BCM_TRIUMPH2_SUPPORT) 
   1995         if (SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 
   1996                 SOC_IS_VALKYRIE2(unit) || SOC_IS_TRIDENT(unit) ||
   1997                 SOC_IS_KATANA(unit)) {
   1998 
   1999             rv = bcm_tr2_ipmc_repl_list_split(unit, temp_encap_count,
   2000                     temp_encap_array, sublist_id_array, 
   2001                     sublist_max, &sublist_count);
   2002             if (BCM_FAILURE(rv)) {
   2003                 goto done;
   2004             }
   2005         } 
   2006 #endif  /* BCM_TRIUMPH2_SUPPORT */
   2007 
   2008         /* If the number of sublists used, given by sublist_count,
   2009          * is less than the max number of sublists allowed,
   2010          * given by sublist_max, the encap ids that are not yet
   2011          * a member of any sublist are assigned to the remaining
   2012          * free sublists.
   2013          * If there are no free sublist left, the encap ids that are
   2014          * not yet a member of any sublist are assigned to an
   2015          * existing sublist selected by hash.
   2016          */
   2017         if (sublist_count < sublist_max) {
   2018             first_free_sublist_id = sublist_count;
   2019             next_free_sublist_id = first_free_sublist_id;
   2020             for (j = 0; j < temp_encap_count; j++) {
   2021                 if (sublist_id_array[j] == sublist_max) {
   2022                     sublist_id_array[j] = next_free_sublist_id;
   2023                     if ((next_free_sublist_id + 1) == sublist_max) {
   2024                         /* wrap around to the first free sublist id */
   2025                         next_free_sublist_id = first_free_sublist_id;
   2026                     } else {
   2027                         next_free_sublist_id++;
   2028                     }
   2029                 }
   2030             }
   2031         } else if (sublist_count == sublist_max) {
   2032             selected_sublist_id = hash % sublist_max;
   2033             for (j = 0; j < temp_encap_count; j++) {
   2034                 if (sublist_id_array[j] == sublist_max) {
   2035                     sublist_id_array[j] = selected_sublist_id;
   2036                 }
   2037             }
   2038         } else {
   2039             /* sublist_count should never be greater than sublist_max */
   2040             rv = BCM_E_INTERNAL;
   2041             goto done;
   2042         }
   2043 
   2044         /* The sublists will be assigned to trunk members in a round-robin
   2045          * fashion, with the starting trunk member selected by hash.
   2046          * Sublist 0 will be assigned to a local trunk member selected
   2047          * by hashing. Then sublist 1 will be assigned to the
   2048          * next trunk member in local_trunk_port_array, and so on.
   2049          */
   2050         sublist0_trunk_member_index = hash % num_local_trunk_ports;
   2051         temp_encap_index = 0;
   2052         for (j = i; j < port_count; j++) {
   2053             if (!BCM_GPORT_IS_TRUNK(mapped_port_array[j])) {
   2054                 continue;
   2055             }
   2056             if (BCM_IF_INVALID == encap_id_array[j]) {
   2057                 continue;
   2058             }
   2059             if (BCM_GPORT_TRUNK_GET(mapped_port_array[j]) != trunk_id) {
   2060                 continue;
   2061             }
   2062             if (temp_encap_array[temp_encap_index] != encap_id_array[j]) {
   2063                 /* They should always match */
   2064                 rv = BCM_E_INTERNAL;
   2065                 goto done;
   2066             }
   2067 
   2068             trunk_member_index = (sublist0_trunk_member_index +
   2069                 sublist_id_array[temp_encap_index]) % num_local_trunk_ports;
   2070 
   2071             mapped_port = local_trunk_port_array[trunk_member_index];
   2072             rv = bcm_esw_port_gport_get(unit, mapped_port,
   2073                     &mapped_port_array[j]);
   2074             if (BCM_FAILURE(rv)) {
   2075                 goto done;
   2076             }
   2077             temp_encap_index++;
   2078         }
   2079     }
   2080 
   2081 done:
   2082     if (hash_key) {
   2083         sal_free(hash_key);
   2084     }
   2085     if (temp_encap_array) {
   2086         sal_free(temp_encap_array);
   2087     }
   2088     if (sublist_id_array) {
   2089         sal_free(sublist_id_array);
   2090     }
   2091 
   2092     return rv;
   2093 }
   2094 
   2095 /*
   2096  * Function:
   2097  *      _bcm_esw_multicast_l3_group_check
   2098  * Purpose:
   2099  *      Helper function to validate L3 or Virtual multicast group
   2100  * Parameters:
   2101  *      unit      - (IN) Device Number
   2102  *      group     - (IN) Multicast group ID
   2103  *      is_l3     - (OUT) L3 Group identifier for Firebolt
   2104  * Returns:
   2105  *      BCM_E_XXX
   2106  */
   2107 STATIC int 
   2108 _bcm_esw_multicast_l3_group_check(int unit, bcm_multicast_t group, int *is_l3)
   2109 {
   2110     if (_BCM_MULTICAST_IS_L3(group) 
   2111         || _BCM_MULTICAST_IS_TRILL(group)
   2112         || _BCM_MULTICAST_IS_FLOW(group)
   2113         || _BCM_MULTICAST_IS_VXLAN(group)) {
   2114         if (NULL != is_l3) {    /* If caller cares about this information */
   2115             *is_l3 = 1;
   2116         }        
   2117     } else if (!SOC_IS_TRX(unit)) {
   2118         /* Pre TX devices don't support Virutal multicast groups */
   2119         return (BCM_E_PARAM);
   2120     } else if (!_BCM_MULTICAST_IS_VPLS(group) &&
   2121                !_BCM_MULTICAST_IS_MIM(group) &&
   2122                !_BCM_MULTICAST_IS_WLAN(group) &&
   2123                !_BCM_MULTICAST_IS_VLAN(group) &&
   2124                !_BCM_MULTICAST_IS_NIV(group) &&
   2125                !_BCM_MULTICAST_IS_L2GRE(group) &&
   2126                !_BCM_MULTICAST_IS_SUBPORT(group) &&
   2127                !_BCM_MULTICAST_IS_EGRESS_OBJECT(group) &&
   2128                !_BCM_MULTICAST_IS_EXTENDER(group)) {
   2129         return (BCM_E_PARAM);
   2130     }
   2131 
   2132     return (BCM_E_NONE);
   2133 }
   2134 
   2135 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_TRIDENT2PLUS_SUPPORT)
   2136 typedef struct _bcm_trunk_first_member_s {
   2137     int trunk_id;
   2138     int pipe_id;
   2139     int first_member;
   2140 } _bcm_trunk_first_member_t;
   2141 
   2142 
   2143 /*
   2144  * Function:
   2145  *      _bcm_esw_ipmc_egress_intf_destroy_in_trunk_repl_mode
   2146  * Purpose:
   2147  *      Destory ipmc egress intf of given ports which are represented by e_pbmp.
   2148  * Parameters:
   2149  *      unit           - (IN) Device Number
   2150  *      mc_index       - (IN) Multicast group ID.
   2151  *      e_pbmp         - (IN) Port bitmap
   2152  *      is_l3          - (IN) Indicates if multicast group type is IPMC.
   2153  * Returns:
   2154  *      BCM_E_XXX
   2155  */
   2156 STATIC int
   2157 _bcm_esw_ipmc_egress_intf_destroy_in_trunk_repl_mode(int unit,
   2158     int mc_index, bcm_pbmp_t e_pbmp, int is_l3)
   2159 {
   2160     bcm_trunk_t tgid;
   2161     _bcm_trunk_first_member_t *first_member_array;
   2162     bcm_port_t first_member, port_iter;
   2163     int count, i, is_first_member, pipe;
   2164     int rv;
   2165 
   2166     first_member_array =
   2167         sal_alloc(sizeof(_bcm_trunk_first_member_t) * SOC_MAX_NUM_PORTS,
   2168                   "first_member_array pointers");
   2169     if (NULL == first_member_array) {
   2170         return BCM_E_MEMORY;
   2171     }
   2172 
   2173     for (i = 0; i < SOC_MAX_NUM_PORTS; i++) {
   2174         first_member_array[i].trunk_id = BCM_TRUNK_INVALID;
   2175         first_member_array[i].first_member = -1;
   2176         first_member_array[i].pipe_id = -1;
   2177     }
   2178 
   2179     count = 0;
   2180     BCM_PBMP_ITER(e_pbmp, port_iter) {
   2181         rv = _bcm_esw_ipmc_port_trunkid_get(unit, port_iter, &tgid);
   2182         if (BCM_FAILURE(rv)) {
   2183             sal_free(first_member_array);
   2184             return rv;
   2185         }
   2186         if (tgid != BCM_TRUNK_INVALID) {
   2187             is_first_member = TRUE;
   2188             first_member = -1;
   2189             pipe = SOC_INFO(unit).port_pipe[port_iter];
   2190             for (i = 0; i < count; i++) {
   2191                 if ((first_member_array[i].trunk_id == tgid) &&
   2192                     (first_member_array[i].pipe_id == pipe)) {
   2193                     is_first_member = FALSE;
   2194                     first_member = first_member_array[i].first_member;
   2195                     break;
   2196                 }
   2197             }
   2198             if (i == count) {
   2199                 first_member_array[count].trunk_id = tgid;
   2200                 first_member_array[count].pipe_id = pipe;
   2201                 first_member_array[count].first_member = port_iter;
   2202                 is_first_member = TRUE;
   2203                 count++;
   2204             }
   2205 
   2206             if (is_first_member) {
   2207                 rv = _bcm_esw_ipmc_egress_intf_set_for_trunk_first_member(
   2208                          unit, mc_index, port_iter, 0, NULL,
   2209                          is_l3, FALSE, tgid);
   2210             } else {
   2211                 rv = _bcm_esw_ipmc_egress_intf_set_for_same_pipe_member(
   2212                          unit, mc_index, port_iter,
   2213                          first_member, BCM_TRUNK_INVALID);
   2214             }
   2215         } else {
   2216             rv = _bcm_esw_ipmc_egress_intf_set_for_trunk_first_member(
   2217                      unit, mc_index, port_iter,0, NULL,
   2218                      is_l3, FALSE, BCM_TRUNK_INVALID);
   2219         }
   2220 
   2221         if (BCM_FAILURE(rv)) {
   2222             sal_free(first_member_array);
   2223             return rv;
   2224         }
   2225     }
   2226 
   2227     sal_free(first_member_array);
   2228 
   2229     return BCM_E_NONE;
   2230 }
   2231 #endif
   2232 
   2233 #ifdef BCM_TRIDENT2_SUPPORT
   2234 static int
   2235 _bcm_esw_multicast_l3_mpls_nh_check(int unit, int nh, int* is_l3_mpls)
   2236 {
   2237     int rv = 0;
   2238     int entry_type = 0;
   2239     soc_field_t entry_type_field = 0;
   2240     egr_l3_next_hop_entry_t egr_entry;
   2241     *is_l3_mpls = 0;
   2242 
   2243     if (SOC_IS_TRIDENT3X(unit)) {
   2244         entry_type_field = DATA_TYPEf;
   2245     } else {
   2246         entry_type_field = ENTRY_TYPEf;
   2247     }
   2248 
   2249     if (SOC_MEM_IS_VALID(unit, EGR_L3_NEXT_HOPm)) {
   2250         if (!BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, next_hop), nh)) {
   2251             return BCM_E_NOT_FOUND;
   2252         }
   2253 
   2254         sal_memset(&egr_entry, 0, sizeof(egr_l3_next_hop_entry_t));
   2255         rv = BCM_XGS3_MEM_READ(unit, EGR_L3_NEXT_HOPm, nh, &egr_entry);
   2256         if (rv != BCM_E_NONE) {
   2257             return rv;
   2258         }
   2259 
   2260         if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm, entry_type_field)) {
   2261             entry_type = soc_mem_field32_get(
   2262                 unit, EGR_L3_NEXT_HOPm, &egr_entry, entry_type_field);
   2263             if (entry_type == 1) {
   2264                 *is_l3_mpls = 1;
   2265             }
   2266         }
   2267     }
   2268 
   2269     return BCM_E_NONE;
   2270 }
   2271 #endif
   2272 
   2273 
   2274 /*
   2275  * Function:
   2276  *      _bcm_esw_multicast_l3_add
   2277  * Purpose:
   2278  *      Helper function to add a port to L3 or Virtual multicast group
   2279  * Parameters:
   2280  *      unit      - (IN) Device Number
   2281  *      group     - (IN) Multicast group ID
   2282  *      port      - (IN) GPORT Identifier
   2283  *      encap_id  - (IN) Encap ID.
   2284  * Returns:
   2285  *      BCM_E_XXX
   2286  */
   2287 STATIC int 
   2288 _bcm_esw_multicast_l3_add(int unit, bcm_multicast_t group, 
   2289                           bcm_gport_t port, bcm_if_t encap_id)
   2290 
   2291 {
   2292     int mc_index, is_l3, gport_id, idx, idx_max, trunk_local_ports = 0; 
   2293     bcm_module_t mod_out;
   2294     bcm_port_t port_out, port_gport;
   2295     bcm_trunk_t trunk_id;
   2296     int modid_local, rv = BCM_E_NONE;
   2297     int is_subport_trunk = FALSE;
   2298 #if defined(BCM_ESW_SUPPORT) && (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS)
   2299     bcm_port_t      local_trunk_member_ports[SOC_MAX_NUM_PP_PORTS] = {0};
   2300     int             max_num_ports = SOC_MAX_NUM_PP_PORTS;
   2301 #else
   2302     bcm_port_t      local_trunk_member_ports[SOC_MAX_NUM_PORTS] = {0};
   2303     int             max_num_ports = SOC_MAX_NUM_PORTS;
   2304 #endif
   2305     bcm_pbmp_t l2_pbmp, l3_pbmp, old_pbmp, *new_pbmp;
   2306     int if_max = BCM_MULTICAST_PORT_MAX;
   2307 
   2308 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
   2309     int is_local_subport = FALSE;
   2310 #endif
   2311 #if defined(BCM_HGPROXY_COE_SUPPORT)
   2312     bcm_trunk_t          subport_trunk_id;
   2313     bcm_trunk_member_t   *trunk_member = NULL;
   2314     bcm_port_t           local_port;
   2315     int                  member_count;
   2316     int                  is_local;
   2317 #endif
   2318 
   2319 #if defined(BCM_ENDURO_SUPPORT) || defined(BCM_TRIUMPH3_SUPPORT)
   2320     /* Size of "L3 Next hop table is limited to 2K on dagger(Enduro variant).
   2321      * On Ranger+ max replication interface is limited by
   2322      * number of EGR_L3_Intfm.
   2323      */
   2324 
   2325     int nexthop_count = 0, egr_intf_count = 0;
   2326     if (SOC_IS_ENDURO(unit) || SOC_IS_TRIUMPH3(unit)) {
   2327         nexthop_count =  soc_mem_index_count(unit, ING_L3_NEXT_HOPm);
   2328         egr_intf_count = soc_mem_index_count(unit, EGR_L3_INTFm);
   2329         if_max = (nexthop_count < egr_intf_count)?
   2330              ((if_max < nexthop_count)? if_max : nexthop_count):
   2331              ((if_max < egr_intf_count)?  if_max : egr_intf_count);
   2332     }
   2333 #endif /* BCM_ENDURO_SUPPORT || BCM_TRIUMPH3_SUPPORT */
   2334 
   2335 #if defined(BCM_HURRICANE_SUPPROT) || defined(BCM_HURRICANE2_SUPPORT) || \
   2336     defined(BCM_GREYHOUND_SUPPORT)
   2337     if (SOC_IS_HURRICANEX(unit) || SOC_IS_GREYHOUND(unit) || \
   2338         SOC_IS_GREYHOUND2(unit)) {
   2339         /* Assign proper if_max for HURRICANEx and GH since if_max is 4096 
   2340          * by default.         */
   2341         if_max = soc_mem_index_count(unit, EGR_L3_INTFm);
   2342     }
   2343 #endif  /* BCM_HURRICANE_SUPPORT || BCM_HURRICANE2_SUPPORT */
   2344 
   2345 #ifdef BCM_TRIDENT2_SUPPORT
   2346     if (SOC_IS_TD2_TT2(unit)) {
   2347         /* To assign proper if_max to avoid getting unexpected parameter
   2348          * validation error since if_max is 4096 by default.
   2349          */
   2350         if_max = soc_mem_index_count(unit, EGR_L3_NEXT_HOPm);
   2351     }
   2352 #endif
   2353 
   2354     is_l3 = 0;      /* Needed to support Firebolt style of L3 Multicast */
   2355     trunk_local_ports = 0; 
   2356     modid_local = FALSE;
   2357 
   2358     mc_index = _BCM_MULTICAST_ID_GET(group);
   2359 
   2360     if ((mc_index < 0) ||
   2361         (mc_index >= soc_mem_index_count(unit, L3_IPMCm))) {
   2362         return BCM_E_PARAM;
   2363     }
   2364 
   2365     BCM_IF_ERROR_RETURN(_bcm_esw_multicast_l3_group_check(unit, group, &is_l3));
   2366 
   2367 #if defined(BCM_TRIDENT_SUPPORT) && defined(INCLUDE_L3)
   2368     if (soc_feature(unit, soc_feature_trill)) {
   2369         if (_BCM_MULTICAST_IS_TRILL(group)) {
   2370              BCM_IF_ERROR_RETURN
   2371                 (bcm_td_trill_egress_add(unit, group));
   2372         }
   2373     }
   2374 #endif /* BCM_TRIDENT_SUPPORT && INCLUDE_L3 */
   2375 
   2376     BCM_IF_ERROR_RETURN(
   2377         _bcm_esw_gport_resolve(unit, port, &mod_out, &port_out,
   2378                                &trunk_id, &gport_id));
   2379 
   2380     /* In case of extended queuing on KTX, trunk_id gets updated with
   2381      * extended queue value. So set it to invalid value.
   2382      */
   2383 #ifdef BCM_KATANA_SUPPORT
   2384     if (soc_feature(unit, soc_feature_extended_queueing)) {
   2385         if ((BCM_GPORT_IS_UCAST_QUEUE_GROUP(port)) ||
   2386             (BCM_GPORT_IS_UCAST_SUBSCRIBER_QUEUE_GROUP(port)) ||
   2387             (BCM_GPORT_IS_MCAST_SUBSCRIBER_QUEUE_GROUP(port))) {
   2388             trunk_id = BCM_TRUNK_INVALID;
   2389         }
   2390     }
   2391 #endif
   2392 
   2393 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
   2394     BCM_IF_ERROR_RETURN(
   2395         _bcm_esw_port_is_local_subport(
   2396             unit, port, mod_out, port_out, &is_local_subport, &port_out));
   2397 
   2398     if (is_local_subport) {
   2399         /* Local subport assigned above */
   2400     } else
   2401 #endif
   2402 
   2403     if (BCM_TRUNK_INVALID != trunk_id) {
   2404         BCM_IF_ERROR_RETURN(
   2405         /* system ports to physical ports conversion done in
   2406          * _bcm_esw_trunk_local_members_get
   2407          */
   2408         _bcm_esw_trunk_local_members_get(unit, trunk_id,
   2409                                          max_num_ports,
   2410                                          local_trunk_member_ports,
   2411                                          &trunk_local_ports));
   2412     }
   2413 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_TRIDENT2PLUS_SUPPORT)
   2414    else if ((BCM_MC_PER_TRUNK_REPL_MODE(unit)) && 
   2415             (encap_id == BCM_ENCAP_TRUNK_MEMBER)) {
   2416         BCM_IF_ERROR_RETURN(
   2417             _bcm_esw_ipmc_egress_intf_add_trunk_member(
   2418                 unit, mc_index, port_out));
   2419     }
   2420 #endif /* BCM_TOMAHAWK_SUPPORT || BCM_TRIDENT2PLUS_SUPPORT */
   2421     else {
   2422         BCM_IF_ERROR_RETURN
   2423             (_bcm_esw_modid_is_local(unit, mod_out, &modid_local));
   2424         if (TRUE != modid_local) {
   2425             /* Only add this to replication set if destination is local */
   2426             return BCM_E_PORT;
   2427         }
   2428 
   2429         /* Convert system port to physical port */
   2430         if (soc_feature(unit, soc_feature_sysport_remap)) {
   2431             BCM_XLATE_SYSPORT_S2P(unit, &port_out);
   2432         }
   2433     }
   2434 
   2435 #ifdef BCM_TRIUMPH3_SUPPORT 
   2436     if (SOC_IS_TRIUMPH3(unit)) {
   2437         int use_axp_port = 0;
   2438         bcm_l3_egress_t l3_egr;
   2439 
   2440         if (_BCM_MULTICAST_IS_WLAN(group)) {
   2441             /* Triumph3 requires WLAN replications to be configured on
   2442              * AXP port.
   2443              */
   2444             use_axp_port = 1;
   2445         } else if (_BCM_MULTICAST_IS_L3(group)) {
   2446             /* Triumph3 requires IPMC replications destined for WLAN
   2447              * virtual ports to be configured on AXP port.
   2448              */
   2449             if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, encap_id)) {
   2450 
   2451                 bcm_l3_egress_t_init(&l3_egr);
   2452                 rv = bcm_esw_l3_egress_get(unit, encap_id, &l3_egr);
   2453                 if (BCM_SUCCESS(rv)) { 
   2454                     if (BCM_GPORT_IS_WLAN_PORT(l3_egr.port)) {
   2455                         use_axp_port = 1;
   2456                     }
   2457                 }
   2458             }
   2459         }
   2460 
   2461         if (use_axp_port) {
   2462             trunk_id = BCM_TRUNK_INVALID;
   2463             port_out = AXP_PORT(unit, SOC_AXP_NLF_WLAN_ENCAP);
   2464         }
   2465     }
   2466 #endif /* BCM_TRIUMPH3_SUPPORT */
   2467 #if defined(INCLUDE_XFLOW_MACSEC)
   2468     if (soc_feature(unit, soc_feature_xflow_macsec)) {
   2469         bcm_l3_egress_t l3_egr;
   2470         if (_BCM_MULTICAST_IS_L3(group)) {
   2471             bcm_l3_egress_t_init(&l3_egr);
   2472             rv = bcm_esw_l3_egress_get(unit, encap_id, &l3_egr);
   2473             if (BCM_SUCCESS(rv)) {
   2474                 if ((l3_egr.flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_ENCRYPT) ||
   2475                     (l3_egr.flags2 & BCM_L3_FLAGS2_XFLOW_MACSEC_DECRYPT)) {
   2476                     /* Macsec IPMC requires macsec port (port 66) in
   2477                      * IPMC tables.
   2478                      */
   2479                     port_out = 66;
   2480                 }
   2481             }
   2482         }
   2483     }
   2484 #endif
   2485 
   2486     if (BCM_IF_INVALID != encap_id) {
   2487 
   2488 #ifdef BCM_TRIDENT2_SUPPORT
   2489         /* if this is a overlay NH enap id, then it
   2490          * is part of RioT flow.
   2491          * As part of that flow or L2 tunnel encap flow,
   2492          * the outer VPLS header will
   2493          * be added by underlay NH. No need to add anything from
   2494          * egress nh. so clear l3_payload field.
   2495          */
   2496         if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, encap_id)) {
   2497             int is_l3_mpls = 0;
   2498             int nh = encap_id - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   2499 
   2500             if (_BCM_MULTICAST_IS_L3(group) ||
   2501                 _BCM_MULTICAST_IS_EGRESS_OBJECT(group)) {
   2502                 BCM_IF_ERROR_RETURN(
   2503                     _bcm_esw_multicast_l3_mpls_nh_check(unit, nh, &is_l3_mpls));
   2504             }
   2505 
   2506             if (!is_l3_mpls) {
   2507                 int local_mc_idx = 0;
   2508                 egr_ipmc_entry_t   egr_ipmc_entry;
   2509                 local_mc_idx = _BCM_MULTICAST_ID_GET(mc_index);
   2510 
   2511                 BCM_IF_ERROR_RETURN(soc_mem_read(unit, EGR_IPMCm, MEM_BLOCK_ANY,
   2512                     local_mc_idx, &egr_ipmc_entry));
   2513                 soc_mem_field32_set(unit, EGR_IPMCm, &egr_ipmc_entry,
   2514                     L3_PAYLOADf, 0);
   2515                 BCM_IF_ERROR_RETURN(soc_mem_write(unit, EGR_IPMCm,
   2516                     MEM_BLOCK_ALL, local_mc_idx, &egr_ipmc_entry));
   2517             }
   2518         }
   2519 #endif
   2520 
   2521         /* Add all local ports in trunk to the multicast egress interface */
   2522         if (BCM_TRUNK_INVALID != trunk_id) {
   2523 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_TRIDENT2PLUS_SUPPORT)
   2524             if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) {
   2525                 BCM_IF_ERROR_RETURN(
   2526                     _bcm_esw_ipmc_egress_intf_add_for_trunk(
   2527                         unit, mc_index, trunk_id, encap_id, is_l3));
   2528             } else
   2529 #endif /* BCM_TOMAHAWK_SUPPORT || BCM_TRIDENT2PLUS_SUPPORT */
   2530             {
   2531                 idx_max = trunk_local_ports;
   2532                 for (idx = 0; idx < idx_max; idx++) {
   2533                     rv = _bcm_esw_ipmc_egress_intf_add(unit, mc_index,
   2534                                                    local_trunk_member_ports[idx],
   2535                                                    encap_id, is_l3);
   2536                     if (BCM_FAILURE(rv)) {
   2537                         while (idx--) {
   2538                             /* Error code ignored because we already in error */
   2539                             (void) _bcm_esw_ipmc_egress_intf_delete(unit,mc_index,
   2540                                                         local_trunk_member_ports[idx],
   2541                                                         if_max, encap_id, is_l3);
   2542                         }
   2543                         return rv;
   2544                     }
   2545                 }
   2546             }
   2547         } else {
   2548             /* Add  the required port to the multicast egress interface */
   2549             port_gport = port_out;
   2550 #if defined(BCM_HGPROXY_COE_SUPPORT)
   2551             if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   2552                 BCM_GPORT_IS_SET(port) &&
   2553                 _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) {
   2554                 port_gport = port;
   2555             }
   2556 #endif
   2557 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_TRIDENT2PLUS_SUPPORT)
   2558             if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) {
   2559                 BCM_IF_ERROR_RETURN(
   2560                     _bcm_esw_ipmc_egress_intf_add_in_per_trunk_mode(
   2561                         unit, mc_index, port_gport, encap_id, is_l3));
   2562             } else
   2563 #endif /* BCM_TOMAHAWK_SUPPORT || BCM_TRIDENT2PLUS_SUPPORT */
   2564             {
   2565                 BCM_IF_ERROR_RETURN(
   2566                     _bcm_esw_ipmc_egress_intf_add(unit, mc_index, port_gport,
   2567                                                   encap_id, is_l3));
   2568             }
   2569         }
   2570         new_pbmp = &l3_pbmp;
   2571     } else {
   2572         /* Updating the L2 bitmap */
   2573         new_pbmp = &l2_pbmp;
   2574     }
   2575 
   2576     /* Add port to the IPMC_L3_BITMAP or L2_BITMAP as decided above */
   2577     rv = _bcm_esw_multicast_ipmc_read(unit, mc_index, &l2_pbmp, &l3_pbmp);
   2578 
   2579     if (BCM_SUCCESS(rv)) {
   2580         BCM_PBMP_ASSIGN(old_pbmp, *new_pbmp);
   2581         if (BCM_TRUNK_INVALID != trunk_id) {
   2582             for (idx = 0; idx < trunk_local_ports; idx++) {
   2583                 BCM_PBMP_PORT_ADD(*new_pbmp, local_trunk_member_ports[idx]);
   2584             }
   2585         } else {
   2586             BCM_PBMP_PORT_ADD(*new_pbmp, port_out);
   2587         }
   2588 #if defined (BCM_HGPROXY_COE_SUPPORT)
   2589         /*
   2590          * If bcm_vlan_control_vlan_set is called before this API, L2_BITMAP
   2591          * may be intialized with the port bitmap including subtending ports.
   2592          * The subtending ports need to be deleted from the L2_BITMAP here.
   2593          */
   2594         if (is_local_subport) {
   2595             rv = bcm_esw_trunk_find(unit, 0, port, &subport_trunk_id);
   2596             if (BCM_SUCCESS(rv)) {
   2597                 trunk_member = sal_alloc(sizeof(bcm_trunk_member_t) *
   2598                                          SOC_MAX_NUM_PORTS, "trunk member");
   2599                 if (NULL == trunk_member) {
   2600                     return BCM_E_MEMORY;
   2601                 }
   2602                 rv = bcm_esw_trunk_get(unit, subport_trunk_id,
   2603                                        NULL, SOC_MAX_NUM_PORTS,
   2604                                        trunk_member, &member_count);
   2605                 if (BCM_FAILURE(rv)) {
   2606                     sal_free(trunk_member);
   2607                     return rv;
   2608                 }
   2609 
   2610                 for (idx = 0; idx < member_count; idx++) {
   2611                     rv = _bcm_esw_modid_is_local(unit,
   2612                                             _BCM_SUBPORT_COE_PORT_ID_MOD_GET(
   2613                                             trunk_member[idx].gport),
   2614                                             &is_local);
   2615                     if (BCM_FAILURE(rv)) {
   2616                         sal_free(trunk_member);
   2617                         return rv;
   2618                     }
   2619                     if (!is_local) {
   2620                         continue;
   2621                     }
   2622                     rv = bcm_esw_port_local_get(unit,
   2623                                                 trunk_member[idx].gport,
   2624                                                 &local_port);
   2625                     if (BCM_FAILURE(rv)) {
   2626                         sal_free(trunk_member);
   2627                         return rv;
   2628                     }
   2629                     BCM_PBMP_PORT_REMOVE(l2_pbmp, local_port);
   2630                 }
   2631                 is_subport_trunk = TRUE;
   2632                 if (NULL != trunk_member) {
   2633                     sal_free(trunk_member);
   2634                 }
   2635             } else {
   2636                 rv = BCM_E_NONE;
   2637                 is_subport_trunk = FALSE;
   2638             }
   2639         }
   2640 #endif
   2641         if (BCM_PBMP_NEQ(old_pbmp, *new_pbmp) ||
   2642             is_subport_trunk) {
   2643             rv = _bcm_esw_multicast_ipmc_write(unit, mc_index, l2_pbmp, 
   2644                                                l3_pbmp, TRUE);
   2645         }
   2646     } 
   2647     if (BCM_FAILURE(rv) && (encap_id != BCM_IF_INVALID)) {
   2648         if (BCM_TRUNK_INVALID != trunk_id) {
   2649 #if defined (BCM_TOMAHAWK_SUPPORT) || defined (BCM_TRIDENT2PLUS_SUPPORT)
   2650             if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) {
   2651                 BCM_IF_ERROR_RETURN(
   2652                     _bcm_esw_ipmc_egress_intf_del_for_trunk(
   2653                         unit, mc_index, trunk_id, if_max, encap_id, is_l3));
   2654             } else
   2655 #endif /* BCM_TOMAHAWK_SUPPORT || BCM_TRIDENT2PLUS_SUPPORT */
   2656             {
   2657                 idx_max = trunk_local_ports;
   2658                 for (idx = 0; idx < idx_max; idx++) {
   2659                     (void) _bcm_esw_ipmc_egress_intf_delete(unit,
   2660                                  mc_index, local_trunk_member_ports[idx],
   2661                                  if_max, encap_id, is_l3);
   2662                 }
   2663             }
   2664         } else {
   2665 #if defined (BCM_TOMAHAWK_SUPPORT) || defined (BCM_TRIDENT2PLUS_SUPPORT)
   2666             if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) {
   2667                 BCM_IF_ERROR_RETURN(
   2668                     _bcm_esw_ipmc_egress_intf_del_in_per_trunk_mode(
   2669                         unit, mc_index, port_out, if_max, encap_id, is_l3));
   2670             } else
   2671 #endif /* BCM_TOMAHAWK_SUPPORT || BCM_TRIDENT2PLUS_SUPPORT */
   2672             {
   2673                (void) _bcm_esw_ipmc_egress_intf_delete(unit, mc_index, port_out,
   2674                                    if_max, encap_id, is_l3);
   2675             }
   2676         }
   2677     }
   2678 
   2679     return rv;
   2680 }
   2681 
   2682 /*
   2683  * Function:
   2684  *      _bcm_esw_multicast_l3_delete
   2685  * Purpose:
   2686  *      Helper function to delete a port from L3 or Virtual multicast group
   2687  * Parameters:
   2688  *      unit      - (IN) Device Number
   2689  *      group     - (IN) Multicast group ID
   2690  *      port      - (IN) GPORT Identifier
   2691  *      encap_id  - (IN) Encap ID.
   2692  * Returns:
   2693  *      BCM_E_XXX
   2694  */
   2695 STATIC int 
   2696 _bcm_esw_multicast_l3_delete(int unit, bcm_multicast_t group, 
   2697                              bcm_gport_t port, bcm_if_t encap_id)
   2698 
   2699 {
   2700     int mc_index, is_l3, gport_id, i, idx, idx_max, trunk_local_ports = 0; 
   2701     bcm_module_t mod_out;
   2702     bcm_port_t port_out;
   2703     bcm_trunk_t trunk_id;
   2704     int modid_local, local_count, port_count, rv = BCM_E_NONE; 
   2705     bcm_port_t    temp_port = BCM_GPORT_INVALID;
   2706 #if defined(BCM_ESW_SUPPORT) && (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS)
   2707     bcm_port_t    local_trunk_member_ports[SOC_MAX_NUM_PP_PORTS] = {0};
   2708     int           max_num_ports = SOC_MAX_NUM_PP_PORTS;
   2709 #else
   2710     bcm_port_t    local_trunk_member_ports[SOC_MAX_NUM_PORTS] = {0};
   2711     int           max_num_ports = SOC_MAX_NUM_PORTS;
   2712 #endif
   2713     bcm_pbmp_t l2_pbmp, l3_pbmp, old_pbmp;
   2714     bcm_gport_t *port_array;
   2715     bcm_if_t *encap_array;
   2716     int if_max = BCM_MULTICAST_PORT_MAX;
   2717 
   2718 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
   2719     int is_local_subport = FALSE;
   2720 #endif
   2721 
   2722 #if defined(BCM_ENDURO_SUPPORT)
   2723     /* Size of "L3 Next hop table is limited to 2K on dagger(Enduro variant).
   2724      * On Ranger+ max replication interface is limited by 
   2725      * number of EGR_L3_Intfm.
   2726      */
   2727 
   2728     int nexthop_count = 0, egr_intf_count = 0;
   2729     if ((SOC_IS_ENDURO(unit) || (SOC_IS_METROLITE(unit)))) {
   2730         nexthop_count =  soc_mem_index_count(unit, ING_L3_NEXT_HOPm);
   2731         egr_intf_count = soc_mem_index_count(unit, EGR_L3_INTFm);
   2732         if_max = (nexthop_count < egr_intf_count)?
   2733                  ((if_max < nexthop_count)? if_max : nexthop_count):
   2734                  ((if_max < egr_intf_count)? if_max : egr_intf_count);
   2735     }
   2736 #endif /* BCM_ENDURO_SUPPORT || BCM_TRIUMPH3_SUPPORT */
   2737 
   2738 #if defined(BCM_TRIUMPH3_SUPPORT)
   2739     if (SOC_IS_TRIUMPH3(unit)) {
   2740         if_max = soc_mem_index_count(unit, EGR_L3_NEXT_HOPm);
   2741     }
   2742 #endif
   2743 
   2744 #if defined(BCM_HURRICANE_SUPPROT) || defined(BCM_HURRICANE2_SUPPORT)
   2745     if (SOC_IS_HURRICANE(unit) || SOC_IS_HURRICANE2(unit)) {
   2746         /* To assign proper if_max to avoid getting unexpected parameter
   2747          * validation error since if_max is 4096 by default.
   2748          */
   2749         if_max = soc_mem_index_count(unit, EGR_L3_INTFm);
   2750     }
   2751 #endif  /* BCM_HURRICANE_SUPPORT || BCM_HURRICANE2_SUPPORT */
   2752 #ifdef BCM_GREYHOUND_SUPPORT
   2753     if (soc_feature(unit, soc_feature_l3mc_use_egress_next_hop)) {
   2754         /* To assign proper if_max to avoid delete operation got unexpect 
   2755          * parameter validation error due to if_max is default at 4096.
   2756          *
   2757          * GH has egress logic changed for IPMC replication to reach 
   2758          *  EGR_L3_NEXT_HOPm before EGR_L3_INTFm. But the maximum replication 
   2759          *  still limited by EGR_L3_INTFm.
   2760          */
   2761         if_max = soc_mem_index_count(unit, EGR_L3_INTFm);
   2762     }
   2763 #endif /* BCM_GREYHOUND_SUPPORT */
   2764 
   2765 #ifdef BCM_TRIDENT2_SUPPORT
   2766 #ifdef BCM_TOMAHAWK3_SUPPORT
   2767     if (SOC_IS_TOMAHAWK3(unit)) {
   2768         if_max = TH3_IPMC_MAX_INTF_COUNT;
   2769     } else
   2770 #endif
   2771     if (SOC_IS_TD2_TT2(unit)) {
   2772         /* To assign proper if_max to avoid getting unexpected parameter
   2773          * validation error since if_max is 4096 by default.
   2774          */
   2775         if_max = soc_mem_index_count(unit, EGR_L3_NEXT_HOPm);
   2776     }
   2777 #endif
   2778 
   2779     is_l3 = 0;      /* Needed to support Firebolt style of L3 Multicast */
   2780     trunk_local_ports = 0; 
   2781     modid_local = FALSE;
   2782     port_count = local_count = 0;
   2783 
   2784     mc_index = _BCM_MULTICAST_ID_GET(group);
   2785 
   2786     if ((mc_index < 0) ||
   2787         (mc_index >= soc_mem_index_count(unit, L3_IPMCm))) {
   2788         return BCM_E_PARAM;
   2789     }
   2790 
   2791     BCM_IF_ERROR_RETURN(_bcm_esw_multicast_l3_group_check(unit, group, &is_l3));
   2792 
   2793 #if defined(BCM_TRIDENT_SUPPORT) && defined(INCLUDE_L3)
   2794     if (soc_feature(unit, soc_feature_trill)) {
   2795         if (_BCM_MULTICAST_IS_TRILL(group)) {
   2796              BCM_IF_ERROR_RETURN
   2797                 (bcm_td_trill_egress_delete(unit, group));
   2798         }
   2799     }
   2800 #endif /* BCM_TRIDENT_SUPPORT && INCLUDE_L3 */
   2801 
   2802     BCM_IF_ERROR_RETURN(
   2803         _bcm_esw_gport_resolve(unit, port, &mod_out, &port_out,
   2804                                &trunk_id, &gport_id));
   2805 
   2806 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
   2807     BCM_IF_ERROR_RETURN(
   2808         _bcm_esw_port_is_local_subport(
   2809             unit, port, mod_out, port_out, &is_local_subport, &port_out));
   2810 
   2811     if (is_local_subport) {
   2812         /* Local subport assigned above */
   2813     } else
   2814 #endif
   2815 
   2816     if (BCM_TRUNK_INVALID != trunk_id) {
   2817         BCM_IF_ERROR_RETURN(
   2818             _bcm_esw_trunk_local_members_get(unit, trunk_id, 
   2819                                              max_num_ports,
   2820                                              local_trunk_member_ports, 
   2821                                              &trunk_local_ports));
   2822         /* Convertion of system ports to physical ports done in */
   2823         /* _bcm_esw_trunk_local_members_get */
   2824     }
   2825 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_TRIDENT2PLUS_SUPPORT)
   2826    else if ((BCM_MC_PER_TRUNK_REPL_MODE(unit)) &&
   2827             (encap_id == BCM_ENCAP_TRUNK_MEMBER)) {
   2828         BCM_IF_ERROR_RETURN(
   2829             _bcm_esw_ipmc_egress_intf_del_trunk_member(
   2830                 unit, mc_index, port_out));
   2831     }
   2832 #endif /* BCM_TOMAHAWK_SUPPORT || BCM_TRIDENT2PLUS_SUPPORT */
   2833     else {
   2834         BCM_IF_ERROR_RETURN
   2835             (_bcm_esw_modid_is_local(unit, mod_out, &modid_local));
   2836         if (TRUE != modid_local) {
   2837             /* Only add this to replication set if destination is local */
   2838             return BCM_E_PORT;
   2839         }
   2840 
   2841         /* Convert system port to physical port */
   2842         if (soc_feature(unit, soc_feature_sysport_remap)) {
   2843             BCM_XLATE_SYSPORT_S2P(unit, &port_out);
   2844         }
   2845     }
   2846 
   2847 #ifdef BCM_TRIUMPH3_SUPPORT 
   2848     if (SOC_IS_TRIUMPH3(unit) || SOC_IS_KATANA2(unit)) {
   2849         if (_BCM_MULTICAST_IS_WLAN(group)) {
   2850             trunk_id = BCM_TRUNK_INVALID;
   2851             port_out = AXP_PORT(unit, SOC_AXP_NLF_WLAN_ENCAP);
   2852         }
   2853     }
   2854 #endif /* BCM_TRIUMPH3_SUPPORT */
   2855 
   2856     if (encap_id == BCM_IF_INVALID) {
   2857         /* Remove L2 port */
   2858 
   2859         soc_mem_lock(unit, L3_IPMCm);
   2860         /* Delete the port from the IPMC L2_BITMAP */
   2861         rv = _bcm_esw_multicast_ipmc_read(unit, mc_index, 
   2862                                           &l2_pbmp, &l3_pbmp);
   2863         if (BCM_SUCCESS(rv)) {
   2864             BCM_PBMP_ASSIGN(old_pbmp, l2_pbmp);
   2865             if (BCM_TRUNK_INVALID != trunk_id) {
   2866                 for (idx = 0; idx < trunk_local_ports; idx++) {
   2867                     BCM_PBMP_PORT_REMOVE(l2_pbmp,
   2868                                          local_trunk_member_ports[idx]);
   2869                 }
   2870             } else {
   2871                 BCM_PBMP_PORT_REMOVE(l2_pbmp, port_out);
   2872             }
   2873 
   2874             if (BCM_PBMP_NEQ(old_pbmp, l2_pbmp)) {
   2875                 rv = _bcm_esw_multicast_ipmc_write(unit, mc_index,
   2876                                         l2_pbmp, l3_pbmp, TRUE);
   2877             } else if (BCM_TRUNK_INVALID == trunk_id) {
   2878                 /* trying to remove members of an empty trunk is acceptable */
   2879                 rv = BCM_E_NOT_FOUND;
   2880             }
   2881         }
   2882         soc_mem_unlock(unit, L3_IPMCm);
   2883         return rv;
   2884     }
   2885 
   2886     /*
   2887      * Walk through the list of egress interfaces for this group.
   2888      * Check if the interface getting deleted is the ONLY
   2889      * instance of the local port in the replication list.
   2890      * If so, we can delete the port from the IPMC L3_BITMAP.
   2891      */
   2892     port_array = sal_alloc(if_max * sizeof(bcm_gport_t),
   2893                            "mcast port array");
   2894     if (port_array == NULL) {
   2895         return BCM_E_MEMORY;
   2896     }
   2897     encap_array = sal_alloc(if_max * sizeof(bcm_if_t),
   2898                             "mcast encap array");
   2899     if (encap_array == NULL) {
   2900         sal_free (port_array);
   2901         return BCM_E_MEMORY;
   2902     }
   2903 
   2904     rv = bcm_esw_multicast_egress_get(unit, group, if_max, 
   2905                                       port_array, encap_array, &port_count);
   2906     if (BCM_FAILURE(rv)) {
   2907         sal_free (port_array);
   2908         sal_free (encap_array);
   2909         return (rv);
   2910     } 
   2911 
   2912     for (i = 0; i < port_count ; i++) {
   2913         if (encap_id == encap_array[i]) {
   2914             /* Skip the one we're about to delete */
   2915             continue;
   2916         }
   2917 
   2918 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
   2919         is_local_subport = FALSE;
   2920 #endif
   2921 
   2922 #if defined(BCM_HGPROXY_COE_SUPPORT)
   2923         if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   2924             BCM_GPORT_IS_SET(port_array[i]) &&
   2925             _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port_array[i])) {
   2926                 is_local_subport = TRUE;
   2927 
   2928             rv = _bcmi_coe_subport_physical_port_get(unit,
   2929                                                      port_array[i],
   2930                                                      &temp_port);
   2931             if (BCM_FAILURE(rv)) {
   2932                 sal_free (port_array);
   2933                 sal_free (encap_array);
   2934                 return (rv);
   2935             }
   2936         } else
   2937 #endif
   2938 #if defined(BCM_KATANA2_SUPPORT)
   2939         if (soc_feature(unit, soc_feature_linkphy_coe) ||
   2940             soc_feature(unit, soc_feature_subtag_coe)) {
   2941             if (BCM_GPORT_IS_SET(port_array[i]) &&
   2942                 _BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit,
   2943                 port_array[i])) {
   2944                 is_local_subport = TRUE;
   2945                 temp_port = _BCM_KT2_SUBPORT_PORT_ID_GET(port_array[i]);
   2946             }
   2947         }
   2948 #endif
   2949 
   2950 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
   2951         if (is_local_subport) {
   2952             /* Local subport assigned above */
   2953         } else
   2954 #endif
   2955         {
   2956             (void) bcm_esw_port_local_get(unit, port_array[i], &temp_port);
   2957         }
   2958 
   2959         if (temp_port == port_out) {
   2960             local_count = 1;
   2961             break;
   2962         } else {
   2963             for (idx = 0; idx < trunk_local_ports; idx++) {
   2964                 if (temp_port == local_trunk_member_ports[idx]) {
   2965                        local_count = 1;
   2966                        break;
   2967                     }
   2968             }
   2969             if (local_count) {
   2970                 break;
   2971             }
   2972         }
   2973     }
   2974     sal_free(port_array);
   2975     sal_free(encap_array);
   2976 
   2977     if (!local_count) {
   2978         soc_mem_lock(unit, L3_IPMCm);
   2979         rv = _bcm_esw_multicast_ipmc_read(unit, mc_index, 
   2980                                           &l2_pbmp, &l3_pbmp);
   2981         if (BCM_SUCCESS(rv)) {
   2982             if (BCM_TRUNK_INVALID != trunk_id) {
   2983                 for (idx = 0; idx < trunk_local_ports; idx++) {
   2984                     BCM_PBMP_PORT_REMOVE(l3_pbmp,
   2985                                          local_trunk_member_ports[idx]);
   2986                 }
   2987             } else {
   2988                 BCM_PBMP_PORT_REMOVE(l3_pbmp, port_out);
   2989             }
   2990             rv = _bcm_esw_multicast_ipmc_write(unit, mc_index, l2_pbmp,
   2991                                                l3_pbmp, TRUE);
   2992         }
   2993         soc_mem_unlock(unit, L3_IPMCm);
   2994         BCM_IF_ERROR_RETURN(rv);
   2995     }
   2996 
   2997     if (BCM_TRUNK_INVALID != trunk_id) {
   2998 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_TRIDENT2PLUS_SUPPORT)
   2999         if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) {
   3000             BCM_IF_ERROR_RETURN(
   3001                 _bcm_esw_ipmc_egress_intf_del_for_trunk(
   3002                     unit, mc_index, trunk_id, if_max, encap_id, is_l3));
   3003         } else
   3004 #endif /* BCM_TOMAHAWK_SUPPORT || BCM_TRIDENT2PLUS_SUPPORT */
   3005         {
   3006             idx_max = trunk_local_ports;
   3007             for (idx = 0; idx < idx_max; idx++) {
   3008                 rv =  _bcm_esw_ipmc_egress_intf_delete(unit, mc_index,
   3009                                     local_trunk_member_ports[idx], if_max,
   3010                                                    encap_id, is_l3);
   3011                 if (rv < 0) {
   3012                     while (idx--) {
   3013                         (void) _bcm_esw_ipmc_egress_intf_add(unit, mc_index,
   3014                                     local_trunk_member_ports[idx], encap_id, is_l3);
   3015                     }
   3016                     return rv;
   3017                 }
   3018             }
   3019          }
   3020     } else {
   3021  #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_TRIDENT2PLUS_SUPPORT)
   3022         if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) {
   3023             BCM_IF_ERROR_RETURN(
   3024                 _bcm_esw_ipmc_egress_intf_del_in_per_trunk_mode(
   3025                     unit, mc_index, port_out, if_max, encap_id, is_l3));
   3026         } else
   3027 #endif /* BCM_TOMAHAWK_SUPPORT || BCM_TRIDENT2PLUS_SUPPORT */
   3028         {
   3029             rv =  _bcm_esw_ipmc_egress_intf_delete(unit, mc_index, port_out,
   3030                                                if_max, encap_id, is_l3);
   3031         }
   3032     }
   3033 
   3034     return rv;
   3035 }
   3036 
   3037 
   3038 /*
   3039  * Function:
   3040  *      _bcm_esw_multicast_l3_get
   3041  * Purpose:
   3042  *      Helper function to get ports that are part of L3 or Virtual multicast 
   3043  * Parameters: 
   3044  *      unit           - (IN) Device Number
   3045  *      mc_index       - (IN) Multicast index
   3046  *      port_max       - (IN) Number of entries in "port_array"
   3047  *      port_array     - (OUT) List of ports
   3048  *      encap_id_array - (OUT) List of encap identifiers
   3049  *      port_count     - (OUT) Actual number of ports returned
   3050  * Returns:
   3051  *      BCM_E_XXX
   3052  * Notes:
   3053  *      If the input parameter port_max = 0, return in the output parameter
   3054  *      port_count the total number of ports/encapsulation IDs in the 
   3055  *      specified multicast group's replication list.
   3056  */
   3057 
   3058 STATIC int     
   3059 _bcm_esw_multicast_l3_get(int unit, bcm_multicast_t group, int port_max,
   3060                              bcm_gport_t *port_array, bcm_if_t *encap_id_array, 
   3061                              int *port_count)
   3062 {
   3063     int             mc_index, i, count, rv;
   3064     bcm_pbmp_t      ether_higig_pbmp, l2_pbmp, l3_pbmp;
   3065     bcm_port_t      port_iter;
   3066     bcm_if_t        *local_id_array;
   3067 #if defined(BCM_KATANA2_SUPPORT)
   3068     int is_local_subport = FALSE;
   3069 #endif
   3070 
   3071     i= 0;
   3072     rv = BCM_E_NONE;
   3073     local_id_array = NULL;
   3074 
   3075     mc_index = _BCM_MULTICAST_ID_GET(group);
   3076     if ((mc_index < 0) ||
   3077         (mc_index >= soc_mem_index_count(unit, L3_IPMCm))) {
   3078         return BCM_E_PARAM;
   3079     }
   3080 
   3081     BCM_IF_ERROR_RETURN(_bcm_esw_multicast_l3_group_check(unit, group, NULL));
   3082 
   3083     if (port_max > 0) {
   3084         local_id_array = sal_alloc(sizeof(bcm_if_t) * port_max,
   3085                                    "local array of interfaces");
   3086         if (NULL == local_id_array) {
   3087             return BCM_E_MEMORY;
   3088         }
   3089         sal_memset(local_id_array, 0x00, sizeof(bcm_if_t) * port_max);
   3090     }
   3091 
   3092     /* Collect list of GPORTs for each front-panel and Higig port. */
   3093     *port_count = 0;
   3094     BCM_PBMP_ASSIGN(ether_higig_pbmp, PBMP_E_ALL(unit));
   3095     BCM_PBMP_OR(ether_higig_pbmp, PBMP_HG_ALL(unit));
   3096 
   3097     /* CPU ports are valid for replication on TD2 */
   3098     if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWKX(unit)) {
   3099         BCM_PBMP_OR(ether_higig_pbmp, PBMP_CMIC(unit));
   3100     }
   3101     if (soc_feature(unit, soc_feature_axp)) {
   3102         if (_BCM_MULTICAST_IS_WLAN(group)) {
   3103             BCM_PBMP_PORT_SET(ether_higig_pbmp,
   3104                               AXP_PORT(unit, SOC_AXP_NLF_WLAN_ENCAP));
   3105         }
   3106     }
   3107 #if defined(BCM_KATANA2_SUPPORT)
   3108     if (soc_feature(unit, soc_feature_subtag_coe) ||
   3109         soc_feature(unit, soc_feature_linkphy_coe)) {
   3110         _bcm_kt2_subport_pbmp_update(unit, &ether_higig_pbmp);
   3111     }
   3112 #endif
   3113     BCM_PBMP_ITER(ether_higig_pbmp, port_iter) {
   3114         if (port_max > 0) {
   3115             rv = bcm_esw_ipmc_egress_intf_get(unit, mc_index, port_iter,
   3116                                              port_max - *port_count, 
   3117                                              local_id_array, 
   3118                                              &count);
   3119         } else {
   3120             rv = bcm_esw_ipmc_egress_intf_get(unit, mc_index, port_iter,
   3121                                              0,
   3122                                              NULL, 
   3123                                              &count);
   3124         }
   3125         if (BCM_FAILURE(rv)) {
   3126             sal_free((void *)local_id_array);
   3127             return rv;
   3128         }
   3129 #if defined(BCM_KATANA2_SUPPORT)
   3130         /* For KT2, pp_port >=42 are used for LinkPHY/SubportPktTag subport.
   3131          * Get the subport info associated with the pp_port and
   3132          * form the subport_gport.
   3133          */ 
   3134         is_local_subport = FALSE;
   3135         if (_bcm_kt2_is_pp_port_linkphy_subtag(unit, port_iter)) {
   3136             is_local_subport = TRUE;
   3137         }
   3138 #endif
   3139 
   3140         for (i = 0; i < count; i++) {
   3141             /* Copy data to provided arrays */
   3142             if ((NULL != encap_id_array) && (NULL != local_id_array)) {
   3143                 if (soc_feature(unit, soc_feature_l3mc_use_egress_next_hop)) {
   3144                     /* Translate the HW index to encap_id */
   3145                     encap_id_array[*port_count + i] = local_id_array[i] +
   3146                             BCM_XGS3_EGRESS_IDX_MIN(unit);
   3147                 } else {
   3148                     encap_id_array[*port_count + i] = local_id_array[i];
   3149                 }
   3150             }
   3151             if (NULL != port_array) {
   3152                 /* Convert to GPORT values */
   3153 #if defined(BCM_KATANA2_SUPPORT)
   3154                 if (is_local_subport) {
   3155 
   3156                     _BCM_KT2_SUBPORT_PORT_ID_SET(port_array[*port_count + i],
   3157                             port_iter);
   3158                     if (BCM_PBMP_MEMBER(
   3159                         SOC_INFO(unit).linkphy_pp_port_pbm, port_iter)) {
   3160                         _BCM_KT2_SUBPORT_PORT_TYPE_SET(
   3161                             port_array[*port_count + i],
   3162                             _BCM_KT2_SUBPORT_TYPE_LINKPHY);
   3163                     } else if (BCM_PBMP_MEMBER(
   3164                         SOC_INFO(unit).subtag_pp_port_pbm, port_iter)) {
   3165                         _BCM_KT2_SUBPORT_PORT_TYPE_SET(
   3166                             port_array[*port_count + i],
   3167                             _BCM_KT2_SUBPORT_TYPE_SUBTAG);
   3168                     } else {
   3169                         sal_free((void *)local_id_array);
   3170                         return BCM_E_PORT;
   3171                     }
   3172                 } else
   3173 #endif /* BCM_KATANA2_SUPPORT */
   3174                 {
   3175                     rv = bcm_esw_port_gport_get(unit, port_iter, 
   3176                                   &(port_array[(*port_count + i)]));
   3177                     if (BCM_FAILURE(rv)) {
   3178                         sal_free((void *)local_id_array);
   3179                         return rv;
   3180                     }
   3181                 }
   3182             }
   3183         }
   3184         *port_count += count;
   3185         if ((port_max > 0) && (*port_count == port_max)) {
   3186             break;
   3187         }
   3188     }
   3189 
   3190     /* Check for L2 ports */
   3191     rv =_bcm_esw_multicast_ipmc_read(unit, mc_index, &l2_pbmp, &l3_pbmp);
   3192     if (BCM_FAILURE(rv)) {
   3193         sal_free((void *)local_id_array);
   3194         return rv;
   3195     }
   3196 
   3197     BCM_PBMP_ITER(l2_pbmp, port_iter) {
   3198         if ((port_max > 0) && (*port_count == port_max)) {
   3199             break;
   3200         }
   3201         if (NULL != port_array) {
   3202 #if defined(BCM_KATANA2_SUPPORT)
   3203             /* For KT2, pp_port >=42 are used for LinkPHY/SubportPktTag subport.
   3204              * Get the subport info associated with the pp_port and
   3205              * form the subport_gport.
   3206              */ 
   3207             is_local_subport = FALSE;
   3208             if (_bcm_kt2_is_pp_port_linkphy_subtag(unit, port_iter)) {
   3209                 is_local_subport = TRUE;
   3210             }
   3211             if (is_local_subport) {
   3212                 _BCM_KT2_SUBPORT_PORT_ID_SET(port_array[*port_count],
   3213                     port_iter);
   3214                 if (BCM_PBMP_MEMBER(
   3215                     SOC_INFO(unit).linkphy_pp_port_pbm, port_iter)) {
   3216                     _BCM_KT2_SUBPORT_PORT_TYPE_SET(port_array[*port_count],
   3217                         _BCM_KT2_SUBPORT_TYPE_LINKPHY);
   3218                 } else if (BCM_PBMP_MEMBER(
   3219                     SOC_INFO(unit).subtag_pp_port_pbm, port_iter)) {
   3220                     _BCM_KT2_SUBPORT_PORT_TYPE_SET(port_array[*port_count],
   3221                         _BCM_KT2_SUBPORT_TYPE_SUBTAG);
   3222                 } else {
   3223                     sal_free((void *)local_id_array);
   3224                     return BCM_E_PORT;
   3225                 }
   3226     
   3227             } else
   3228 #endif /* BCM_KATANA2_SUPPORT */
   3229             {
   3230                 rv = bcm_esw_port_gport_get(unit, port_iter, 
   3231                                         &(port_array[*port_count]));
   3232 
   3233                 if (BCM_FAILURE(rv)) {
   3234                     sal_free((void *)local_id_array);
   3235                     return rv;
   3236                 }
   3237             }
   3238         }
   3239         if (NULL != encap_id_array) {
   3240             encap_id_array[*port_count] = BCM_IF_INVALID;
   3241         }
   3242         *port_count += 1;
   3243     }
   3244 
   3245     if (local_id_array) {
   3246         sal_free((void *)local_id_array);
   3247     }
   3248     return rv;
   3249 }
   3250 
   3251 /*
   3252  * Function:
   3253  *      _bcm_esw_multicast_l3_create
   3254  * Purpose:
   3255  *      Helper function to allocate a multicast group index for L3 or Virtual
   3256  * Parameters:
   3257  *      unit       - (IN)   Device Number
   3258  *      flags      - (IN)   BCM_MULTICAST_*
   3259  *      group      - (OUT)  Group ID
   3260  * Returns:
   3261  *      BCM_E_XXX
   3262  */
   3263 STATIC int
   3264 _bcm_esw_multicast_l3_create(int unit, uint32 flags, bcm_multicast_t *group)
   3265 {
   3266     int                 mc_index, rv;
   3267     int                 is_set = FALSE;
   3268     egr_ipmc_entry_t    egr_ipmc;
   3269     bcm_pbmp_t          active, l2_pbmp, l3_pbmp;
   3270     uint32              type;
   3271     uint32 entry[SOC_MAX_MEM_FIELD_WORDS];  /* hw entry bufffer. */
   3272 
   3273     /* Check if IPMC module is initialized */
   3274     IPMC_INIT(unit);
   3275 
   3276     rv  = BCM_E_NONE;
   3277     type = flags & BCM_MULTICAST_TYPE_MASK;
   3278 
   3279     if (flags & BCM_MULTICAST_WITH_ID) {
   3280         mc_index = _BCM_MULTICAST_ID_GET(*group);
   3281         if ((mc_index < 0) ||
   3282             (mc_index >= soc_mem_index_count(unit, L3_IPMCm))) {
   3283             return BCM_E_PARAM;
   3284         }
   3285         rv = bcm_xgs3_ipmc_id_is_set(unit, mc_index, &is_set);
   3286         if (BCM_SUCCESS(rv)) {
   3287             if (is_set) {
   3288                 return BCM_E_EXISTS;
   3289             }
   3290         } else {
   3291             return rv;
   3292         }
   3293         rv = bcm_xgs3_ipmc_id_alloc(unit, mc_index);
   3294         if (BCM_FAILURE(rv)) {
   3295             return rv;
   3296         }
   3297     } else {
   3298         /* Allocate an IPMC index */
   3299         BCM_IF_ERROR_RETURN(bcm_xgs3_ipmc_create(unit, &mc_index));
   3300     }
   3301 
   3302     /*Per IPMC Group Attributes */
   3303     sal_memset(&egr_ipmc, 0, sizeof(egr_ipmc));
   3304 
   3305     /* For L3 IPMC case , L3_PAYLOAD must be set to 1 */
   3306     if (soc_feature(unit, soc_feature_egr_ipmc_mem_field_l3_payload_valid) &&
   3307            (type == BCM_MULTICAST_TYPE_L3)) {
   3308         uint32 val=1;
   3309         soc_EGR_IPMCm_field_set(unit, &egr_ipmc, L3_PAYLOADf, &val);
   3310     }
   3311 
   3312     if ((type & _BCM_VIRTUAL_TYPES_MASK) && 
   3313         (type != BCM_MULTICAST_TYPE_WLAN)) {
   3314         if (soc_mem_field_valid(unit, EGR_IPMCm, REPLICATION_TYPEf)) {
   3315             soc_EGR_IPMCm_field32_set(unit, &egr_ipmc,
   3316                                       REPLICATION_TYPEf, 0x1);
   3317             /* Next-hop indexes from MMU */
   3318         }
   3319         if (soc_mem_field_valid(unit, EGR_IPMCm, DONT_PRUNE_VLANf)) {
   3320             soc_EGR_IPMCm_field32_set(unit, &egr_ipmc, DONT_PRUNE_VLANf, 1);
   3321         }
   3322     }
   3323 
   3324     /* Commit the values to HW */
   3325     if (SOC_MEM_IS_VALID(unit, EGR_IPMCm)) {
   3326         rv = WRITE_EGR_IPMCm(unit, MEM_BLOCK_ALL, mc_index, &egr_ipmc);
   3327         if (BCM_FAILURE(rv)) {
   3328             (void) bcm_xgs3_ipmc_id_free(unit, mc_index);
   3329             return rv;
   3330         }
   3331     }
   3332 
   3333     /* Add stack ports to L2 PBMP */
   3334     BCM_PBMP_CLEAR(l2_pbmp);
   3335     BCM_PBMP_CLEAR(l3_pbmp);
   3336     SOC_PBMP_STACK_ACTIVE_GET(unit, active);
   3337     BCM_PBMP_OR(l2_pbmp, active);
   3338     BCM_PBMP_REMOVE(l2_pbmp, SOC_PBMP_STACK_INACTIVE(unit));
   3339 
   3340     rv = _bcm_esw_multicast_ipmc_write(unit, mc_index, l2_pbmp,
   3341                                        l3_pbmp, TRUE);
   3342     if (BCM_FAILURE(rv)) {
   3343         sal_memset(&egr_ipmc, 0, sizeof(egr_ipmc));
   3344         if (SOC_MEM_IS_VALID(unit, EGR_IPMCm)) {
   3345             (void) WRITE_EGR_IPMCm(unit, MEM_BLOCK_ALL, mc_index, 
   3346                                    &egr_ipmc);
   3347             (void) bcm_xgs3_ipmc_id_free(unit, mc_index);
   3348             return rv;
   3349         }
   3350     }
   3351 
   3352     if (type == BCM_MULTICAST_TYPE_L3) {
   3353         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_L3,
   3354                                  mc_index);
   3355     } else if (type == BCM_MULTICAST_TYPE_VPLS) {
   3356         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_VPLS,
   3357                                  mc_index);
   3358     } else if (type == BCM_MULTICAST_TYPE_MIM) {
   3359         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_MIM,
   3360                                  mc_index);
   3361     } else if (type == BCM_MULTICAST_TYPE_WLAN) {
   3362         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_WLAN,
   3363                                  mc_index);
   3364     } else if (type == BCM_MULTICAST_TYPE_SUBPORT) {
   3365         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_SUBPORT,
   3366                                  mc_index);
   3367     }else if (type == BCM_MULTICAST_TYPE_TRILL) {
   3368         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_TRILL,
   3369                                  mc_index);
   3370     } else if (type == BCM_MULTICAST_TYPE_VLAN) {
   3371         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_VLAN,
   3372                                  mc_index);
   3373     } else if (type == BCM_MULTICAST_TYPE_NIV) {
   3374         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_NIV,
   3375                                  mc_index);
   3376     } else if (type == BCM_MULTICAST_TYPE_EGRESS_OBJECT) {
   3377         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_EGRESS_OBJECT,
   3378                                  mc_index);
   3379     } else if (type == BCM_MULTICAST_TYPE_L2GRE) {
   3380         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_L2GRE,
   3381                                  mc_index);
   3382     } else if (type == BCM_MULTICAST_TYPE_VXLAN) {
   3383         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_VXLAN,
   3384                                  mc_index);
   3385     } else if (type == BCM_MULTICAST_TYPE_FLOW) {
   3386         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_FLOW,
   3387                                  mc_index);
   3388     } else if (type == BCM_MULTICAST_TYPE_EXTENDER) {
   3389         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_EXTENDER,
   3390                                  mc_index);
   3391     }
   3392 
   3393     if (soc_feature(unit, soc_feature_trill)) {
   3394         if (type == BCM_MULTICAST_TYPE_TRILL) {
   3395             if (SOC_MEM_FIELD_VALID(unit, L3_IPMCm, REMOVE_SGLP_FROM_L3_BITMAPf)) {
   3396                 rv = soc_mem_read(unit, L3_IPMCm, MEM_BLOCK_ANY, mc_index, entry);
   3397                 if (BCM_SUCCESS(rv)) {
   3398                     soc_mem_field32_set(unit, L3_IPMCm, entry, 
   3399                                     REMOVE_SGLP_FROM_L3_BITMAPf, 0x1);
   3400                     rv = soc_mem_write(unit, L3_IPMCm, MEM_BLOCK_ALL, mc_index, &entry);
   3401                 }
   3402             }
   3403         }
   3404     }
   3405 
   3406     if (BCM_SUCCESS(rv) && SOC_IS_TRX(unit)) {
   3407         /* Record IPMC types for reference */
   3408         rv = _bcm_tr_multicast_ipmc_group_type_set(unit, *group);
   3409     }
   3410 
   3411     return rv;
   3412 }
   3413 
   3414 
   3415 /*
   3416  * Function:
   3417  *      _bcm_esw_multicast_l3_destroy
   3418  * Purpose:
   3419  *      Helper function to destroy L3 and Virtual multicast 
   3420  * Parameters: 
   3421  *      unit           - (IN) Device Number
   3422  *      group          - (IN) Multicast group to destroy
   3423  * Returns:
   3424  *      BCM_E_XXX
   3425  */
   3426 
   3427 STATIC int     
   3428 _bcm_esw_multicast_l3_destroy(int unit, bcm_multicast_t group)
   3429 {
   3430     int                 is_l3, mc_index;
   3431     bcm_port_t          port_iter;
   3432     bcm_pbmp_t          ether_higig_pbmp, l2_pbmp, l3_pbmp;
   3433     egr_ipmc_entry_t    egr_ipmc;
   3434 
   3435 
   3436     /* Check if IPMC module is initialized */
   3437     IPMC_INIT(unit);
   3438 
   3439     is_l3 = 0;
   3440     
   3441     BCM_IF_ERROR_RETURN(_bcm_esw_multicast_l3_group_check(unit, group, &is_l3));
   3442 
   3443     mc_index = _BCM_MULTICAST_ID_GET(group);
   3444     if ((mc_index < 0) || (mc_index >= soc_mem_index_count(unit, L3_IPMCm))) {
   3445         return BCM_E_PARAM;
   3446     }
   3447 
   3448     /* Decrement ref count by calling 'free' */
   3449     BCM_IF_ERROR_RETURN(bcm_xgs3_ipmc_id_free(unit, mc_index));
   3450 
   3451     if (IPMC_USED_ISSET(unit, mc_index)) {
   3452         /* Group is in use, correct the ref count
   3453          * decremented by above 'free' and return error. */
   3454         IPMC_USED_SET(unit, mc_index)                                   \
   3455         return BCM_E_BUSY;
   3456     } else { /* Ref count is zero. Group is not being used. */
   3457         /* Clear the replication set */
   3458         BCM_IF_ERROR_RETURN(
   3459         _bcm_esw_multicast_ipmc_read(unit, mc_index, &l2_pbmp, &l3_pbmp));
   3460         if(is_l3) {
   3461            BCM_PBMP_ASSIGN(ether_higig_pbmp, l3_pbmp);
   3462         } else {
   3463            BCM_PBMP_ASSIGN(ether_higig_pbmp, l2_pbmp);
   3464         }
   3465         BCM_PBMP_OR(ether_higig_pbmp, PBMP_HG_ALL(unit));
   3466         /* CPU ports are valid for replication on TD2 */
   3467         if (SOC_IS_TRIDENT2X(unit)) {
   3468             BCM_PBMP_OR(ether_higig_pbmp, PBMP_CMIC(unit));
   3469         }
   3470         if (soc_feature(unit, soc_feature_axp)) {
   3471             if (_BCM_MULTICAST_IS_WLAN(group)) {
   3472                 BCM_PBMP_PORT_SET(ether_higig_pbmp,
   3473                                   AXP_PORT(unit, SOC_AXP_NLF_WLAN_ENCAP));
   3474             }
   3475         }
   3476 #if defined(BCM_KATANA2_SUPPORT)
   3477         if (soc_feature(unit, soc_feature_subtag_coe) ||
   3478             soc_feature(unit, soc_feature_linkphy_coe)) {
   3479            _bcm_kt2_subport_pbmp_update(unit, &ether_higig_pbmp);
   3480        }
   3481 #endif
   3482 
   3483 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_TRIDENT2PLUS_SUPPORT)
   3484         if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) {
   3485             BCM_IF_ERROR_RETURN(
   3486                 _bcm_esw_ipmc_egress_intf_destroy_in_trunk_repl_mode(
   3487                      unit, mc_index, ether_higig_pbmp, is_l3));
   3488         } else
   3489 #endif /* BCM_TOMAHAWK_SUPPORT || BCM_TRIDENT2PLUS_SUPPORT */
   3490         {
   3491             BCM_PBMP_ITER(ether_higig_pbmp, port_iter) {
   3492                 BCM_IF_ERROR_RETURN(
   3493                      _bcm_esw_ipmc_egress_intf_set(unit, mc_index, port_iter, 0,
   3494                                                    NULL, is_l3, FALSE));
   3495             }
   3496         }
   3497 
   3498         /* Clear the IPMC related tables */
   3499         BCM_PBMP_CLEAR(l2_pbmp);
   3500         BCM_PBMP_CLEAR(l3_pbmp);
   3501 
   3502         BCM_IF_ERROR_RETURN(
   3503         _bcm_esw_multicast_ipmc_write(unit, mc_index, l2_pbmp, l3_pbmp, FALSE));
   3504 
   3505         if (SOC_MEM_IS_VALID(unit, EGR_IPMCm)) {
   3506             sal_memset(&egr_ipmc, 0, sizeof(egr_ipmc));
   3507             BCM_IF_ERROR_RETURN
   3508                 (WRITE_EGR_IPMCm(unit, MEM_BLOCK_ALL, mc_index, &egr_ipmc));
   3509         }
   3510 
   3511         /* Free IPMC type record */
   3512         if (SOC_IS_TRX(unit)) {
   3513             BCM_IF_ERROR_RETURN(
   3514                 _bcm_tr_multicast_ipmc_group_type_set(unit, mc_index));
   3515         }
   3516     }
   3517     
   3518     return BCM_E_NONE;
   3519 }
   3520 #endif /* INCLUDE_L3 */
   3521 
   3522 /*
   3523  * Function:
   3524  *      _bcm_esw_multicast_type_validate
   3525  * Purpose:
   3526  *      Helper function to validate multicast type support 
   3527  * Parameters:
   3528  *      unit       - (IN)   Device Number
   3529  *      type       - (IN)   BCM_MULTICAST_TYPE_*
   3530  * Returns:
   3531  *      BCM_E_XXX
   3532  */
   3533 STATIC int 
   3534 _bcm_esw_multicast_type_validate(int unit, uint32 type)
   3535 {
   3536     int rv; 
   3537 
   3538     /* Only single multicast type is allowed per API call */
   3539     /* therefore number of bits on indicating Multicast type must equal to 1 */
   3540     if (1 != _shr_popcount(type)) {
   3541         return BCM_E_PARAM;
   3542     }
   3543 
   3544     rv = BCM_E_PARAM; /* return error by default */
   3545 
   3546     switch (type) {
   3547         case BCM_MULTICAST_TYPE_L2: 
   3548             rv = BCM_E_NONE;
   3549             break;
   3550         case BCM_MULTICAST_TYPE_L3: 
   3551             if (soc_feature(unit, soc_feature_ip_mcast_repl)) {
   3552                 rv = BCM_E_NONE;
   3553             }else {
   3554                 rv = BCM_E_UNAVAIL;
   3555             }
   3556             break;
   3557         case BCM_MULTICAST_TYPE_VPLS:
   3558             if (soc_feature(unit, soc_feature_mpls)) {
   3559                 rv = BCM_E_NONE;
   3560             } else {
   3561                 rv = BCM_E_UNAVAIL;
   3562             }
   3563             break;
   3564         case BCM_MULTICAST_TYPE_SUBPORT:
   3565             if (soc_feature(unit, soc_feature_subport)) {
   3566                 rv = BCM_E_NONE;
   3567             }
   3568             break;
   3569         case BCM_MULTICAST_TYPE_MIM:
   3570             if (soc_feature(unit, soc_feature_mim)) {
   3571                 rv = BCM_E_NONE;
   3572             }
   3573             break;
   3574         case BCM_MULTICAST_TYPE_WLAN:
   3575             if (soc_feature(unit, soc_feature_wlan)) {
   3576                 rv = BCM_E_NONE;
   3577             }
   3578             break;
   3579         case BCM_MULTICAST_TYPE_VLAN:
   3580             if (soc_feature(unit, soc_feature_vlan_vp)) {
   3581                 rv = BCM_E_NONE;
   3582             }
   3583             break;
   3584         case BCM_MULTICAST_TYPE_TRILL:
   3585             if (soc_feature(unit, soc_feature_trill)) {
   3586                 rv = BCM_E_NONE;
   3587             }
   3588             break;
   3589         case BCM_MULTICAST_TYPE_NIV:
   3590             if (soc_feature(unit, soc_feature_niv)) {
   3591                 rv = BCM_E_NONE;
   3592             }
   3593             break;
   3594         case BCM_MULTICAST_TYPE_EGRESS_OBJECT:
   3595             if (soc_feature(unit, soc_feature_mpls)) {
   3596                 rv = BCM_E_NONE;
   3597             }
   3598             break;
   3599         case BCM_MULTICAST_TYPE_L2GRE:
   3600             if (soc_feature(unit, soc_feature_l2gre)) {
   3601                 rv = BCM_E_NONE;
   3602             } else {
   3603                 rv = BCM_E_UNAVAIL;
   3604             }
   3605             break;
   3606         case BCM_MULTICAST_TYPE_VXLAN:
   3607             if (soc_feature(unit, soc_feature_vxlan) ||
   3608                 soc_feature(unit, soc_feature_vxlan_lite)) {
   3609                 rv = BCM_E_NONE;
   3610             } else {
   3611                 rv = BCM_E_UNAVAIL;
   3612             }
   3613             break;
   3614         case BCM_MULTICAST_TYPE_FLOW:
   3615             if (soc_feature(unit, soc_feature_flex_flow)) {
   3616                 rv = BCM_E_NONE;
   3617             } else {
   3618                 rv = BCM_E_UNAVAIL;
   3619             }
   3620             break;
   3621         case BCM_MULTICAST_TYPE_EXTENDER:
   3622             if (soc_feature(unit, soc_feature_port_extension)) {
   3623                 rv = BCM_E_NONE;
   3624             }
   3625             break;
   3626 
   3627         default:
   3628             rv = BCM_E_PARAM;
   3629     }
   3630 
   3631     return rv;
   3632 }
   3633 
   3634 /*
   3635  * Function:
   3636  *      _bcm_multicast_create
   3637  * Purpose:
   3638  *      Helper function to allocate a multicast group index
   3639  * Parameters:
   3640  *      unit       - (IN)   Device Number
   3641  *      flags      - (IN)   BCM_MULTICAST_*
   3642  *      group      - (OUT)  Group ID
   3643  * Returns:
   3644  *      BCM_E_XXX
   3645  */
   3646 STATIC int
   3647 _bcm_esw_multicast_create(int unit, uint32 flags, bcm_multicast_t *group)
   3648 {
   3649     uint32 type;
   3650 
   3651     type = flags & BCM_MULTICAST_TYPE_MASK;
   3652 
   3653     BCM_IF_ERROR_RETURN(
   3654         _bcm_esw_multicast_type_validate(unit, type));
   3655 
   3656     if (type == BCM_MULTICAST_TYPE_L2) {
   3657         /* Create L2 multicast group */
   3658         return _bcm_esw_multicast_l2_create(unit, flags, group);
   3659     } else {
   3660 #if defined(INCLUDE_L3)
   3661         /* Create L3/Virtual multicast group */
   3662         return _bcm_esw_multicast_l3_create(unit, flags, group);
   3663 #endif /* INCLUDE_L3 */
   3664     }
   3665 
   3666     return BCM_E_UNAVAIL;
   3667 }
   3668 
   3669 
   3670 /* Macro to free memory and return code instead of using goto */
   3671 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_TOMAHAWK_SUPPORT)
   3672 #define BCM_MULTICAST_MEM_FREE_RETURN(_r_)                      \
   3673         if (local_trunk_port_array) {                           \
   3674             for (j = 0; j < port_count; j++) {                  \
   3675                 if (local_trunk_port_array[j]) {                \
   3676                     sal_free(local_trunk_port_array[j]);        \
   3677                 }                                               \
   3678             }                                                   \
   3679             sal_free(local_trunk_port_array);                   \
   3680         }                                                       \
   3681         if (local_port_array) {                                 \
   3682             sal_free(local_port_array);                         \
   3683         }                                                       \
   3684         if (trunk_local_ports) {                                \
   3685             sal_free(trunk_local_ports);                        \
   3686         }                                                       \
   3687         if (temp_encap_list) {                                  \
   3688             sal_free(temp_encap_list);                          \
   3689             temp_encap_list = NULL;                             \
   3690         }                                                       \
   3691         if (trunk_pipe_first_member_array) {                    \
   3692             for (j = 0; j < port_count; j++) {                  \
   3693                 if (trunk_pipe_first_member_array[j]) {         \
   3694                     sal_free(trunk_pipe_first_member_array[j]); \
   3695                 }                                               \
   3696             }                                                   \
   3697             sal_free(trunk_pipe_first_member_array);            \
   3698         }                                                       \
   3699         return _r_;
   3700 #else
   3701 #define BCM_MULTICAST_MEM_FREE_RETURN(_r_)              \
   3702     if (local_trunk_port_array) {                       \
   3703         for (j = 0; j < port_count; j++) {              \
   3704             if (local_trunk_port_array[j]) {            \
   3705                 sal_free(local_trunk_port_array[j]);    \
   3706             }                                           \
   3707         }                                               \
   3708         sal_free(local_trunk_port_array);               \
   3709     }                                                   \
   3710     if (local_port_array) {                             \
   3711         sal_free(local_port_array);                     \
   3712     }                                                   \
   3713     if (trunk_local_ports) {                            \
   3714         sal_free(trunk_local_ports);                    \
   3715     }                                                   \
   3716     if (temp_encap_list) {                              \
   3717         sal_free(temp_encap_list);                      \
   3718         temp_encap_list = NULL;                         \
   3719     }                                                   \
   3720     return _r_;
   3721 #endif
   3722 
   3723 
   3724 
   3725 #if defined(BCM_XGS3_SWITCH_SUPPORT) && defined(INCLUDE_L3)
   3726 /*
   3727  * Function:
   3728  *      _bcm_esw_multicast_egress_set
   3729  * Purpose:
   3730  *      Helper function to assign the complete set of egress GPORTs in the
   3731  *      replication list for the specified multicast index.
   3732  * Parameters:
   3733  *      unit       - (IN) Device Number
   3734  *      group      - (IN) Multicast group ID
   3735  *      port_count   - (IN) Number of ports in replication list
   3736  *      port_array   - (IN) List of GPORT Identifiers
   3737  *      encap_id_array - (IN) List of encap identifiers
   3738  * Returns:
   3739  *      BCM_E_XXX
   3740  */
   3741 STATIC int
   3742 _bcm_esw_multicast_egress_set(int unit, bcm_multicast_t group, int port_count,
   3743                             bcm_gport_t *port_array, bcm_if_t *encap_id_array)
   3744 {
   3745     int mc_index, i, j, rv = BCM_E_NONE;
   3746     int gport_id, *temp_encap_list = NULL;
   3747     bcm_port_t *local_port_array = NULL, **local_trunk_port_array = NULL;
   3748 #if defined(BCM_ESW_SUPPORT) && (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS)
   3749     int max_num_ports = SOC_MAX_NUM_PP_PORTS;
   3750 #else
   3751     int max_num_ports = SOC_MAX_NUM_PORTS;
   3752 #endif
   3753     bcm_module_t mod_out;
   3754     bcm_port_t port_out;
   3755     bcm_pbmp_t l2_pbmp, l3_pbmp;
   3756     l2mc_entry_t l2mc_entry; 
   3757     bcm_trunk_t trunk_id;
   3758     soc_mem_t   mem;
   3759     int idx, idx_max;
   3760     int modid_local = 0;
   3761     int   *trunk_local_ports = NULL;
   3762 #if defined (INCLUDE_L3)
   3763     int list_count, is_l3 = 0;
   3764     bcm_pbmp_t mc_eligible_pbmp, e_pbmp;
   3765     bcm_port_t port_iter;
   3766     int trunk_local_found;
   3767 #endif /* INCLUDE_L3 */
   3768 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
   3769     int is_local_subport = FALSE;
   3770 #endif
   3771 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_TOMAHAWK_SUPPORT)
   3772     int **trunk_pipe_first_member_array = NULL;
   3773     int pos, pipe;
   3774 #endif /* BCM_TRIDENT2PLUS_SUPPORT || BCM_TOMAHAWK_SUPPORT */
   3775 
   3776     /* Input parameters check. */
   3777     mc_index = _BCM_MULTICAST_ID_GET(group);
   3778     mem = (_BCM_MULTICAST_L2_OR_FABRIC(unit, group)) ? L2MCm : L3_IPMCm; 
   3779     /* Table index sanity check. */
   3780 #ifdef BCM_XGS3_FABRIC_SUPPORT
   3781     if (SOC_IS_XGS3_FABRIC(unit)) {
   3782         BCM_IF_ERROR_RETURN
   3783             (_bcm_esw_fabric_multicast_param_check(unit, group, &mc_index));
   3784     } else
   3785 #endif /* BCM_XGS3_FABRIC_SUPPORT */
   3786     if ((mc_index < 0) || (mc_index >= soc_mem_index_count(unit, mem))) {
   3787         return (BCM_E_PARAM);
   3788     }
   3789 
   3790     if (port_count > 0) {
   3791         if (NULL == port_array) {
   3792             return (BCM_E_PARAM);
   3793         }
   3794         if (!_BCM_MULTICAST_L2_OR_FABRIC(unit, group) && 
   3795             (NULL == encap_id_array)) {
   3796             return (BCM_E_PARAM);
   3797         }
   3798     } else if (port_count < 0) {
   3799         return (BCM_E_PARAM);
   3800     }   
   3801 
   3802 #ifdef BCM_XGS3_FABRIC_SUPPORT
   3803     if (SOC_IS_XGS3_FABRIC(unit)) {
   3804         /* The group was already validated above */
   3805     } else
   3806 #endif /* BCM_XGS3_FABRIC_SUPPORT */
   3807     if (!SOC_IS_TRX(unit)) {
   3808         if ((0 == _BCM_MULTICAST_IS_L2(group)) && 
   3809             (0 == _BCM_MULTICAST_IS_L3(group))) {
   3810             return (BCM_E_PARAM);
   3811         }
   3812     } else {
   3813 #if defined (INCLUDE_L3)
   3814          rv = _bcm_esw_multicast_l3_group_check(unit, group, NULL);
   3815 #endif /* INCLUDE_L3 */
   3816         if (BCM_FAILURE(rv) && (0 == _BCM_MULTICAST_IS_L2(group))) {
   3817             return BCM_E_PARAM;
   3818         }
   3819     }
   3820 
   3821     /* Convert GPORT array into local port numbers */
   3822     if (port_count > 0) {
   3823         local_port_array =
   3824             sal_alloc(sizeof(bcm_port_t) * port_count, "local_port array");
   3825         if (NULL == local_port_array) {
   3826             BCM_MULTICAST_MEM_FREE_RETURN(BCM_E_MEMORY);
   3827         }
   3828         
   3829         temp_encap_list =
   3830             sal_alloc(sizeof(int) * port_count, "temp_encap_list");
   3831         if (NULL == temp_encap_list) {
   3832             BCM_MULTICAST_MEM_FREE_RETURN(rv);
   3833         }
   3834 
   3835         trunk_local_ports =
   3836             sal_alloc(sizeof(int) * port_count, "trunk_local_ports");
   3837         if (NULL == trunk_local_ports) {
   3838             BCM_MULTICAST_MEM_FREE_RETURN(BCM_E_MEMORY);
   3839         }
   3840 
   3841         local_trunk_port_array =
   3842             sal_alloc(sizeof(bcm_port_t *) * port_count,
   3843                       "local_trunk_port_array pointers");
   3844         if (NULL == local_trunk_port_array) {
   3845             BCM_MULTICAST_MEM_FREE_RETURN(BCM_E_MEMORY);
   3846         }
   3847 
   3848         for (i = 0; i < port_count; i++) {
   3849             local_trunk_port_array[i] =
   3850                 sal_alloc(sizeof(bcm_port_t) * max_num_ports,
   3851                           "local_trunk_port_array");
   3852             if (NULL == local_trunk_port_array[i]) {
   3853                 BCM_MULTICAST_MEM_FREE_RETURN(BCM_E_MEMORY);
   3854             }
   3855         }
   3856 
   3857         for (i = 0; i < port_count; i++) {
   3858             trunk_local_ports[i] = 0;
   3859             for (idx = 0; idx < max_num_ports; idx++) {
   3860                 local_trunk_port_array[i][idx] = 0;
   3861             }
   3862         }
   3863 
   3864 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_TOMAHAWK_SUPPORT)
   3865         if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) {
   3866             trunk_pipe_first_member_array =
   3867                 sal_alloc(sizeof(int *) * port_count,
   3868                           "trunk_pipe_first_member_array pointers");
   3869             if (NULL == trunk_pipe_first_member_array) {
   3870                 BCM_MULTICAST_MEM_FREE_RETURN(BCM_E_MEMORY);
   3871             }
   3872 
   3873             for (i = 0; i < port_count; i++) {
   3874                 trunk_pipe_first_member_array[i] =
   3875                     sal_alloc(sizeof(int) * BCM_PIPES_MAX,
   3876                               "trunk_pipe_first_member_array");
   3877                 if (NULL == trunk_pipe_first_member_array[i]) {
   3878                     BCM_MULTICAST_MEM_FREE_RETURN(BCM_E_MEMORY);
   3879                 }
   3880             }
   3881 
   3882             for (i = 0; i < port_count; i++) {
   3883                 for (idx = 0; idx < BCM_PIPES_MAX; idx++) {
   3884                     trunk_pipe_first_member_array[i][idx] = -1;
   3885                 }
   3886             }
   3887         }
   3888 #endif /* BCM_TRIDENT2PLUS_SUPPORT || BCM_TOMAHAWK_SUPPORT */
   3889 
   3890     }
   3891 
   3892 
   3893     for (i = 0; i < port_count ; i++) {
   3894         rv = _bcm_esw_gport_resolve(unit, port_array[i],
   3895                                     &mod_out, &port_out,
   3896                                     &trunk_id, &gport_id); 
   3897         if (BCM_FAILURE(rv)) {
   3898             BCM_MULTICAST_MEM_FREE_RETURN(rv);
   3899         }
   3900 
   3901 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
   3902         rv = _bcm_esw_port_is_local_subport(
   3903                  unit, port_array[i], mod_out, port_out,
   3904                  &is_local_subport, &local_port_array[i]);
   3905         if (BCM_FAILURE(rv)) {
   3906             BCM_MULTICAST_MEM_FREE_RETURN(rv);
   3907         }
   3908 
   3909         if (is_local_subport) {
   3910             /* Local subport assigned above */
   3911         } else
   3912 #endif
   3913 
   3914         if (BCM_TRUNK_INVALID != trunk_id) {
   3915             rv = _bcm_esw_trunk_local_members_get(unit, trunk_id,
   3916                     max_num_ports, local_trunk_port_array[i],
   3917                     &trunk_local_ports[i]);
   3918             if (BCM_FAILURE(rv)) {
   3919                 BCM_MULTICAST_MEM_FREE_RETURN(rv);
   3920             }
   3921             /* Record the trunk ID to use later */
   3922             BCM_GPORT_TRUNK_SET(local_port_array[i], trunk_id);
   3923         } else {
   3924             rv = _bcm_esw_modid_is_local(unit, mod_out, &modid_local);
   3925             if (BCM_FAILURE(rv)) {
   3926                 BCM_MULTICAST_MEM_FREE_RETURN(rv);
   3927             }
   3928 
   3929             /* Convert system local_port to physical local_port */ 
   3930             if (soc_feature(unit, soc_feature_sysport_remap)) { 
   3931                 BCM_XLATE_SYSPORT_S2P(unit, &port_out); 
   3932             }
   3933 
   3934             if (TRUE != modid_local) {
   3935                 BCM_MULTICAST_MEM_FREE_RETURN(BCM_E_PARAM);
   3936             }
   3937             local_port_array[i] = port_out;
   3938         }
   3939     }
   3940 
   3941     BCM_PBMP_CLEAR(l2_pbmp);
   3942     BCM_PBMP_CLEAR(l3_pbmp);
   3943     if (_BCM_MULTICAST_L2_OR_FABRIC(unit, group)) {
   3944         for (i = 0; i < port_count; i++) {
   3945             if (BCM_GPORT_IS_TRUNK(local_port_array[i])) {
   3946                 for (idx = 0; idx < trunk_local_ports[i]; idx++) {
   3947                     BCM_PBMP_PORT_ADD(l2_pbmp,
   3948                                       local_trunk_port_array[i][idx]);
   3949                 }
   3950             } else {
   3951                 BCM_PBMP_PORT_ADD(l2_pbmp, local_port_array[i]);
   3952             }
   3953         }
   3954 
   3955         /* Update the L2MC port bitmap */
   3956         soc_mem_lock(unit, L2MCm);
   3957         rv = soc_mem_read(unit, L2MCm, MEM_BLOCK_ANY, mc_index, &l2mc_entry);
   3958         if (BCM_FAILURE(rv)) {
   3959             soc_mem_unlock(unit, L2MCm);
   3960             BCM_MULTICAST_MEM_FREE_RETURN(rv);
   3961         }
   3962         soc_mem_pbmp_field_set(unit, L2MCm, &l2mc_entry, PORT_BITMAPf,
   3963                                &l2_pbmp);
   3964         rv = soc_mem_write(unit, L2MCm, MEM_BLOCK_ALL,
   3965                            mc_index, &l2mc_entry);
   3966         soc_mem_unlock(unit, L2MCm);
   3967 #if defined(INCLUDE_L3)
   3968     } else {
   3969         if (_BCM_MULTICAST_IS_L3(group)) {
   3970             is_l3 = 1;
   3971         }
   3972         if (0 == port_count) {
   3973             /* Clearing the replication set */
   3974             list_count = 0;
   3975             BCM_PBMP_CLEAR(e_pbmp);
   3976             BCM_PBMP_ASSIGN(e_pbmp, PBMP_E_ALL(unit));
   3977 #if defined(BCM_TRIDENT2_SUPPORT)
   3978             if (SOC_IS_TRIDENT2X(unit)) {
   3979                 BCM_PBMP_PORT_ADD(e_pbmp,CMIC_PORT(unit));
   3980             }
   3981 #endif	    
   3982 #if defined(BCM_KATANA2_SUPPORT)
   3983             if (soc_feature(unit, soc_feature_subtag_coe) ||
   3984                 soc_feature(unit, soc_feature_linkphy_coe)) {
   3985                _bcm_kt2_subport_pbmp_update(unit, &e_pbmp);
   3986            }
   3987 #endif
   3988 
   3989 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_TRIDENT2PLUS_SUPPORT)
   3990             if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) {
   3991                 BCM_IF_ERROR_RETURN(
   3992                     _bcm_esw_ipmc_egress_intf_destroy_in_trunk_repl_mode(
   3993                          unit, mc_index, e_pbmp, is_l3));
   3994             } else
   3995 #endif /* BCM_TOMAHAWK_SUPPORT || BCM_TRIDENT2PLUS_SUPPORT */
   3996             {
   3997                 BCM_PBMP_ITER(e_pbmp, port_iter) {
   3998                     rv = _bcm_esw_ipmc_egress_intf_set(unit, mc_index, port_iter,
   3999                                             list_count, NULL, is_l3, FALSE);
   4000                     if (BCM_FAILURE(rv)) {
   4001                         BCM_MULTICAST_MEM_FREE_RETURN(rv);
   4002                     }
   4003                 }
   4004             }
   4005         } else {
   4006             /* 
   4007              * For each port, walk through the list of GPORTs
   4008              * and collect the ones that match the port.
   4009              */
   4010 
   4011 #ifdef BCM_TOMAHAWK3_SUPPORT
   4012             if (SOC_IS_TOMAHAWK3(unit)) {
   4013                 /* MAx number of replications across all ports cannot exceed
   4014                  * TH3_IPMC_MAX_INTF_COUNT*/
   4015                 if (port_count > TH3_IPMC_MAX_INTF_COUNT) {
   4016                     rv = BCM_E_PARAM;
   4017                     BCM_MULTICAST_MEM_FREE_RETURN(rv);
   4018                 }
   4019             }
   4020 #endif
   4021             /* Valid SOC ports plus the CMIC port */
   4022             BCM_PBMP_ASSIGN(mc_eligible_pbmp, PBMP_PORT_ALL(unit));
   4023             BCM_PBMP_PORT_ADD(mc_eligible_pbmp, CMIC_PORT(unit));
   4024 #if defined(BCM_KATANA2_SUPPORT)
   4025             if (soc_feature(unit, soc_feature_subtag_coe) ||
   4026                 soc_feature(unit, soc_feature_linkphy_coe)) {
   4027                _bcm_kt2_subport_pbmp_update(unit, &mc_eligible_pbmp);
   4028            }
   4029 #endif
   4030             BCM_PBMP_ITER(mc_eligible_pbmp, port_iter) {
   4031                 list_count = 0;
   4032 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_TOMAHAWK_SUPPORT)
   4033                 trunk_id = BCM_TRUNK_INVALID;
   4034                 pos = -1;
   4035 #endif /* BCM_TRIDENT2PLUS_SUPPORT || BCM_TOMAHAWK_SUPPORT */
   4036                 for (i = 0; i < port_count ; i++) {
   4037                     if (BCM_GPORT_IS_TRUNK(local_port_array[i])) {
   4038                         trunk_local_found = 0;
   4039                         idx_max = trunk_local_ports[i];
   4040                         for (idx = 0; idx < idx_max; idx++) {                        
   4041                             if (local_trunk_port_array[i][idx] == port_iter) {
   4042                                 trunk_local_found = 1;
   4043 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_TOMAHAWK_SUPPORT)
   4044                                 if (trunk_id == BCM_TRUNK_INVALID) {
   4045                                     pos = i;
   4046                                     trunk_id = BCM_GPORT_TRUNK_GET(local_port_array[i]);
   4047                                 }
   4048 #endif /* BCM_TRIDENT2PLUS_SUPPORT || BCM_TOMAHAWK_SUPPORT */
   4049                                 break;
   4050                             }
   4051                         }
   4052                         if (!trunk_local_found) {
   4053                             continue;
   4054                         }   
   4055                     } else {
   4056                         if (local_port_array[i] != port_iter) {
   4057                             continue;
   4058                         }
   4059                     }
   4060                     if (encap_id_array[i] == BCM_IF_INVALID) {
   4061                         /* Add port to L2 pbmp */
   4062                         BCM_PBMP_PORT_ADD(l2_pbmp, port_iter);
   4063                     } else {
   4064                         if (soc_feature(unit, 
   4065                                 soc_feature_l3mc_use_egress_next_hop)) {
   4066                             /* _bcm_esw_ipmc_egress_intf_set() processing the 
   4067                              * real HW index to indicate egress NH object.
   4068                              */
   4069                             temp_encap_list[list_count] = encap_id_array[i] - 
   4070                                      BCM_XGS3_EGRESS_IDX_MIN(unit);
   4071                         } else {
   4072                             temp_encap_list[list_count] = encap_id_array[i];
   4073                         }
   4074                         list_count++;
   4075                     }
   4076                 }
   4077                 if ((0 == list_count) && (CMIC_PORT(unit) == port_iter)) {
   4078                     if (!SOC_IS_TRIDENT2(unit)) {
   4079                         /* Don't install L3 ports on CMIC */
   4080                         continue;
   4081                     }
   4082                 }
   4083 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_TRIDENT2PLUS_SUPPORT)
   4084                 if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) {
   4085                     if (trunk_id != BCM_TRUNK_INVALID) {
   4086                         bcm_port_t first_member;
   4087                         pipe = SOC_INFO(unit).port_pipe[port_iter];
   4088                         first_member = trunk_pipe_first_member_array[pos][pipe];
   4089                         if (first_member == -1) {
   4090                             rv = _bcm_esw_ipmc_egress_intf_set_for_trunk_first_member(
   4091                                      unit, mc_index, port_iter, list_count,
   4092                                      temp_encap_list, is_l3, TRUE, trunk_id);
   4093                             trunk_pipe_first_member_array[pos][pipe] = port_iter;
   4094 #if defined(BCM_TOMAHAWK3_SUPPORT)
   4095                             if(SOC_IS_TOMAHAWK3(unit)) {
   4096                                 int th3_idx;
   4097                                 for(th3_idx = 0; th3_idx < BCM_PIPES_MAX; th3_idx++) {
   4098                                     trunk_pipe_first_member_array[pos][th3_idx] = port_iter;
   4099                                 }
   4100                             }
   4101 #endif
   4102                         } else {
   4103                             rv = _bcm_esw_ipmc_egress_intf_set_for_same_pipe_member(
   4104                                      unit, mc_index, port_iter, first_member,
   4105                                      trunk_id);
   4106                         }
   4107                     } else {
   4108                         rv = _bcm_esw_ipmc_egress_intf_set_for_trunk_first_member(
   4109                              unit, mc_index, port_iter, list_count,
   4110                              temp_encap_list, is_l3, TRUE, BCM_TRUNK_INVALID);
   4111                     }
   4112                 } else
   4113 #endif /* BCM_TOMAHAWK_SUPPORT || BCM_TRIDENT2PLUS_SUPPORT */
   4114                 {
   4115                     rv = _bcm_esw_ipmc_egress_intf_set(
   4116                              unit, mc_index, port_iter, list_count,
   4117                              temp_encap_list, is_l3, TRUE);
   4118                 }
   4119                 if (BCM_FAILURE(rv)) {
   4120                     BCM_MULTICAST_MEM_FREE_RETURN(rv);
   4121                 }
   4122                 if (list_count) {
   4123                     BCM_PBMP_PORT_ADD(l3_pbmp, port_iter);
   4124                 }
   4125             }
   4126         }
   4127         rv = _bcm_esw_multicast_ipmc_write(unit, mc_index, l2_pbmp,
   4128                                            l3_pbmp, TRUE);
   4129 #endif  /* INCLUDE_L3 */
   4130     }
   4131 
   4132     BCM_MULTICAST_MEM_FREE_RETURN(rv);
   4133 }
   4134 #endif
   4135 
   4136 
   4137 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   4138 
   4139 #ifdef	BCM_XGS3_FABRIC_SUPPORT
   4140 int
   4141 _bcm_fabric_multicast_ipmc_group_type_set(int unit, bcm_multicast_t group)
   4142 {
   4143     uint8 group_type = _BCM_MULTICAST_TYPE_GET(group);
   4144     uint32 ipmc_id = _BCM_MULTICAST_ID_GET(group);
   4145 
   4146     /* Don't check if MULTICAST_GROUP_IS_SET because we also want to
   4147      * be able to clear a group. */
   4148 
   4149 
   4150     /* It's an IPMC type group */
   4151     _fabric_multicast_ipmc_group_types[unit][ipmc_id] = group_type;
   4152 
   4153 #ifdef BCM_WARM_BOOT_SUPPORT
   4154     SOC_CONTROL_LOCK(unit);
   4155     SOC_CONTROL(unit)->scache_dirty = 1;
   4156     SOC_CONTROL_UNLOCK(unit);
   4157 #endif
   4158     return BCM_E_NONE;
   4159 }
   4160 
   4161 int
   4162 _bcm_fabric_multicast_ipmc_group_type_get(int unit, uint32 ipmc_id,
   4163                                       bcm_multicast_t *group)
   4164 {
   4165     if ((NULL != _fabric_multicast_ipmc_group_types[unit]) && /* Verify init */
   4166         (0 != _fabric_multicast_ipmc_group_types[unit][ipmc_id])) {
   4167         _BCM_MULTICAST_GROUP_SET(*group,
   4168                                  _fabric_multicast_ipmc_group_types[unit][ipmc_id],
   4169                                  ipmc_id);
   4170         return BCM_E_NONE;
   4171     } else {
   4172         *group = 0;
   4173         return BCM_E_NOT_FOUND;
   4174     }
   4175     return BCM_E_NONE;
   4176 }
   4177 #ifdef BCM_WARM_BOOT_SUPPORT
   4178 STATIC int
   4179 _bcm_fabric_multicast_reinit(int unit)
   4180 {
   4181     int ipmc_base, ipmc_size = 0, alloc_size, ipmc_id;
   4182     int index_min, index_max, search_index;
   4183     soc_scache_handle_t scache_handle;
   4184     uint8 *multicast_scache;
   4185     int rv = BCM_E_NONE;
   4186 
   4187     SOC_IF_ERROR_RETURN
   4188         (soc_hbx_ipmc_size_get(unit, &ipmc_base, &ipmc_size));
   4189 
   4190     alloc_size = ipmc_size * sizeof(uint8);
   4191     SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_MULTICAST, 0);
   4192     rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE,
   4193             0, &multicast_scache,
   4194             BCM_FABRIC_IPMC_WB_DEFAULT_VERSION, NULL);
   4195 
   4196     if (BCM_E_NOT_FOUND == rv) {
   4197         multicast_scache = NULL;
   4198         /* Version which doesnt support fabric IPMC group types.
   4199          * Update type as L3.
   4200          */
   4201         index_min = BCM_FABRIC_IPMC_BASE(unit);
   4202         index_max = BCM_FABRIC_IPMC_MAX(unit);
   4203 
   4204         for (search_index = index_min; search_index <= index_max;
   4205                 search_index++) {
   4206             ipmc_id = search_index - index_min;
   4207             /* If that mc index exists */
   4208             if (SHR_BITGET(BCM_FABRIC_MC_USED_BITMAP(unit),
   4209                         search_index)) {
   4210                 _fabric_multicast_ipmc_group_types[unit][ipmc_id] =
   4211                                                 _BCM_MULTICAST_TYPE_L3;
   4212             }
   4213         }
   4214     } else if (BCM_FAILURE(rv)) {
   4215         return rv;
   4216     } else {
   4217         sal_memcpy(_fabric_multicast_ipmc_group_types[unit], multicast_scache,
   4218                 alloc_size);
   4219     }
   4220     return BCM_E_NONE;
   4221 }
   4222 #endif
   4223 /*
   4224  * Function:
   4225  *      _bcm_esw_fabric_multicast_init
   4226  * Purpose:
   4227  *      Initialize the multicast module on XGS3 fabric devices.
   4228  * Parameters:
   4229  *      unit - (IN) Unit number.
   4230  * Returns:
   4231  *      BCM_E_xxx
   4232  * Notes:
   4233  */
   4234 STATIC int 
   4235 _bcm_esw_fabric_multicast_init(int unit)
   4236 {
   4237     int	mc_base, mc_size;
   4238     int	ipmc_base, ipmc_size, alloc_size;
   4239     int l2mc_table_size = soc_mem_index_count(unit, L2MCm);
   4240 #ifdef BCM_WARM_BOOT_SUPPORT
   4241     int rv = BCM_E_NONE;
   4242     soc_scache_handle_t scache_handle;
   4243     uint8               *multicast_scache;
   4244 #endif /* BCM_WARM_BOOT_SUPPORT */
   4245 
   4246     SOC_IF_ERROR_RETURN
   4247         (soc_hbx_mcast_size_get(unit, &mc_base, &mc_size));
   4248     SOC_IF_ERROR_RETURN
   4249         (soc_hbx_ipmc_size_get(unit, &ipmc_base, &ipmc_size));
   4250 
   4251     _bcm_fabric_mc_info[unit].mcast_size = mc_size;
   4252     _bcm_fabric_mc_info[unit].ipmc_size = ipmc_size;
   4253 
   4254     if (NULL != _bcm_fabric_mc_info[unit].mcast_used) {
   4255         sal_free(_bcm_fabric_mc_info[unit].mcast_used);
   4256         _bcm_fabric_mc_info[unit].mcast_used = NULL;
   4257     }
   4258     alloc_size = SHR_BITALLOCSIZE(l2mc_table_size);
   4259     _bcm_fabric_mc_info[unit].mcast_used = 
   4260         sal_alloc(alloc_size, "Fabric MC entries used");
   4261     if (NULL == _bcm_fabric_mc_info[unit].mcast_used) {
   4262         return BCM_E_MEMORY;
   4263     }
   4264     sal_memset(_bcm_fabric_mc_info[unit].mcast_used, 0, alloc_size);
   4265 
   4266     alloc_size = ipmc_size * sizeof(uint8);
   4267 #ifdef BCM_WARM_BOOT_SUPPORT
   4268     if (!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) {
   4269         SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_MULTICAST, 0);
   4270         rv = _bcm_esw_scache_ptr_get(unit, scache_handle,
   4271                                      (0 == SOC_WARM_BOOT(unit)),
   4272                                      alloc_size,
   4273                                      &multicast_scache,
   4274                                      BCM_FABRIC_IPMC_WB_DEFAULT_VERSION, NULL);
   4275         if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) {
   4276             return rv;
   4277         }
   4278     } /* Else, not enough memory, don't allocate scache */
   4279 #endif /* BCM_WARM_BOOT_SUPPORT */
   4280 
   4281 
   4282     if (NULL == _fabric_multicast_ipmc_group_types[unit]) {
   4283         _fabric_multicast_ipmc_group_types[unit] =
   4284             sal_alloc(alloc_size, "fabric_multicast_group_types");
   4285         if (NULL == _fabric_multicast_ipmc_group_types[unit]) {
   4286             return BCM_E_MEMORY;
   4287         }
   4288     }
   4289     sal_memset(_fabric_multicast_ipmc_group_types[unit], 0, alloc_size);
   4290     
   4291 #ifdef BCM_WARM_BOOT_SUPPORT
   4292     multicast_mode_set[unit] = TRUE;
   4293 
   4294     /* Recover the used multicast entries */
   4295     if (SOC_WARM_BOOT(unit)) {
   4296         l2mc_entry_t *l2mc_entry, *l2mc_table;
   4297         int index, index_min, index_max, l2mc_tbl_sz;
   4298 
   4299         /*
   4300          * Go through L2MC table to find valid entries
   4301          */
   4302         index_min = soc_mem_index_min(unit, L2MCm);
   4303         index_max = soc_mem_index_max(unit, L2MCm);
   4304 
   4305         l2mc_tbl_sz = sizeof(l2mc_entry_t) * l2mc_table_size;
   4306         l2mc_table = soc_cm_salloc(unit, l2mc_tbl_sz, "l2mc tbl dma");
   4307         if (l2mc_table == NULL) {
   4308             sal_free(BCM_FABRIC_MC_USED_BITMAP(unit));
   4309             return BCM_E_MEMORY;
   4310         }
   4311 
   4312         memset((void *)l2mc_table, 0, l2mc_tbl_sz);
   4313         if (soc_mem_read_range(unit, L2MCm, MEM_BLOCK_ANY,
   4314                                index_min, index_max, l2mc_table) < 0) {
   4315             sal_free(BCM_FABRIC_MC_USED_BITMAP(unit));
   4316             soc_cm_sfree(unit, l2mc_table);
   4317             return SOC_E_INTERNAL;
   4318         }
   4319 
   4320         for (index = index_min; index <= index_max; index++) {
   4321 
   4322             l2mc_entry = soc_mem_table_idx_to_pointer(unit, L2MCm,
   4323                                                       l2mc_entry_t *,
   4324                                                       l2mc_table, index);
   4325 
   4326             if (!soc_mem_field32_get(unit, L2MCm, l2mc_entry, VALIDf)) {
   4327                 continue;
   4328             }
   4329 
   4330             SHR_BITSET(BCM_FABRIC_MC_USED_BITMAP(unit), index);
   4331         }
   4332 
   4333         soc_cm_sfree(unit, l2mc_table);
   4334     }
   4335     if (SOC_WARM_BOOT(unit)) {
   4336         return (_bcm_fabric_multicast_reinit(unit));
   4337     }
   4338 #endif /* BCM_WARM_BOOT_SUPPORT */
   4339 
   4340     SOC_IF_ERROR_RETURN(soc_mem_clear(unit, L2MCm, MEM_BLOCK_ALL, FALSE));
   4341 
   4342     if (SOC_IS_TITAN2X(unit)) {
   4343         BCM_IF_ERROR_RETURN(bcm_xgs3_l2_addr_mcast_delete_all(unit));
   4344     }
   4345 
   4346     return BCM_E_NONE;
   4347 }
   4348 
   4349 /*
   4350  * Function:
   4351  *      _bcm_esw_fabric_multicast_detach
   4352  * Purpose:
   4353  *      Detach the multicast module on XGS3 fabric devices.
   4354  * Parameters:
   4355  *      unit - (IN) Unit number.
   4356  * Returns:
   4357  *      BCM_E_xxx
   4358  * Notes:
   4359  */
   4360 STATIC int
   4361 _bcm_esw_fabric_multicast_detach(int unit)
   4362 {
   4363 #ifdef BCM_WARM_BOOT_SUPPORT
   4364     int autosync;
   4365     BCM_IF_ERROR_RETURN(
   4366             bcm_esw_switch_control_get(unit, bcmSwitchControlAutoSync, &autosync));
   4367     if (autosync) {
   4368         BCM_IF_ERROR_RETURN(_bcm_fabric_multicast_sync(unit));
   4369     }
   4370 #endif /* BCM_WARM_BOOT_SUPPORT */
   4371     _bcm_fabric_mc_info[unit].mcast_size = 0;
   4372     _bcm_fabric_mc_info[unit].ipmc_size = 0;
   4373 
   4374     if (NULL != _bcm_fabric_mc_info[unit].mcast_used) {
   4375         sal_free(_bcm_fabric_mc_info[unit].mcast_used);
   4376         _bcm_fabric_mc_info[unit].mcast_used = NULL;
   4377     }
   4378 
   4379     if (NULL != _fabric_multicast_ipmc_group_types[unit]) {
   4380         sal_free(_fabric_multicast_ipmc_group_types[unit]);
   4381         _fabric_multicast_ipmc_group_types[unit] = NULL;
   4382     }
   4383 
   4384     return BCM_E_NONE;
   4385 }
   4386 
   4387 /*
   4388  * Function:
   4389  *      _bcm_esw_fabric_multicast_create
   4390  * Purpose:
   4391  *      Create a multicast group on XGS3 fabric devices.
   4392  * Parameters:
   4393  *      unit - (IN) Unit number.
   4394  * Returns:
   4395  *      BCM_E_xxx
   4396  * Notes:
   4397  */
   4398 STATIC int 
   4399 _bcm_esw_fabric_multicast_create(int unit, uint32 flags, bcm_multicast_t *group)
   4400 {
   4401     uint32 type;
   4402     int search_index, fabric_index = -1;
   4403     int index_min, index_max, rv;
   4404     l2mc_entry_t	l2mc;
   4405 
   4406     /* On switch devices, we verify that the particular multicast group
   4407      * type is valid and supported on the device.
   4408      * We Must Not Do This on Fabrics!
   4409      * Fabric devices must be able to pass all group types.  We translate
   4410      * the type here to what is appropriate on the specific device HW.
   4411      */
   4412     type = flags & BCM_MULTICAST_TYPE_MASK;
   4413     if (1 != _shr_popcount(type)) {
   4414         return BCM_E_PARAM;
   4415     }
   4416 
   4417     if (type == BCM_MULTICAST_TYPE_L2) {
   4418         index_min = BCM_FABRIC_MCAST_BASE(unit);
   4419         index_max =  BCM_FABRIC_MCAST_MAX(unit);
   4420         if (flags & BCM_MULTICAST_WITH_ID) {
   4421             if (!_BCM_MULTICAST_IS_L2(*group)) {
   4422                 /* Group ID doesn't match creation flag type */
   4423                 return BCM_E_PARAM;
   4424             }
   4425         }
   4426     } else {
   4427         index_min = BCM_FABRIC_IPMC_BASE(unit);
   4428         index_max = BCM_FABRIC_IPMC_MAX(unit);
   4429         if (flags & BCM_MULTICAST_WITH_ID) {
   4430             if (_BCM_MULTICAST_IS_L2(*group)) {
   4431                 /* Group ID doesn't match creation flag type */
   4432                 return BCM_E_PARAM;
   4433             }
   4434         }
   4435     }
   4436 
   4437     if (flags & BCM_MULTICAST_WITH_ID) {
   4438         fabric_index = _BCM_MULTICAST_ID_GET(*group) + index_min;
   4439         if ((fabric_index < index_min) || (fabric_index > index_max)) {
   4440             /* Group index out of bounds */
   4441             return BCM_E_PARAM;
   4442         }
   4443         if (SHR_BITGET(BCM_FABRIC_MC_USED_BITMAP(unit),
   4444                        fabric_index)) {
   4445             /* Requested group has already been created */
   4446             return BCM_E_EXISTS;
   4447         }
   4448     } else {
   4449         for (search_index = index_min; search_index <= index_max;
   4450              search_index++) {
   4451             if (!SHR_BITGET(BCM_FABRIC_MC_USED_BITMAP(unit),
   4452                             search_index)) {
   4453                 fabric_index = search_index;
   4454                 break;
   4455             }
   4456         }
   4457         if (-1 == fabric_index) {
   4458             /* Out of free groups */
   4459             return BCM_E_RESOURCE;
   4460         }
   4461     }
   4462 
   4463     /* Mark HW entry as valid */
   4464     sal_memset(&l2mc, 0, sizeof(l2mc));
   4465     soc_mem_field32_set(unit, L2MCm, &l2mc, VALIDf, 1);
   4466     soc_mem_lock(unit, L2MCm);
   4467     rv = WRITE_L2MCm(unit, MEM_BLOCK_ALL, fabric_index, &l2mc);
   4468     soc_mem_unlock(unit, L2MCm);
   4469     if (BCM_FAILURE(rv)) {
   4470         return rv;
   4471     }
   4472 
   4473     /* Record group allocation */
   4474     SHR_BITSET(BCM_FABRIC_MC_USED_BITMAP(unit), fabric_index);
   4475 
   4476     if (type == BCM_MULTICAST_TYPE_L2) {
   4477         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_L2,
   4478                                  fabric_index - index_min);
   4479     } else if (type == BCM_MULTICAST_TYPE_L3) {
   4480         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_L3,
   4481                                  fabric_index - index_min);
   4482     } else if (type == BCM_MULTICAST_TYPE_VPLS) {
   4483         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_VPLS,
   4484                                  fabric_index - index_min);
   4485     } else if (type == BCM_MULTICAST_TYPE_MIM) {
   4486         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_MIM,
   4487                                  fabric_index - index_min);
   4488     } else if (type == BCM_MULTICAST_TYPE_WLAN) {
   4489         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_WLAN,
   4490                                  fabric_index - index_min);
   4491     } else if (type == BCM_MULTICAST_TYPE_SUBPORT) {
   4492         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_SUBPORT,
   4493                                  fabric_index - index_min);
   4494     }else if (type == BCM_MULTICAST_TYPE_TRILL) {
   4495         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_TRILL,
   4496                                  fabric_index - index_min);
   4497     } else if (type == BCM_MULTICAST_TYPE_VLAN) {
   4498         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_VLAN,
   4499                                  fabric_index - index_min);
   4500     } else if (type == BCM_MULTICAST_TYPE_NIV) {
   4501         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_NIV,
   4502                                  fabric_index - index_min);
   4503     } else if (type == BCM_MULTICAST_TYPE_EGRESS_OBJECT) {
   4504         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_EGRESS_OBJECT,
   4505                                  fabric_index - index_min);
   4506     } else if (type == BCM_MULTICAST_TYPE_L2GRE) {
   4507         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_L2GRE,
   4508                                  fabric_index - index_min);
   4509     } else if (type == BCM_MULTICAST_TYPE_VXLAN) {
   4510         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_VXLAN,
   4511                                  fabric_index - index_min);
   4512     } else if (type == BCM_MULTICAST_TYPE_FLOW) {
   4513         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_FLOW,
   4514                                  fabric_index - index_min);
   4515     } else if (type == BCM_MULTICAST_TYPE_EXTENDER) {
   4516         _BCM_MULTICAST_GROUP_SET(*group, _BCM_MULTICAST_TYPE_EXTENDER,
   4517                                  fabric_index - index_min);
   4518     }
   4519 
   4520     /* Record IPMC types for reference */
   4521     BCM_IF_ERROR_RETURN(
   4522             _bcm_fabric_multicast_ipmc_group_type_set(unit, *group));
   4523     return BCM_E_NONE;
   4524 }
   4525 
   4526 /*
   4527  * Function:
   4528  *      _bcm_esw_fabric_multicast_destroy
   4529  * Purpose:
   4530  *      Destroy a multicast group on XGS3 fabric devices.
   4531  * Parameters:
   4532  *      unit - (IN) Unit number.
   4533  * Returns:
   4534  *      BCM_E_xxx
   4535  * Notes:
   4536  */
   4537 STATIC int 
   4538 _bcm_esw_fabric_multicast_destroy(int unit, bcm_multicast_t group)
   4539 {
   4540     int fabric_index = -1;
   4541     int index_min, index_max, rv;
   4542     l2mc_entry_t	l2mc;
   4543 
   4544     if (_BCM_MULTICAST_IS_L2(group)) {
   4545         index_min = BCM_FABRIC_MCAST_BASE(unit);
   4546         index_max =  BCM_FABRIC_MCAST_MAX(unit);
   4547     } else {
   4548         /* All non-L2 types are the same on fabric devices */
   4549         index_min = BCM_FABRIC_IPMC_BASE(unit);
   4550         index_max = BCM_FABRIC_IPMC_MAX(unit);
   4551     }
   4552     fabric_index = _BCM_MULTICAST_ID_GET(group) + index_min;
   4553 
   4554     if ((fabric_index < index_min) || (fabric_index > index_max)) {
   4555         /* Group index out of bounds */
   4556         return BCM_E_PARAM;
   4557     }
   4558     if (!SHR_BITGET(BCM_FABRIC_MC_USED_BITMAP(unit), fabric_index)) {
   4559         /* Requested group has not been created */
   4560         return BCM_E_NOT_FOUND;
   4561     }
   4562 
   4563     /* Mark HW entry as invalid */
   4564     sal_memset(&l2mc, 0, sizeof(l2mc));
   4565     soc_mem_lock(unit, L2MCm);
   4566     rv = WRITE_L2MCm(unit, MEM_BLOCK_ALL, fabric_index, &l2mc);
   4567     soc_mem_unlock(unit, L2MCm);
   4568     if (BCM_FAILURE(rv)) {
   4569         return rv;
   4570     }
   4571 
   4572     /* Clear group allocation */
   4573     SHR_BITCLR(BCM_FABRIC_MC_USED_BITMAP(unit), fabric_index);
   4574 
   4575     /* Free IPMC type record. fabric_index does not have type info */
   4576     BCM_IF_ERROR_RETURN(
   4577             _bcm_fabric_multicast_ipmc_group_type_set(unit, group));
   4578 
   4579     return BCM_E_NONE;
   4580 }
   4581 
   4582 /*
   4583  * Function:
   4584  *      _bcm_esw_fabric_multicast_group_get
   4585  * Purpose:
   4586  *      Retrieve the flags associated with a multicast group.
   4587  * Parameters:
   4588  *      unit - (IN) Unit number.
   4589  *      group - (IN) Multicast group ID
   4590  *      flags - (OUT) BCM_MULTICAST_*
   4591  * Returns:
   4592  *      BCM_E_xxx
   4593  * Notes:
   4594  */
   4595 STATIC int 
   4596 _bcm_esw_fabric_multicast_group_get(int unit, bcm_multicast_t group,
   4597                                     uint32 *flags)
   4598 {
   4599     int mc_index , rv = BCM_E_NONE;
   4600     uint32 type_flags;
   4601     bcm_multicast_t get_group;
   4602 
   4603     /* Check if this is a known group */
   4604     mc_index = _BCM_MULTICAST_ID_GET(group);
   4605     BCM_IF_ERROR_RETURN
   4606         (_bcm_esw_fabric_multicast_param_check(unit, group, &mc_index));
   4607 
   4608     /* Check for the type of the multicast group */
   4609     if (_BCM_MULTICAST_IS_L2(group)) {
   4610         type_flags = BCM_MULTICAST_TYPE_L2;
   4611     } else {
   4612         if (!_BCM_MULTICAST_IS_L3(group) &&
   4613                 !_BCM_MULTICAST_IS_VPLS(group) &&
   4614                 !_BCM_MULTICAST_IS_MIM(group) &&
   4615                 !_BCM_MULTICAST_IS_SUBPORT(group) &&
   4616                 !_BCM_MULTICAST_IS_WLAN(group) &&
   4617                 !_BCM_MULTICAST_IS_VLAN(group) &&
   4618                 !_BCM_MULTICAST_IS_TRILL(group) &&
   4619                 !_BCM_MULTICAST_IS_NIV(group) &&
   4620                 !_BCM_MULTICAST_IS_L2GRE(group) &&
   4621                 !_BCM_MULTICAST_IS_VXLAN(group) &&
   4622                 !_BCM_MULTICAST_IS_FLOW(group) &&
   4623                 !_BCM_MULTICAST_IS_EGRESS_OBJECT(group) &&
   4624                 !_BCM_MULTICAST_IS_EXTENDER(group)) {
   4625             return BCM_E_PARAM;
   4626         }
   4627         rv = _bcm_fabric_multicast_ipmc_group_type_get(unit, mc_index,
   4628                 &get_group);
   4629 
   4630         if (BCM_E_NOT_FOUND == rv) {
   4631             type_flags = 0;
   4632         } else if (BCM_FAILURE(rv)) {
   4633             return rv;
   4634         } else if (get_group != group) {
   4635             /* IPMC index is allocated, but not to the same group type */
   4636             type_flags = 0;
   4637             return BCM_E_NOT_FOUND;
   4638         } else {
   4639             type_flags =
   4640                 _bcm_esw_multicast_group_type_to_flags(
   4641                         _BCM_MULTICAST_TYPE_GET(group));
   4642         }
   4643     }
   4644 
   4645     *flags = (type_flags | BCM_MULTICAST_WITH_ID);
   4646 
   4647     return BCM_E_NONE;
   4648 }
   4649 
   4650 /*
   4651  * Function:
   4652  *      _bcm_esw_fabric_multicast_group_traverse
   4653  * Purpose:
   4654  *      Iterate over the defined multicast groups of the type
   4655  *      specified in 'flags'.  If all types are desired, use
   4656  *      MULTICAST_TYPE_MASK.
   4657  * Parameters:
   4658  *      unit - (IN) Unit number.
   4659  *      trav_fn - (IN) Callback function.
   4660  *      flags - (IN) BCM_MULTICAST_*
   4661  *      user_data - (IN) User data to be passed to callback function.
   4662  * Returns:
   4663  *      BCM_E_xxx
   4664  * Notes:
   4665  */
   4666 int 
   4667 _bcm_esw_fabric_multicast_group_traverse(int unit,
   4668                                  bcm_multicast_group_traverse_cb_t trav_fn, 
   4669                                          uint32 flags, void *user_data)
   4670 {
   4671     int search_index;
   4672     int index_min, index_max;
   4673     int rv = BCM_E_NONE;
   4674     uint32 group_flags, flags_mask;
   4675     bcm_multicast_t group;
   4676 
   4677     /* Create a flags_mask with all flags */
   4678     flags_mask = BCM_MULTICAST_TYPE_L2 | BCM_MULTICAST_TYPE_L3 |
   4679                  BCM_MULTICAST_TYPE_VPLS | BCM_MULTICAST_TYPE_SUBPORT |
   4680                  BCM_MULTICAST_TYPE_MIM | BCM_MULTICAST_TYPE_WLAN |
   4681                  BCM_MULTICAST_TYPE_VLAN | BCM_MULTICAST_TYPE_TRILL |
   4682                  BCM_MULTICAST_TYPE_NIV | BCM_MULTICAST_TYPE_EGRESS_OBJECT |
   4683                  BCM_MULTICAST_TYPE_EXTENDER | BCM_MULTICAST_TYPE_VXLAN;
   4684 
   4685 
   4686     if (0 == (flags & flags_mask)) {
   4687         /* No recognized multicast types to traverse */
   4688         return BCM_E_PARAM;
   4689     }
   4690 
   4691     flags &= flags_mask;
   4692 
   4693     /* L2 groups */
   4694     if (flags & BCM_MULTICAST_TYPE_L2) {
   4695         index_min = BCM_FABRIC_MCAST_BASE(unit);
   4696         index_max =  BCM_FABRIC_MCAST_MAX(unit);
   4697         group_flags = BCM_MULTICAST_TYPE_L2 | BCM_MULTICAST_WITH_ID;
   4698 
   4699         for (search_index = index_min; search_index <= index_max;
   4700                 search_index++) {
   4701             if (SHR_BITGET(BCM_FABRIC_MC_USED_BITMAP(unit), search_index)) {
   4702                 _BCM_MULTICAST_GROUP_SET(group, _BCM_MULTICAST_TYPE_L2,
   4703                         search_index);
   4704                 BCM_IF_ERROR_RETURN
   4705                     ((*trav_fn)(unit, group, group_flags, user_data));
   4706             }
   4707         }
   4708     }
   4709         
   4710     /* L3 groups */
   4711     if (flags & ~(BCM_MULTICAST_TYPE_L2)) {
   4712         index_min = BCM_FABRIC_IPMC_BASE(unit);
   4713         index_max = BCM_FABRIC_IPMC_MAX(unit);
   4714 
   4715         for (search_index = index_min; search_index <= index_max;
   4716                 search_index++) {
   4717             if (SHR_BITGET(BCM_FABRIC_MC_USED_BITMAP(unit), search_index)) {
   4718                 rv = _bcm_fabric_multicast_ipmc_group_type_get(unit,
   4719                                         search_index - index_min, &group);
   4720 
   4721                 if (BCM_E_NOT_FOUND == rv) {
   4722                     continue;
   4723                 } else if (BCM_FAILURE(rv)) {
   4724                     return rv;
   4725                 } else {
   4726                     group_flags =
   4727                         _bcm_esw_multicast_group_type_to_flags(
   4728                                 _BCM_MULTICAST_TYPE_GET(group)) |
   4729                                 BCM_MULTICAST_WITH_ID;
   4730 
   4731                     BCM_IF_ERROR_RETURN
   4732                         ((*trav_fn)(unit, group, group_flags, user_data));
   4733                 }
   4734             }
   4735         }
   4736     }
   4737 
   4738     return BCM_E_NONE;
   4739 }
   4740 #endif	/* BCM_XGS3_FABRIC_SUPPORT */
   4741 
   4742 /*
   4743  * Function:
   4744  *      bcm_esw_multicast_init
   4745  * Purpose:
   4746  *      Initialize the multicast module.
   4747  * Parameters:
   4748  *      unit - (IN) Unit number.
   4749  * Returns:
   4750  *      BCM_E_xxx
   4751  * Notes:
   4752  */
   4753 int 
   4754 bcm_esw_multicast_init(int unit)
   4755 {
   4756 #ifdef BCM_WARM_BOOT_SUPPORT
   4757     multicast_mode_set[unit] = FALSE;
   4758 #endif /* BCM_WARM_BOOT_SUPPORT */
   4759 
   4760 #ifdef BCM_XGS3_FABRIC_SUPPORT
   4761     if (SOC_IS_XGS3_FABRIC(unit)) {
   4762         /* Fabrics must track the multicast groups here, since they
   4763          * are not recorded in the mcast or IPMC modules. */
   4764         BCM_IF_ERROR_RETURN(_bcm_esw_fabric_multicast_init(unit));
   4765         multicast_initialized[unit] = TRUE;
   4766         return BCM_E_NONE;
   4767     }
   4768 #endif /* BCM_XGS3_FABRIC_SUPPORT */
   4769 
   4770 #ifdef BCM_SHADOW_SUPPORT
   4771     if (SOC_IS_SHADOW(unit)) {
   4772         multicast_initialized[unit] = TRUE;
   4773         return BCM_E_NONE;
   4774     }
   4775 #endif /*BCM_SHADOW_SUPPORT*/
   4776 
   4777 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3)
   4778     if (SOC_IS_TRX(unit)) {
   4779         BCM_IF_ERROR_RETURN(bcm_xgs3_mcast_init(unit));
   4780         BCM_IF_ERROR_RETURN(bcm_trx_multicast_init(unit));
   4781     }
   4782 #endif /* BCM_TRX_SUPPORT && INCLUDE_L3 */
   4783 
   4784 #if defined(BCM_FIREBOLT_SUPPORT) || defined(BCM_SCORPION_SUPPORT)
   4785     if (SOC_REG_IS_VALID(unit, IPMC_L3_MTUr)) {
   4786         soc_reg_t reg;
   4787         uint64 rval64, *rval64s[1];
   4788         uint32 pindex;
   4789         /* Create profile for IPMC_L3_MTU register */
   4790         if (_bcm_mtu_profile[unit] == NULL) {
   4791             _bcm_mtu_profile[unit] =
   4792                 sal_alloc(sizeof(soc_profile_reg_t), "MTU size Profile Reg");
   4793             if (_bcm_mtu_profile[unit] == NULL) {
   4794                 return BCM_E_MEMORY;
   4795             }
   4796             soc_profile_reg_t_init(_bcm_mtu_profile[unit]);
   4797             reg = IPMC_L3_MTUr;
   4798             BCM_IF_ERROR_RETURN
   4799                 (soc_profile_reg_create(unit, &reg, 1, _bcm_mtu_profile[unit]));
   4800             /* Add a default entry for backward comaptability */
   4801             COMPILER_64_ZERO(rval64);
   4802             COMPILER_64_SET(rval64, 0, 0x3fff);
   4803             rval64s[0] = &rval64;
   4804             BCM_IF_ERROR_RETURN
   4805                 (soc_profile_reg_add(unit, _bcm_mtu_profile[unit], rval64s,
   4806                                      1, &pindex)); 
   4807         }
   4808     }
   4809 #endif
   4810 
   4811     multicast_initialized[unit] = TRUE;
   4812     return BCM_E_NONE;
   4813 }
   4814 
   4815 /*
   4816  * Function:
   4817  *      bcm_esw_multicast_detach
   4818  * Purpose:
   4819  *      Shut down (uninitialize) the multicast module.
   4820  * Parameters:
   4821  *      unit - (IN) Unit number.
   4822  * Returns:
   4823  *      BCM_E_xxx
   4824  * Notes:
   4825  */
   4826 int 
   4827 bcm_esw_multicast_detach(int unit)
   4828 {
   4829 #ifdef BCM_XGS3_FABRIC_SUPPORT
   4830     if (SOC_IS_XGS3_FABRIC(unit)) {
   4831         /* Fabrics must track the multicast groups here, since they
   4832          * are not recorded in the mcast or IPMC modules. */
   4833         BCM_IF_ERROR_RETURN(_bcm_esw_fabric_multicast_detach(unit));
   4834         multicast_initialized[unit] = FALSE;
   4835         return BCM_E_NONE;
   4836     }
   4837 #endif /* BCM_XGS3_FABRIC_SUPPORT */
   4838 
   4839 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3)
   4840     if (SOC_IS_TRX(unit)) {
   4841         BCM_IF_ERROR_RETURN(bcm_trx_multicast_detach(unit));
   4842         multicast_initialized[unit] = FALSE;
   4843         return BCM_E_NONE;
   4844     }
   4845 #endif /* BCM_TRX_SUPPORT && INCLUDE_L3 */
   4846 
   4847     multicast_initialized[unit] = FALSE;
   4848     return BCM_E_NONE;
   4849 }
   4850 
   4851 /*
   4852  * Function:
   4853  *      bcm_multicast_create
   4854  * Purpose:
   4855  *      Allocate a multicast group index
   4856  * Parameters:
   4857  *      unit       - (IN)   Device Number
   4858  *      flags      - (IN)   BCM_MULTICAST_*
   4859  *      group      - (OUT)  Group ID
   4860  * Returns:
   4861  *      BCM_E_XXX
   4862  */
   4863 int
   4864 bcm_esw_multicast_create(int unit, uint32 flags, bcm_multicast_t *group)
   4865 {
   4866     int rv = BCM_E_UNAVAIL;
   4867 
   4868     MULTICAST_INIT_CHECK(unit);
   4869 
   4870 #ifdef BCM_XGS3_FABRIC_SUPPORT
   4871     if (SOC_IS_XGS3_FABRIC(unit)) {
   4872         return _bcm_esw_fabric_multicast_create(unit, flags, group);
   4873     }
   4874 #endif /* BCM_XGS3_FABRIC_SUPPORT */
   4875 
   4876 #if defined(BCM_XGS3_SWITCH_SUPPORT) 
   4877     if (SOC_IS_XGS3_SWITCH(unit)) {
   4878 #ifdef BCM_TOMAHAWK3_SUPPORT
   4879         /* Check for unsupported multicast interface types */
   4880         if (SOC_IS_TOMAHAWK3(unit)) {
   4881             uint32 unsupp_flags;
   4882 
   4883             unsupp_flags = BCM_MULTICAST_TYPE_VPLS |
   4884                            BCM_MULTICAST_TYPE_SUBPORT |
   4885                            BCM_MULTICAST_TYPE_MIM |
   4886                            BCM_MULTICAST_TYPE_WLAN |
   4887                            BCM_MULTICAST_TYPE_VLAN |
   4888                            BCM_MULTICAST_TYPE_TRILL |
   4889                            BCM_MULTICAST_TYPE_NIV |
   4890                            BCM_MULTICAST_TYPE_L2GRE |
   4891                            BCM_MULTICAST_TYPE_VXLAN |
   4892                            BCM_MULTICAST_TYPE_EXTENDER |
   4893                            BCM_MULTICAST_TYPE_MAC |
   4894                            BCM_MULTICAST_TYPE_PORTS_GROUP |
   4895                            BCM_MULTICAST_DISABLE_SRC_KNOCKOUT |
   4896                            BCM_MULTICAST_INGRESS_GROUP |
   4897                            BCM_MULTICAST_EGRESS_GROUP;
   4898 
   4899             if (flags & unsupp_flags) {
   4900                 return BCM_E_UNAVAIL;
   4901             }
   4902         }
   4903 #endif /* BCM_TOMAHAWK3_SUPPORT */
   4904         rv = _bcm_esw_multicast_create(unit, flags, group);
   4905 
   4906 #if defined(BCM_WARM_BOOT_SUPPORT) && defined(INCLUDE_L3)
   4907         if (BCM_SUCCESS(rv) && !multicast_mode_set[unit]) {
   4908             /* Notify IPMC module that we're operating in multicast mode
   4909              * for Warm Boot purposes */
   4910             BCM_IF_ERROR_RETURN
   4911                 (_bcm_esw_ipmc_repl_wb_flags_set(unit,
   4912                                                  _BCM_IPMC_WB_MULTICAST_MODE,
   4913                                                  _BCM_IPMC_WB_MULTICAST_MODE));
   4914             multicast_mode_set[unit] = TRUE;
   4915         }
   4916 #endif /* BCM_WARM_BOOT_SUPPORT && INCLUDE_L3 */
   4917     }
   4918 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   4919     return rv;
   4920 }
   4921 
   4922 /*
   4923  * Function:
   4924  *      bcm_multicast_destroy
   4925  * Purpose:
   4926  *      Free a multicast group index
   4927  * Parameters:
   4928  *      unit       - (IN) Device Number
   4929  *      group      - (IN) Group ID
   4930  * Returns:
   4931  *      BCM_E_XXX
   4932  */
   4933 int
   4934 bcm_esw_multicast_destroy(int unit, bcm_multicast_t group)
   4935 {
   4936     MULTICAST_INIT_CHECK(unit);
   4937 
   4938     if (!_BCM_MULTICAST_IS_SET(group)) {
   4939         return BCM_E_PARAM;
   4940     }
   4941 
   4942 #ifdef BCM_XGS3_FABRIC_SUPPORT
   4943     if (SOC_IS_XGS3_FABRIC(unit)) {
   4944         return _bcm_esw_fabric_multicast_destroy(unit, group);
   4945     }
   4946 #endif /* BCM_XGS3_FABRIC_SUPPORT */
   4947 
   4948 #if defined(BCM_XGS3_SWITCH_SUPPORT) 
   4949     if (SOC_IS_XGS3_SWITCH(unit)) {
   4950         if (_BCM_MULTICAST_IS_L2(group)) {
   4951             return _bcm_esw_multicast_l2_destroy(unit, group);
   4952         } else {
   4953 #if defined(INCLUDE_L3)
   4954             return _bcm_esw_multicast_l3_destroy(unit, group);
   4955 #endif
   4956         }
   4957     }
   4958 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   4959     return BCM_E_UNAVAIL;
   4960 }
   4961 
   4962 /*
   4963  * Function:
   4964  *      bcmi_esw_multicast_multi_alloc
   4965  * Purpose:
   4966  *      Create/alloc multiple multicast groups
   4967  * Parameters:
   4968  *      unit          - (IN) Unit number.
   4969  *      info          - (IN) info for creating groups.
   4970  *      base_mc_group - (IN/OUT) base group number
   4971  *                               of multiple groups.
   4972  * Returns:
   4973  *      BCM_E_XXX
   4974  * Notes:
   4975  */
   4976 int
   4977 bcmi_esw_multicast_multi_alloc(int unit, bcm_multicast_multi_info_t info,
   4978                               bcm_multicast_t *base_mc_group)
   4979 {
   4980     int rv = BCM_E_NONE;
   4981 
   4982 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3)
   4983     int rv2 = BCM_E_NONE;
   4984     ipmc_entry_t entry;
   4985     int num_entries = info.number_of_elements;
   4986     int i=0,j=0; /* iterators */
   4987     bcm_multicast_t group;
   4988     int flags=0, type;
   4989     uint32 ipmc_id = 0;
   4990 
   4991     IPMC_INIT(unit);
   4992 
   4993     /* dont allow more than 4 groups allocation */
   4994     if ((info.number_of_elements < 1) ||
   4995         (info.number_of_elements > 4)) {
   4996         return BCM_E_PARAM;
   4997     }
   4998 
   4999     IPMC_LOCK(unit);
   5000 
   5001     /* create multi consecutive multicast groups */
   5002     if (info.flags & BCM_MULTICAST_MULTI_WITH_ID) {
   5003         ipmc_id = _BCM_MULTICAST_ID_GET(*base_mc_group);
   5004         if ((ipmc_id >= (IPMC_GROUP_NUM(unit)) - num_entries) ||
   5005             (ipmc_id < 1)) {
   5006 
   5007             IPMC_UNLOCK(unit);
   5008             return BCM_E_PARAM;
   5009         }
   5010         i = ipmc_id;
   5011         for (j=0; j < num_entries; j++) {
   5012             if ((ipmc_id + j) == IPMC_GROUP_NUM(unit)) {
   5013                 IPMC_UNLOCK(unit);
   5014                 return BCM_E_FULL;
   5015             }
   5016 
   5017             if (IPMC_USED_ISSET(unit, ipmc_id + j)) {
   5018                 IPMC_UNLOCK(unit);
   5019                 return BCM_E_EXISTS;
   5020             }
   5021         }
   5022     } else {
   5023         for (i = 0; i < (IPMC_GROUP_NUM(unit) - num_entries); i++) {
   5024             if (!IPMC_USED_ISSET(unit, i)) {
   5025                 for (j=1; j<num_entries ; j++) {
   5026                     if(IPMC_USED_ISSET(unit, (i+j))) {
   5027                         break;
   5028                     }
   5029                 }
   5030             }
   5031             if (j == num_entries) {
   5032                 break;
   5033             }
   5034         }
   5035         if (j < num_entries) {
   5036             IPMC_UNLOCK(unit);
   5037             return BCM_E_FULL;
   5038         }
   5039     }
   5040 
   5041     IPMC_UNLOCK(unit);
   5042     /*
   5043      * we only support 2 type of groups till now.
   5044      * make L3 type as default
   5045      */
   5046     if (info.flags & BCM_MULTICAST_MULTI_TYPE_VPLS) {
   5047         flags |= BCM_MULTICAST_TYPE_VPLS;
   5048         type = _BCM_MULTICAST_TYPE_VPLS;
   5049     } else {
   5050         flags |= BCM_MULTICAST_TYPE_L3;
   5051         type = _BCM_MULTICAST_TYPE_L3;
   5052     }
   5053 
   5054     flags |= BCM_MULTICAST_WITH_ID;
   5055     for (j=0; j<num_entries; j++) {
   5056         group = i + j;
   5057         rv = bcm_esw_multicast_create(unit, flags, &group);
   5058         if (BCM_FAILURE(rv)) {
   5059             /* we need to clear all the groups that we have created here */
   5060             /* reduce one iteration as this is not successful */
   5061             j--;
   5062             goto create_cleanup;
   5063         }
   5064         IPMC_USED_SET(unit, i+j);
   5065         if (j == 0) {
   5066             *base_mc_group = group;
   5067         }
   5068         rv = soc_mem_read(unit, L3_IPMCm, MEM_BLOCK_ANY, i+j, &entry);
   5069 
   5070         if (BCM_FAILURE(rv)) {
   5071             goto create_cleanup;
   5072         }
   5073         soc_L3_IPMCm_field32_set(unit, &entry, VALIDf, 1);
   5074         rv = soc_mem_write(unit, L3_IPMCm, MEM_BLOCK_ALL, i+j, &entry);
   5075         if (BCM_FAILURE(rv)) {
   5076             goto create_cleanup;
   5077         }
   5078     }
   5079     rv =  bcmi_multicast_multi_count_set(unit, *base_mc_group, num_entries);
   5080     if (BCM_FAILURE(rv)) {
   5081         goto create_cleanup;
   5082     }
   5083 
   5084     return BCM_E_NONE;
   5085 
   5086 create_cleanup:
   5087     if (BCM_FAILURE(rv)) {
   5088         while (j >= 0) {
   5089             _BCM_MULTICAST_GROUP_SET(group, type, i+j);
   5090             rv2 = bcm_esw_multicast_destroy(unit, group);
   5091             LOG_ERROR(BSL_LS_BCM_COMMON, (BSL_META_U(unit,
   5092                  "destroy for multicast group 0x%x failed.  error : %s \n"),
   5093                  group, bcm_errmsg(rv2)));
   5094 
   5095              IPMC_USED_CLR(unit, i+j);
   5096             /*
   5097              * Capturing the error but not returning back.
   5098              * We should return the original error.
   5099              * But even if this fails, we will have to keep moving
   5100              * to report the original error to user.
   5101              * Displaying one error message.
   5102              */
   5103             rv2 = soc_mem_read(unit, L3_IPMCm, MEM_BLOCK_ANY, i+j, &entry);
   5104             LOG_ERROR(BSL_LS_BCM_COMMON, (BSL_META_U(unit,
   5105                  "mem read for L3_IPMCm at index %d failed.  error : %s \n"),
   5106                  i+j, bcm_errmsg(rv2)));
   5107 
   5108             soc_L3_IPMCm_field32_set(unit, &entry, VALIDf, 0);
   5109             rv2 = soc_mem_write(unit, L3_IPMCm, MEM_BLOCK_ALL, i+j, &entry);
   5110             LOG_ERROR(BSL_LS_BCM_COMMON, (BSL_META_U(unit,
   5111                  "mem write for L3_IPMCm at index %d failed.  error : %s \n"),
   5112                  i+j, bcm_errmsg(rv2)));
   5113             /* reduce the interator for next cycle */
   5114             j--;
   5115         }
   5116         *base_mc_group = -1;
   5117     }
   5118 #endif
   5119     return rv;
   5120 }
   5121 
   5122 /*
   5123  * Function:
   5124  *      bcmi_esw_multicast_multi_free
   5125  * Purpose:
   5126  *      Free multiple multicast groups
   5127  * Parameters:
   5128  *      unit          - (IN) Unit number.
   5129  *      base_mc_group - (IN) base group number
   5130  *                               of multiple groups.
   5131  * Returns:
   5132  *      BCM_E_XXX
   5133  * Notes:
   5134  */
   5135 int
   5136 bcmi_esw_multicast_multi_free(int unit, bcm_multicast_t base_mc_group)
   5137 {
   5138 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3)
   5139 
   5140     int rv;
   5141     int num_entries = 4;
   5142     int i = 0; /* iterators */
   5143     int ipmc_id = _BCM_MULTICAST_ID_GET(base_mc_group);
   5144 
   5145     if (!_BCM_MULTICAST_IS_SET(base_mc_group)) {
   5146         return BCM_E_PARAM;
   5147     }
   5148 
   5149     if ((ipmc_id < 0) || (ipmc_id >= soc_mem_index_count(unit, L3_IPMCm))) {
   5150         return BCM_E_PARAM;
   5151     }
   5152 
   5153     IPMC_INIT(unit);
   5154 
   5155     if(!(IPMC_USED_ISSET(unit, ipmc_id))) {
   5156         return BCM_E_NOT_FOUND;
   5157     }
   5158 
   5159     BCM_IF_ERROR_RETURN(
   5160         bcmi_multicast_multi_count_get(unit, base_mc_group, &num_entries));
   5161 
   5162     if (num_entries == 0) {
   5163         /* nothing to be done. just return */
   5164         return BCM_E_NONE;
   5165     }
   5166 
   5167     for (; i< num_entries; i++) {
   5168         IPMC_USED_CLR(unit, (ipmc_id + i));
   5169         rv = bcm_esw_multicast_destroy(unit, base_mc_group + i);
   5170 
   5171         if (BCM_FAILURE(rv)) {
   5172             return rv;
   5173         }
   5174 
   5175     }
   5176 #endif
   5177     return BCM_E_NONE;
   5178 }
   5179 /*
   5180  * Function:
   5181  *      bcm_multicast_l3_encap_get
   5182  * Purpose:
   5183  *      Get the Encap ID for L3.
   5184  * Parameters:
   5185  *      unit  - (IN) Unit number.
   5186  *      group - (IN) Multicast group ID.
   5187  *      port  - (IN) Physical port.
   5188  *      intf  - (IN) L3 interface ID.
   5189  *      encap_id - (OUT) Encap ID.
   5190  * Returns:
   5191  *      BCM_E_XXX
   5192  * Notes:
   5193  */
   5194 int 
   5195 bcm_esw_multicast_l3_encap_get(int unit, bcm_multicast_t group,
   5196                                bcm_gport_t port, bcm_if_t intf,
   5197                                bcm_if_t *encap_id)
   5198 {
   5199     MULTICAST_INIT_CHECK(unit);
   5200 
   5201     if (encap_id == NULL) {
   5202         return BCM_E_PARAM;
   5203     }
   5204 
   5205 #ifdef BCM_XGS3_FABRIC_SUPPORT
   5206     if (SOC_IS_XGS3_FABRIC(unit)) {
   5207         /* Encap ID is not used for fabric devices in XGS3 */
   5208         *encap_id = BCM_IF_INVALID;
   5209         return BCM_E_NONE;
   5210     }
   5211 #endif	/* BCM_XGS3_FABRIC_SUPPORT */
   5212 
   5213 #if defined(BCM_XGS3_SWITCH_SUPPORT) && defined(INCLUDE_L3)
   5214     if (SOC_IS_XGS3_SWITCH(unit)) {
   5215         if (BCM_GPORT_IS_VLAN_PORT(port) ||
   5216             BCM_GPORT_IS_NIV_PORT(port) ||
   5217             BCM_GPORT_IS_EXTENDER_PORT(port)) {
   5218 #ifdef BCM_TRIDENT2_SUPPORT
   5219             if (soc_feature(unit, soc_feature_virtual_port_routing)) {
   5220                 return bcm_td2_multicast_l3_vp_encap_get(unit, group, port,
   5221                         intf, encap_id);
   5222             } else
   5223 #endif /* BCM_TRIDENT2_SUPPORT */
   5224             {
   5225                 return BCM_E_UNAVAIL;
   5226             }
   5227         }
   5228 
   5229 #ifdef BCM_GREYHOUND_SUPPORT
   5230         if (soc_feature(unit, soc_feature_l3mc_use_egress_next_hop)) {
   5231             /* intf for this feature must be egress_nh index
   5232              * Note: intf=BCM_IF_INVALID is special process for adding
   5233              *      l2mc egress. this value must be handled.
   5234              */
   5235             if (intf != BCM_IF_INVALID) {
   5236                 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)){
   5237                     return bcm_esw_multicast_egress_object_encap_get(unit,
   5238                            group, intf, encap_id);
   5239                 }
   5240             }
   5241         }
   5242 #endif /* BCM_GREYHOUND_SUPPORT */
   5243 
   5244         /* For L3 IPMC, encap_id is simply the L3 interface ID */
   5245         *encap_id = intf;
   5246         return BCM_E_NONE;
   5247     }
   5248 #endif /* BCM_XGS3_SWITCH_SUPPORT && INCLUDE_L3 */
   5249 
   5250     return BCM_E_UNAVAIL; 
   5251 }
   5252 
   5253 /*
   5254  * Function:
   5255  *      bcm_multicast_l2_encap_get
   5256  * Purpose:
   5257  *      Get the Encap ID for L2.
   5258  * Parameters:
   5259  *      unit     - (IN) Unit number.
   5260  *      group    - (IN) Multicast group ID.
   5261  *      port     - (IN) Physical port.
   5262  *      vlan     - (IN) Vlan.
   5263  *      encap_id - (OUT) Encap ID.
   5264  * Returns:
   5265  *      BCM_E_XXX
   5266  * Notes:
   5267  */
   5268 int 
   5269 bcm_esw_multicast_l2_encap_get(int unit, bcm_multicast_t group,
   5270                                bcm_gport_t port, bcm_vlan_t vlan,
   5271                                bcm_if_t *encap_id)
   5272 {
   5273     MULTICAST_INIT_CHECK(unit);
   5274     
   5275     if (encap_id == NULL) {
   5276         return BCM_E_PARAM;
   5277     }
   5278 
   5279     *encap_id = BCM_IF_INVALID;
   5280 
   5281 #if defined(BCM_XGS3_SWITCH_SUPPORT) && defined(INCLUDE_L3)
   5282     if (SOC_IS_XGS3_SWITCH(unit)) {
   5283 
   5284 #if defined(BCM_HGPROXY_COE_SUPPORT)
   5285         if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   5286             _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) {
   5287             /* Encap ID is used for L2 in XGS for TD2+CoE GPORT-SUBPORT
   5288                types */
   5289             return _bcmi_coe_multicast_subport_encap_get(unit, port, encap_id);
   5290 
   5291         } else
   5292 #endif
   5293 		{
   5294 			return BCM_E_NONE;
   5295 		}
   5296     }
   5297 #endif /* BCM_XGS3_SWITCH_SUPPORT && INCLUDE_L3 */
   5298     return BCM_E_UNAVAIL; 
   5299 }
   5300 
   5301 /*
   5302  * Function:
   5303  *      bcm_multicast_trill_encap_get
   5304  * Purpose:
   5305  *      Get the Encap ID for a TRILL port.
   5306  * Parameters:
   5307  *      unit         - (IN) Unit number.
   5308  *      group        - (IN) Multicast group ID.
   5309  *      port         - (IN) Physical port.
   5310  *      intf          - (IN) L3 interface ID.
   5311  *      encap_id     - (OUT) Encap ID.
   5312  * Returns:
   5313  *      BCM_E_XXX
   5314  * Notes:
   5315  */
   5316 int
   5317 bcm_esw_multicast_trill_encap_get(int unit, bcm_multicast_t group, bcm_gport_t port,
   5318                                  bcm_if_t intf, bcm_if_t *encap_id)
   5319 {
   5320     MULTICAST_INIT_CHECK(unit);
   5321 
   5322     if (encap_id == NULL) {
   5323         return BCM_E_PARAM;
   5324     }
   5325 
   5326 #if defined(BCM_TRIDENT_SUPPORT) && defined(INCLUDE_L3)
   5327     if (soc_feature(unit, soc_feature_trill)) { 
   5328         /* For TRILL IPMC, encap_id is simply the L3 interface ID */
   5329         *encap_id = intf;
   5330         return BCM_E_NONE;
   5331     }
   5332 #endif /* BCM_TRIDENT_SUPPORT && INCLUDE_L3 */
   5333     return BCM_E_UNAVAIL;
   5334 }
   5335 
   5336 /*
   5337  * Function:
   5338  *      bcm_multicast_vpls_encap_get
   5339  * Purpose:
   5340  *      Get the Encap ID for a MPLS port.
   5341  * Parameters:
   5342  *      unit         - (IN) Unit number.
   5343  *      group        - (IN) Multicast group ID.
   5344  *      port         - (IN) Physical port.
   5345  *      mpls_port_id - (IN) MPLS port ID.
   5346  *      encap_id     - (OUT) Encap ID.
   5347  * Returns:
   5348  *      BCM_E_XXX
   5349  * Notes:
   5350  */
   5351 int
   5352 bcm_esw_multicast_vpls_encap_get(int unit, bcm_multicast_t group, bcm_gport_t port,
   5353                                  bcm_gport_t mpls_port_id, bcm_if_t *encap_id)
   5354 {
   5355     MULTICAST_INIT_CHECK(unit);
   5356     
   5357     if (encap_id == NULL) {
   5358         return BCM_E_PARAM;
   5359     }
   5360 
   5361 #if defined(BCM_TRIUMPH2_SUPPORT) && defined(INCLUDE_L3)
   5362     if (SOC_IS_TD_TT(unit) || SOC_IS_TRIUMPH2(unit) ||
   5363             SOC_IS_APOLLO(unit) || SOC_IS_VALKYRIE2(unit) ||
   5364             SOC_IS_KATANAX(unit) || SOC_IS_TRIUMPH3(unit)) {
   5365         return bcm_tr2_multicast_vpls_encap_get(unit, group, port, 
   5366                                                mpls_port_id, encap_id);
   5367     }
   5368 #endif /* BCM_TRIUMPH2_SUPPORT && INCLUDE_L3 */
   5369 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3)
   5370     if (SOC_IS_TR_VL(unit) && !SOC_IS_HURRICANEX(unit) && 
   5371         !SOC_IS_GREYHOUND2(unit)) {
   5372         return bcm_tr_multicast_vpls_encap_get(unit, group, port, 
   5373                                                mpls_port_id, encap_id);
   5374     }
   5375 #endif /* BCM_TRX_SUPPORT && INCLUDE_L3 */
   5376     return BCM_E_UNAVAIL;
   5377 }
   5378 
   5379 /*
   5380  * Function:
   5381  *      bcm_multicast_subport_encap_get
   5382  * Purpose:
   5383  *      Get the Encap ID for a subport.
   5384  * Parameters:
   5385  *      unit      - (IN) Unit number.
   5386  *      group     - (IN) Multicast group ID.
   5387  *      port      - (IN) Physical port.
   5388  *      subport   - (IN) Subport ID.
   5389  *      encap_id  - (OUT) Encap ID.
   5390  * Returns:
   5391  *      BCM_E_XXX
   5392  * Notes:
   5393  */
   5394 int
   5395 bcm_esw_multicast_subport_encap_get(int unit, bcm_multicast_t group, bcm_gport_t port,
   5396                                     bcm_gport_t subport, bcm_if_t *encap_id)
   5397 {
   5398     MULTICAST_INIT_CHECK(unit);
   5399 
   5400     if (encap_id == NULL) {
   5401         return BCM_E_PARAM;
   5402     }
   5403 
   5404 #if defined(BCM_TRIUMPH2_SUPPORT) && defined(INCLUDE_L3)
   5405     if (SOC_IS_TD_TT(unit) || SOC_IS_TRIUMPH2(unit) || SOC_IS_APOLLO(unit) || 
   5406         SOC_IS_VALKYRIE2(unit) || SOC_IS_ENDURO(unit) || SOC_IS_KATANAX(unit) ||
   5407         SOC_IS_TRIUMPH3(unit)) {
   5408         return bcm_tr2_multicast_subport_encap_get(unit, group, port, 
   5409                                                   subport, encap_id);
   5410     }
   5411 #endif /* BCM_TRIUMPH2_SUPPORT && INCLUDE_L3 */
   5412 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3)
   5413     if (SOC_IS_TRX(unit) && !SOC_IS_SCORPION(unit) && !SOC_IS_HURRICANE(unit) && 
   5414         !SOC_IS_HURRICANE2(unit) && !SOC_IS_XGS3_FABRIC(unit)) {
   5415         return bcm_tr_multicast_subport_encap_get(unit, group, port, 
   5416                                                   subport, encap_id);
   5417     }
   5418 #endif /* BCM_TRX_SUPPORT && INCLUDE_L3 */
   5419     return BCM_E_UNAVAIL;
   5420 }
   5421 
   5422 /*
   5423  * Function:
   5424  *      bcm_multicast_mim_encap_get
   5425  * Purpose:
   5426  *      Get the Encap ID for MiM.
   5427  * Parameters:
   5428  *      unit      - (IN) Unit number.
   5429  *      group     - (IN) Multicast group ID.
   5430  *      port      - (IN) Physical port.
   5431  *      mim_port  - (IN) MiM port ID.
   5432  *      encap_id  - (OUT) Encap ID.
   5433  * Returns:
   5434  *      BCM_E_XXX
   5435  * Notes:
   5436  */
   5437 int
   5438 bcm_esw_multicast_mim_encap_get(int unit, bcm_multicast_t group, bcm_gport_t port,
   5439                                 bcm_gport_t mim_port, bcm_if_t *encap_id)
   5440 {
   5441     MULTICAST_INIT_CHECK(unit);
   5442 
   5443     if (encap_id == NULL) {
   5444         return BCM_E_PARAM;
   5445     }
   5446 
   5447 #if defined(BCM_TRIUMPH2_SUPPORT) && defined(INCLUDE_L3)
   5448     if (soc_feature(unit, soc_feature_mim)) {
   5449         return bcm_tr2_multicast_mim_encap_get(unit, group, port, 
   5450                                               mim_port, encap_id);
   5451     }
   5452 #endif /* BCM_TRIUMPH2_SUPPORT && INCLUDE_L3 */
   5453     return BCM_E_UNAVAIL;
   5454 }
   5455 
   5456 /*
   5457  * Function:
   5458  *      bcm_multicast_wlan_encap_get
   5459  * Purpose:
   5460  *      Get the Encap ID for WLAN.
   5461  * Parameters:
   5462  *      unit      - (IN) Unit number.
   5463  *      group     - (IN) Multicast group ID.
   5464  *      port      - (IN) Physical port.
   5465  *      wlan_port - (IN) WLAN port ID.
   5466  *      encap_id  - (OUT) Encap ID.
   5467  * Returns:
   5468  *      BCM_E_XXX
   5469  * Notes:
   5470  */
   5471 int
   5472 bcm_esw_multicast_wlan_encap_get(int unit, bcm_multicast_t group, bcm_gport_t port,
   5473                                  bcm_gport_t wlan_port, bcm_if_t *encap_id)
   5474 {
   5475     MULTICAST_INIT_CHECK(unit);
   5476     
   5477     if (encap_id == NULL) {
   5478         return BCM_E_PARAM;
   5479     }
   5480 
   5481 #if defined(BCM_TRIUMPH2_SUPPORT) && defined(INCLUDE_L3)
   5482     if (soc_feature(unit, soc_feature_wlan)) {
   5483         return bcm_tr2_multicast_wlan_encap_get(unit, group, port, 
   5484                                                wlan_port, encap_id);
   5485     }
   5486 #endif /* BCM_TRIUMPH2_SUPPORT && INCLUDE_L3 */
   5487     return BCM_E_UNAVAIL;
   5488 }
   5489 
   5490 /*
   5491  * Function:
   5492  *      bcm_multicast_vlan_encap_get
   5493  * Purpose:
   5494  *      Get the Encap ID for VLAN virtual port.
   5495  * Parameters:
   5496  *      unit      - (IN) Unit number.
   5497  *      group     - (IN) Multicast group ID.
   5498  *      port      - (IN) Physical port.
   5499  *      vlan_port - (IN) VLAN port ID.
   5500  *      encap_id  - (OUT) Encap ID.
   5501  * Returns:
   5502  *      BCM_E_XXX
   5503  * Notes:
   5504  */
   5505 int
   5506 bcm_esw_multicast_vlan_encap_get(int unit, bcm_multicast_t group,
   5507                                  bcm_gport_t port, bcm_gport_t vlan_port_id,
   5508                                  bcm_if_t *encap_id)
   5509 {
   5510     MULTICAST_INIT_CHECK(unit);
   5511     
   5512     if (encap_id == NULL) {
   5513         return BCM_E_PARAM;
   5514     }
   5515 
   5516 #if defined(BCM_TRIUMPH2_SUPPORT) && defined(INCLUDE_L3)
   5517     if (soc_feature(unit, soc_feature_vlan_vp)) {
   5518         int vp;
   5519         ing_dvp_table_entry_t dvp;
   5520 
   5521         if (!BCM_GPORT_IS_VLAN_PORT(vlan_port_id)) {
   5522             return BCM_E_PARAM;
   5523         }
   5524         vp = BCM_GPORT_VLAN_PORT_ID_GET(vlan_port_id); 
   5525         if (vp >= soc_mem_index_count(unit, SOURCE_VPm)) {
   5526             return BCM_E_PARAM;
   5527         }
   5528         if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) {
   5529             return BCM_E_PARAM;
   5530         }
   5531         BCM_IF_ERROR_RETURN (READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp));
   5532 
   5533         /* Next-hop index is used for multicast replication */
   5534         *encap_id = (bcm_if_t) soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   5535         if (!SOC_IS_ENDURO(unit)) {
   5536             *encap_id += BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   5537         }
   5538         return BCM_E_NONE;
   5539     }
   5540 #endif /* BCM_TRIUMPH2_SUPPORT && INCLUDE_L3 */
   5541 
   5542     return BCM_E_UNAVAIL;
   5543 }
   5544 
   5545 /*
   5546  * Function:
   5547  *      bcm_multicast_niv_encap_get
   5548  * Purpose:
   5549  *      Get the Encap ID for NIV virtual port.
   5550  * Parameters:
   5551  *      unit        - (IN) Unit number.
   5552  *      group       - (IN) Multicast group ID.
   5553  *      port        - (IN) Physical port.
   5554  *      niv_port_id - (IN) NIV port ID.
   5555  *      encap_id    - (OUT) Encap ID.
   5556  * Returns:
   5557  *      BCM_E_XXX
   5558  * Notes:
   5559  */
   5560 int
   5561 bcm_esw_multicast_niv_encap_get(int unit, bcm_multicast_t group, bcm_gport_t port,
   5562                                 bcm_gport_t niv_port_id, bcm_if_t *encap_id)
   5563 {
   5564     MULTICAST_INIT_CHECK(unit);
   5565     
   5566     if (encap_id == NULL) {
   5567         return BCM_E_PARAM;
   5568     }
   5569 
   5570 #if defined(BCM_TRIDENT_SUPPORT) && defined(INCLUDE_L3)
   5571     if (soc_feature(unit, soc_feature_niv)) {
   5572         int vp;
   5573         ing_dvp_table_entry_t dvp;
   5574 
   5575         if (!BCM_GPORT_IS_NIV_PORT(niv_port_id)) {
   5576             return BCM_E_PARAM;
   5577         }
   5578         vp = BCM_GPORT_NIV_PORT_ID_GET(niv_port_id); 
   5579         if (vp >= soc_mem_index_count(unit, SOURCE_VPm)) {
   5580             return BCM_E_PARAM;
   5581         }
   5582         if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   5583             return BCM_E_PARAM;
   5584         }
   5585         BCM_IF_ERROR_RETURN (READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp));
   5586 
   5587         /* Next-hop index is used for multicast replication */
   5588         *encap_id = (bcm_if_t) soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   5589         *encap_id += BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   5590 
   5591         return BCM_E_NONE;
   5592     }
   5593 #endif /* BCM_TRIDENT_SUPPORT && INCLUDE_L3 */
   5594 
   5595     return BCM_E_UNAVAIL;
   5596 }
   5597 
   5598 /*
   5599  * Function:
   5600  *      bcm_esw_multicast_egress_object_encap_get
   5601  * Purpose:
   5602  *      Get the Encap ID for Egress_object
   5603  * Parameters:
   5604  *      unit        - (IN) Unit number.
   5605  *      group       - (IN) Multicast group ID.
   5606  *      intf          - (IN) Egress Object ID.
   5607  *      encap_id    - (OUT) Encap ID.
   5608  * Returns:
   5609  *      BCM_E_XXX
   5610  * Notes:
   5611  */
   5612 int
   5613 bcm_esw_multicast_egress_object_encap_get(int unit, bcm_multicast_t group, bcm_if_t intf,
   5614                                 bcm_if_t *encap_id)
   5615 {
   5616     MULTICAST_INIT_CHECK(unit);
   5617     
   5618     if (encap_id == NULL) {
   5619         return BCM_E_PARAM;
   5620     }
   5621 
   5622 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_GREYHOUND_SUPPORT)
   5623 #if defined(INCLUDE_L3)
   5624     if (soc_feature(unit, soc_feature_l3)) {
   5625         if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) {
   5626             if (soc_feature(unit, soc_feature_l3mc_use_egress_next_hop)) {
   5627                 *encap_id = intf;
   5628             } else {
   5629                 *encap_id = (intf - BCM_XGS3_EGRESS_IDX_MIN(unit)) + 
   5630                         BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   5631             }
   5632         } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) {
   5633             *encap_id = intf;
   5634         } else if (BCM_XGS3_PROXY_EGRESS_IDX_VALID(unit, intf)) {
   5635             *encap_id = (intf - BCM_XGS3_PROXY_EGRESS_IDX_MIN(unit)) + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   5636         } else {
   5637             return BCM_E_PARAM;
   5638         }
   5639         return BCM_E_NONE;
   5640     }
   5641 #endif  /* INCLUDE_L3 */
   5642 #endif /* BCM_TRIDENT_SUPPORT || BCM_GREYHOUND_SUPPORT */
   5643 
   5644     return BCM_E_UNAVAIL;
   5645 }
   5646 
   5647 /*
   5648  * Function:
   5649  *      bcm_esw_multicast_l2gre_encap_get
   5650  * Purpose:
   5651  *      Get the Encap ID for L2GRE virtual port
   5652  * Parameters:
   5653  *      unit        - (IN) Unit number.
   5654  *      group       - (IN) Multicast group ID.
   5655  *      port        - (IN) Physical port.
   5656  *      l2gre_port_id - (IN) L2GRE port ID.
   5657  *      encap_id    - (OUT) Encap ID.
   5658  * Returns:
   5659  *      BCM_E_XXX
   5660  * Notes:
   5661  */
   5662 int
   5663 bcm_esw_multicast_l2gre_encap_get(int unit, bcm_multicast_t group, bcm_gport_t port,
   5664                                 bcm_gport_t l2gre_port_id, bcm_if_t *encap_id)
   5665 {
   5666 	if (encap_id == NULL) {
   5667 	    return BCM_E_PARAM;
   5668 	}
   5669 
   5670 #if defined(BCM_TRIUMPH3_SUPPORT) && defined(INCLUDE_L3)
   5671     if (soc_feature(unit, soc_feature_l2gre)) {
   5672         int vp;
   5673         ing_dvp_table_entry_t dvp;
   5674 
   5675         if (!BCM_GPORT_IS_L2GRE_PORT(l2gre_port_id)) {
   5676             return BCM_E_PARAM;
   5677         }
   5678         /* Get Multicast DVP index */
   5679         vp = BCM_GPORT_L2GRE_PORT_ID_GET(l2gre_port_id); 
   5680         if (vp >= soc_mem_index_count(unit, SOURCE_VPm)) {
   5681             return BCM_E_PARAM;
   5682         }
   5683         if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeL2Gre)) {
   5684             return BCM_E_PARAM;
   5685         }
   5686         /* Multicast DVP will never point to ECMP group */
   5687         BCM_IF_ERROR_RETURN (READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp));
   5688         if (soc_ING_DVP_TABLEm_field32_get(unit, &dvp, ECMPf)) {
   5689             return BCM_E_PARAM;
   5690         }
   5691 
   5692         /* Next-hop index is used for multicast replication */
   5693         *encap_id = (bcm_if_t) soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   5694         *encap_id += BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   5695 
   5696         return BCM_E_NONE;
   5697     }
   5698 #endif /* BCM_TRIUMPH3_SUPPORT && INCLUDE_L3 */
   5699 
   5700     return BCM_E_UNAVAIL;
   5701 }
   5702 
   5703 
   5704 /*
   5705  * Function:
   5706  *      bcm_esw_multicast_vxlan_encap_get
   5707  * Purpose:
   5708  *      Get the Encap ID for VXLAN virtual port
   5709  * Parameters:
   5710  *      unit        - (IN) Unit number.
   5711  *      group       - (IN) Multicast group ID.
   5712  *      port        - (IN) Physical port.
   5713  *      vxlan_port_id - (IN) L2GRE port ID.
   5714  *      encap_id    - (OUT) Encap ID.
   5715  * Returns:
   5716  *      BCM_E_XXX
   5717  * Notes:
   5718  */
   5719 int
   5720 bcm_esw_multicast_vxlan_encap_get(int unit, bcm_multicast_t group, bcm_gport_t port,
   5721                                 bcm_gport_t vxlan_port_id, bcm_if_t *encap_id)
   5722 {
   5723 #if defined(INCLUDE_L3)
   5724 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_GREYHOUND2_SUPPORT)
   5725     int vp = -1;
   5726 #endif /* BCM_TRIDENT2_SUPPORT || BCM_GREYHOUND2_SUPPORT */
   5727 #endif /* INCLUDE_L3 */
   5728 
   5729     if (encap_id == NULL) {
   5730         return BCM_E_PARAM;
   5731     }
   5732 
   5733 #if defined(BCM_TRIDENT2_SUPPORT) && defined(INCLUDE_L3)
   5734     if (soc_feature(unit, soc_feature_vxlan)) {
   5735         ing_dvp_table_entry_t dvp;
   5736 
   5737         if (!BCM_GPORT_IS_VXLAN_PORT(vxlan_port_id)) {
   5738             return BCM_E_PARAM;
   5739         }
   5740 
   5741         /* Get Multicast DVP index */
   5742         vp = BCM_GPORT_VXLAN_PORT_ID_GET(vxlan_port_id); 
   5743         if (vp >= soc_mem_index_count(unit, SOURCE_VPm)) {
   5744             return BCM_E_PARAM;
   5745         }
   5746 
   5747         if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeVxlan)) {
   5748             return BCM_E_PARAM;
   5749         }
   5750 
   5751         /* Multicast DVP will never point to ECMP group */
   5752         BCM_IF_ERROR_RETURN (READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp));
   5753 
   5754         /* Next-hop index is used for multicast replication */
   5755         *encap_id = (bcm_if_t) soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   5756         *encap_id += BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   5757 
   5758         return BCM_E_NONE;
   5759     } else
   5760 #endif /* BCM_TRIDENT2_SUPPORT && INCLUDE_L3 */
   5761 #if defined(BCM_GREYHOUND2_SUPPORT) && defined(INCLUDE_L3)
   5762     if (soc_feature(unit, soc_feature_vxlan_lite)) {
   5763         int ecmp = 0, nh_ecmp_index = 0;
   5764 
   5765         if (!BCM_GPORT_IS_VXLAN_PORT(vxlan_port_id)) {
   5766             return BCM_E_PARAM;
   5767         }
   5768 
   5769         /* Get Multicast DVP index */
   5770         vp = BCM_GPORT_VXLAN_PORT_ID_GET(vxlan_port_id);
   5771         if (vp == -1) {
   5772             return BCM_E_PARAM;
   5773         }
   5774 
   5775         if (!bcmi_gh2_vxlan_vp_used_get(unit, vp)) {
   5776             return BCM_E_PARAM;
   5777         }
   5778 
   5779         BCM_IF_ERROR_RETURN(
   5780             bcmi_gh2_vxlan_port_to_nh_ecmp_index(unit, vp,
   5781                                                  &ecmp, &nh_ecmp_index));
   5782         if (ecmp) {
   5783             return BCM_E_PARAM;
   5784         }
   5785 
   5786         /* Next-hop index is used for multicast replication */
   5787         *encap_id = (bcm_if_t)nh_ecmp_index;
   5788         *encap_id += BCM_XGS3_EGRESS_IDX_MIN(unit);
   5789 
   5790         return BCM_E_NONE;
   5791     } else
   5792 #endif /* BCM_GREYHOUND2_SUPPORT && INCLUDE_L3 */
   5793     {
   5794         return BCM_E_UNAVAIL;
   5795     }
   5796 }
   5797 
   5798 /*
   5799  * Function:
   5800  *      bcm_multicast_extender_encap_get
   5801  * Purpose:
   5802  *      Get the Encap ID for Extender virtual port.
   5803  * Parameters:
   5804  *      unit        - (IN) Unit number.
   5805  *      group       - (IN) Multicast group ID.
   5806  *      port        - (IN) Physical port.
   5807  *      extender_port_id - (IN) Extender port ID.
   5808  *      encap_id    - (OUT) Encap ID.
   5809  * Returns:
   5810  *      BCM_E_XXX
   5811  * Notes:
   5812  */
   5813 int
   5814 bcm_esw_multicast_extender_encap_get(int unit, bcm_multicast_t group,
   5815         bcm_gport_t port, bcm_gport_t extender_port_id, bcm_if_t *encap_id)
   5816 {
   5817     MULTICAST_INIT_CHECK(unit);
   5818 
   5819     if (encap_id == NULL) {
   5820         return BCM_E_PARAM;
   5821     }
   5822 
   5823 #if defined(BCM_TRIUMPH3_SUPPORT) && defined(INCLUDE_L3)
   5824     if (soc_feature(unit, soc_feature_port_extension)) {
   5825         int vp;
   5826         ing_dvp_table_entry_t dvp;
   5827 
   5828         if (!BCM_GPORT_IS_EXTENDER_PORT(extender_port_id)) {
   5829             return BCM_E_PARAM;
   5830         }
   5831         vp = BCM_GPORT_EXTENDER_PORT_ID_GET(extender_port_id); 
   5832         if (vp >= soc_mem_index_count(unit, SOURCE_VPm)) {
   5833             return BCM_E_PARAM;
   5834         }
   5835         if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeExtender)) {
   5836             return BCM_E_PARAM;
   5837         }
   5838         BCM_IF_ERROR_RETURN
   5839             (READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp));
   5840 
   5841         /* Next-hop index is used for multicast replication */
   5842         *encap_id = (bcm_if_t) soc_ING_DVP_TABLEm_field32_get(unit, &dvp,
   5843                 NEXT_HOP_INDEXf);
   5844         *encap_id += BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   5845 
   5846         return BCM_E_NONE;
   5847     }
   5848 #endif /* BCM_TRIUMPH3_SUPPORT && INCLUDE_L3 */
   5849 
   5850     return BCM_E_UNAVAIL;
   5851 }
   5852 
   5853 /*
   5854  * Function:
   5855  *      bcm_multicast_mac_encap_get
   5856  * Purpose:
   5857  *      Get the Encap ID for MAC virtual port.
   5858  * Parameters:
   5859  *      unit        - (IN) Unit number.
   5860  *      group       - (IN) Multicast group ID.
   5861  *      port        - (IN) Physical port.
   5862  *      mac_port_id - (IN) MAC port ID.
   5863  *      encap_id    - (OUT) Encap ID.
   5864  * Returns:
   5865  *      BCM_E_XXX
   5866  * Notes:
   5867  */
   5868 int
   5869 bcm_esw_multicast_mac_encap_get(int unit, bcm_multicast_t group, bcm_gport_t port,
   5870                                 bcm_gport_t mac_port_id, bcm_if_t *encap_id)
   5871 {
   5872     MULTICAST_INIT_CHECK(unit);
   5873     
   5874     if (encap_id == NULL) {
   5875         return BCM_E_PARAM;
   5876     }
   5877 
   5878 #if defined(BCM_TRIDENT2_SUPPORT) && defined(INCLUDE_L3)
   5879     if (soc_feature(unit, soc_feature_mac_virtual_port)) {
   5880         int vp;
   5881         ing_dvp_table_entry_t dvp;
   5882 
   5883         if (!BCM_GPORT_IS_MAC_PORT(mac_port_id)) {
   5884             return BCM_E_PARAM;
   5885         }
   5886         vp = BCM_GPORT_MAC_PORT_ID_GET(mac_port_id); 
   5887         if (vp >= soc_mem_index_count(unit, SOURCE_VPm)) {
   5888             return BCM_E_PARAM;
   5889         }
   5890         BCM_IF_ERROR_RETURN(READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp));
   5891 
   5892         /* Next-hop index is used for multicast replication */
   5893         *encap_id = (bcm_if_t) soc_ING_DVP_TABLEm_field32_get(unit, &dvp,
   5894                 NEXT_HOP_INDEXf);
   5895         *encap_id += BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   5896 
   5897         return BCM_E_NONE;
   5898     }
   5899 #endif /* BCM_TRIDENT2_SUPPORT && INCLUDE_L3 */
   5900 
   5901     return BCM_E_UNAVAIL;
   5902 }
   5903 
   5904 /*
   5905  * Function:
   5906  *      bcm_multicast_egress_add
   5907  * Purpose:
   5908  *      Add a GPORT to the replication list
   5909  *      for the specified multicast index.
   5910  * Parameters:
   5911  *      unit      - (IN) Device Number
   5912  *      group     - (IN) Multicast group ID
   5913  *      port      - (IN) GPORT Identifier
   5914  *      encap_id  - (IN) Encap ID.
   5915  * Returns:
   5916  *      BCM_E_XXX
   5917  */
   5918 int
   5919 bcm_esw_multicast_egress_add(int unit, bcm_multicast_t group, 
   5920                              bcm_gport_t port, bcm_if_t encap_id)
   5921 {
   5922     int rv=BCM_E_NONE;
   5923 
   5924     MULTICAST_INIT_CHECK(unit);
   5925 
   5926    /* Check whether the given multicast group is available */
   5927     rv = bcm_esw_multicast_group_is_free(unit, group);
   5928     if (rv != BCM_E_EXISTS) {
   5929         if (BCM_SUCCESS(rv)) {
   5930             rv = BCM_E_NOT_FOUND;
   5931         }
   5932         return rv;
   5933     }
   5934 
   5935 #if defined(BCM_XGS3_SWITCH_SUPPORT) 
   5936     if (SOC_IS_XGS3_SWITCH(unit)) {
   5937         if (_BCM_MULTICAST_L2_OR_FABRIC(unit, group)) {
   5938             return _bcm_esw_multicast_l2_add(unit, group, port, encap_id);
   5939         } else {
   5940 #if defined(INCLUDE_L3)
   5941             /* If (1) the given group is an IPMC group, (2) the given port is
   5942              * a trunk gport, and (3) IPMC trunk resolution is disabled for the
   5943              * trunk group in hardware, then encap_id is added to only one
   5944              * member of the trunk group. The following procedure finds which
   5945              * trunk member the encap_id is mapped to.
   5946              */
   5947             bcm_gport_t mapped_port;
   5948             BCM_IF_ERROR_RETURN
   5949                 (_bcm_esw_multicast_egress_encap_id_to_trunk_member_map(unit,
   5950                     group, 1, &port, &encap_id, &mapped_port));
   5951             return _bcm_esw_multicast_l3_add(unit, group, mapped_port, encap_id);
   5952 #endif /* INCLUDE_L3 */
   5953         }
   5954     }
   5955 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   5956     return BCM_E_UNAVAIL;
   5957 }
   5958 
   5959 /*
   5960  * Function:
   5961  *      bcm_multicast_egress_delete
   5962  * Purpose:
   5963  *      Delete GPORT from the replication list
   5964  *      for the specified multicast index.
   5965  * Parameters:
   5966  *      unit      - (IN) Device Number
   5967  *      group     - (IN) Multicast group ID
   5968  *      port      - (IN) GPORT Identifier
   5969  *      encap_id  - (IN) Encap ID.
   5970  * Returns:
   5971  *      BCM_E_XXX
   5972  */
   5973 int
   5974 bcm_esw_multicast_egress_delete(int unit, bcm_multicast_t group, 
   5975                                 bcm_gport_t port, bcm_if_t encap_id)
   5976 {
   5977     int rv=BCM_E_NONE;
   5978 
   5979     MULTICAST_INIT_CHECK(unit);
   5980 
   5981     /* Check whether the given multicast group is available */
   5982     rv = bcm_esw_multicast_group_is_free(unit, group);
   5983     if (rv != BCM_E_EXISTS) {
   5984         if (BCM_SUCCESS(rv)) {
   5985             rv = BCM_E_NOT_FOUND;
   5986         }
   5987         return rv;
   5988     }
   5989 
   5990 #if defined(BCM_XGS3_SWITCH_SUPPORT) 
   5991     if (SOC_IS_XGS3_SWITCH(unit)) {
   5992         if (_BCM_MULTICAST_L2_OR_FABRIC(unit, group)) {
   5993             return _bcm_esw_multicast_l2_delete(unit, group, port, encap_id);
   5994         } else {
   5995 #if defined(INCLUDE_L3)
   5996             /* If (1) the given group is an IPMC group, (2) the given port is
   5997              * a trunk gport, and (3) IPMC trunk resolution is disabled for
   5998              * the trunk group in hardware, then encap_id resides on only one
   5999              * member of the trunk group. The following procedure finds which
   6000              * trunk member the encap_id resides on.
   6001              */
   6002             bcm_gport_t mapped_port;
   6003             BCM_IF_ERROR_RETURN
   6004                 (_bcm_esw_multicast_egress_mapped_trunk_member_find(unit,
   6005                     group, port, encap_id, &mapped_port));
   6006             return _bcm_esw_multicast_l3_delete(unit, group, mapped_port, encap_id);
   6007 #endif /* INCLUDE_L3 */
   6008         }
   6009     }
   6010 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   6011     return BCM_E_UNAVAIL;
   6012 }
   6013 
   6014 /*
   6015  * Function:
   6016  *      bcm_multicast_egress_delete_all
   6017  * Purpose:
   6018  *      Delete all replications for the specified multicast index.
   6019  * Parameters:
   6020  *      unit      - (IN) Device Number
   6021  *      group     - (IN) Multicast group ID
   6022  * Returns:
   6023  *      BCM_E_XXX
   6024  */
   6025 int
   6026 bcm_esw_multicast_egress_delete_all(int unit, bcm_multicast_t group)
   6027 { 
   6028     int rv=BCM_E_NONE;
   6029     MULTICAST_INIT_CHECK(unit);
   6030 
   6031     /* Check whether the given multicast group is available */
   6032     rv = bcm_esw_multicast_group_is_free(unit, group);
   6033     if (rv != BCM_E_EXISTS) {
   6034         if (BCM_SUCCESS(rv)) {
   6035             rv = BCM_E_NOT_FOUND;
   6036         }
   6037         return rv;
   6038     }
   6039 
   6040     rv = bcm_esw_multicast_egress_set(unit, group, 0, NULL, NULL);
   6041 #if defined(INCLUDE_L3) && defined(BCM_KATANA_SUPPORT)
   6042     if ((SOC_IS_SABER2(unit)|| SOC_IS_KATANAX(unit)) && BCM_SUCCESS(rv)) {
   6043         return _bcm_esw_multicast_egress_subscriber_delete_all(unit, group);
   6044     }
   6045 #endif
   6046     return rv;
   6047 }
   6048 /*  
   6049  * Function:
   6050  *      bcm_multicast_egress_set
   6051  * Purpose:
   6052  *      Assign the complete set of egress GPORTs in the
   6053  *      replication list for the specified multicast index.
   6054  * Parameters:
   6055  *      unit       - (IN) Device Number
   6056  *      group      - (IN) Multicast group ID
   6057  *      port_count - (IN) Number of ports in replication list
   6058  *      port_array - (IN) List of GPORT Identifiers
   6059  *      encap_id_array - (IN) List of encap identifiers
   6060  * Returns:
   6061  *      BCM_E_XXX
   6062  */     
   6063 int     
   6064 bcm_esw_multicast_egress_set(int unit, bcm_multicast_t group, int port_count,
   6065                              bcm_gport_t *port_array, bcm_if_t *encap_id_array)
   6066 {
   6067     int rv=BCM_E_NONE;
   6068 
   6069     MULTICAST_INIT_CHECK(unit);
   6070 
   6071     /* Check whether the given multicast group is available */
   6072     rv = bcm_esw_multicast_group_is_free(unit, group);
   6073     if (rv != BCM_E_EXISTS) {
   6074         if (BCM_SUCCESS(rv)) {
   6075             rv = BCM_E_NOT_FOUND;
   6076         }
   6077         return rv;
   6078     }
   6079 
   6080 #if defined(BCM_XGS3_SWITCH_SUPPORT) && defined(INCLUDE_L3)
   6081     if (SOC_IS_XGS3_SWITCH(unit)) {
   6082         /* If (1) the given group is an IPMC group, (2) the given port is a
   6083          * trunk gport, and (3) IPMC trunk resolution is disabled for the
   6084          * trunk group in hardware, then each encap_id is added to only one
   6085          * member in trunk group. The following procedure maps the encap_ids
   6086          * to trunk members.
   6087          */
   6088         int rv;
   6089         bcm_gport_t *mapped_port_array = NULL;
   6090         if (port_count > 0) {
   6091             mapped_port_array = sal_alloc(sizeof(bcm_gport_t) * port_count,
   6092                     "resolved port array");
   6093             if (NULL == mapped_port_array) {
   6094                 return BCM_E_MEMORY;
   6095             }
   6096             rv = _bcm_esw_multicast_egress_encap_id_to_trunk_member_map(unit,
   6097                     group, port_count, port_array, encap_id_array,
   6098                     mapped_port_array);
   6099             if (BCM_FAILURE(rv)) {
   6100                 sal_free(mapped_port_array);
   6101                 return rv;
   6102             }
   6103         }
   6104 
   6105         rv = _bcm_esw_multicast_egress_set(unit, group, port_count, 
   6106                 mapped_port_array, encap_id_array);
   6107 
   6108         if (mapped_port_array) {
   6109             sal_free(mapped_port_array);
   6110         }
   6111 
   6112         return rv;
   6113     }
   6114 #endif /* BCM_XGS3_SWITCH_SUPPORT && INCLUDE_L3 */
   6115     return BCM_E_UNAVAIL;
   6116 }   
   6117 
   6118 #if (defined(BCM_TRX_SUPPORT) || defined(BCM_XGS3_SWITCH_SUPPORT)) && defined(INCLUDE_L3)
   6119 /*
   6120  * Function:
   6121  *      _bcm_esw_multicast_egress_get
   6122  * Purpose:
   6123  *      Helper function to API 
   6124  * Parameters: 
   6125  *      unit           - (IN) Device Number
   6126  *      mc_index       - (IN) Multicast index
   6127  *      port_max       - (IN) Number of entries in "port_array"
   6128  *      port_array     - (OUT) List of ports
   6129  *      encap_id_array - (OUT) List of encap identifiers
   6130  *      port_count     - (OUT) Actual number of ports returned
   6131  * Returns:
   6132  *      BCM_E_XXX
   6133  * Notes:
   6134  *      If the input parameter port_max = 0, return in the output parameter
   6135  *      port_count the total number of ports/encapsulation IDs in the 
   6136  *      specified multicast group's replication list.
   6137  */
   6138 STATIC int     
   6139 _bcm_esw_multicast_egress_get(int unit, bcm_multicast_t group, int port_max,
   6140                               bcm_gport_t *port_array,
   6141                               bcm_if_t *encap_id_array, 
   6142                               int *port_count)
   6143 {
   6144 #if defined(BCM_XGS3_SWITCH_SUPPORT) 
   6145     if (SOC_IS_XGS3_SWITCH(unit)) {
   6146         if (_BCM_MULTICAST_L2_OR_FABRIC(unit, group)) {
   6147             return _bcm_esw_multicast_l2_get(unit, group, port_max, port_array, 
   6148                                              encap_id_array, port_count);
   6149         } else {
   6150 #if defined(INCLUDE_L3)
   6151             return _bcm_esw_multicast_l3_get(unit, group, port_max, port_array, 
   6152                                              encap_id_array, port_count);
   6153 #endif /* INCLUDE_L3 */
   6154         }
   6155     }
   6156 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   6157 
   6158     return BCM_E_UNAVAIL;
   6159 }
   6160 #endif
   6161 
   6162 /*
   6163  * Function:
   6164  *      bcm_multicast_egress_get
   6165  * Purpose:
   6166  *      Retrieve a set of egress multicast GPORTs in the
   6167  *      replication list for the specified multicast index.
   6168  * Parameters: 
   6169  *      unit           - (IN) Device Number
   6170  *      mc_index       - (IN) Multicast index
   6171  *      port_max       - (IN) Number of entries in "port_array"
   6172  *      port_array     - (OUT) List of ports
   6173  *      encap_id_array - (OUT) List of encap identifiers
   6174  *      port_count     - (OUT) Actual number of ports returned
   6175  * Returns:
   6176  *      BCM_E_XXX
   6177  * Notes:
   6178  *      If the input parameter port_max = 0, return in the output parameter
   6179  *      port_count the total number of ports/encapsulation IDs in the 
   6180  *      specified multicast group's replication list.
   6181  */
   6182 int     
   6183 bcm_esw_multicast_egress_get(int unit, bcm_multicast_t group, int port_max,
   6184                              bcm_gport_t *port_array,
   6185                              bcm_if_t *encap_id_array, 
   6186                              int *port_count)
   6187 {
   6188     int rv = BCM_E_UNAVAIL;
   6189 #if (defined(BCM_TRX_SUPPORT) || defined(BCM_XGS3_SWITCH_SUPPORT)) && defined(INCLUDE_L3)
   6190     int i;
   6191     bcm_module_t mod_out, my_modid;
   6192     bcm_port_t port_in, port_out;
   6193 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
   6194     int is_local_subport = FALSE;
   6195 #endif
   6196 #if defined(BCM_TOMAHAWK_SUPPORT) || defined (BCM_TRIDENT2PLUS_SUPPORT)
   6197     int r_rv;
   6198     int tgid;
   6199     bcm_module_t  local_modid = 0;
   6200     int trunk_local_ports = 0;
   6201     bcm_trunk_info_t tinfo;
   6202     #if defined(BCM_ESW_SUPPORT) && (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS)
   6203         bcm_port_t      local_trunk_member_ports[SOC_MAX_NUM_PP_PORTS] = {0};
   6204         int             max_num_ports = SOC_MAX_NUM_PP_PORTS;
   6205     #else
   6206         bcm_port_t      local_trunk_member_ports[SOC_MAX_NUM_PORTS] = {0};
   6207         int             max_num_ports = SOC_MAX_NUM_PORTS;
   6208 #endif    
   6209 #endif
   6210 
   6211     MULTICAST_INIT_CHECK(unit);
   6212 
   6213     /* Check whether the given multicast group is available */
   6214     rv = bcm_esw_multicast_group_is_free(unit, group);
   6215     if (rv != BCM_E_EXISTS) {
   6216         if (BCM_SUCCESS(rv)) {
   6217             rv = BCM_E_NOT_FOUND;
   6218         }
   6219         return rv;
   6220     }
   6221 
   6222     /* port_array and encap_id_array are allowed to be NULL */
   6223     if ((NULL == port_count) || (port_max < 0) ){
   6224         return BCM_E_PARAM;
   6225     }
   6226 
   6227     /* If port_max = 0, port_array and encap_id_array must be NULL */
   6228     if (port_max == 0) {
   6229         if ((NULL != port_array) || (NULL != encap_id_array)) {
   6230             return BCM_E_PARAM;
   6231         }
   6232     }
   6233 
   6234     BCM_IF_ERROR_RETURN
   6235         (_bcm_esw_multicast_egress_get(unit, group, port_max, port_array,
   6236                                       encap_id_array, port_count));
   6237 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_TRIDENT2PLUS_SUPPORT)
   6238     if (!SOC_IS_TOMAHAWK3(unit)) {
   6239         if ((BCM_MC_PER_TRUNK_REPL_MODE(unit)) && (NULL != port_array)) {
   6240             BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get (unit, &local_modid));
   6241             r_rv = bcm_esw_trunk_find(unit, local_modid, *port_array, &tgid);
   6242             if ((BCM_E_NONE == r_rv) && (BCM_TRUNK_INVALID != tgid)) {
   6243                 BCM_IF_ERROR_RETURN
   6244                     (bcm_esw_trunk_get(unit, tgid, &tinfo, 0, NULL, NULL));
   6245                 if (!(tinfo.flags & BCM_TRUNK_FLAG_IPMC_CLEAVE)) {
   6246                     BCM_IF_ERROR_RETURN(
   6247                     _bcm_esw_trunk_local_members_get(unit, tgid,
   6248                                                      max_num_ports,
   6249                                                      local_trunk_member_ports,
   6250                                                      &trunk_local_ports));
   6251                     for (i = 0; i < trunk_local_ports; i++) {
   6252                         BCM_IF_ERROR_RETURN
   6253                         (bcm_esw_port_gport_get(unit, local_trunk_member_ports[i],
   6254                                                 (port_array + i)));
   6255                         encap_id_array[i] = encap_id_array[0];
   6256                     }
   6257                 }
   6258             }
   6259         }
   6260     } /* if (!SOC_IS_TOMAHAWK3(unit)) */
   6261 #endif /* BCM_TOMAHAWK_SUPPORT || BCM_TRIDENT2PLUS_SUPPORT */
   6262     if (NULL != port_array) {
   6263         /* Convert GPORT_LOCAL format to GPORT_MODPORT format */
   6264         if (bcm_esw_stk_my_modid_get(unit, &my_modid) < 0) {
   6265             return BCM_E_INTERNAL;
   6266         }
   6267         for (i = 0; i < *port_count; i++) {
   6268 
   6269 #if defined(BCM_HGPROXY_COE_SUPPORT)
   6270 			if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   6271 				BCM_GPORT_IS_SET(port_array[i]) &&
   6272 				_BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port_array[i])) {
   6273 
   6274 				if(_bcm_xgs5_subport_coe_gport_local(unit, port_array[i])) {
   6275 					is_local_subport = TRUE;
   6276 				}
   6277 			} else
   6278 #endif
   6279 #if defined(BCM_KATANA2_SUPPORT)
   6280 			/* For LinkPHY/SubTag subport return in subport_gport format*/
   6281 			if (soc_feature(unit, soc_feature_linkphy_coe) ||
   6282 				soc_feature(unit, soc_feature_subtag_coe)) {
   6283 				is_local_subport = FALSE;
   6284 				if (BCM_GPORT_IS_SET(port_array[i]) &&
   6285 					_BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit,
   6286 					port_array[i])) {
   6287 					is_local_subport = TRUE;
   6288 				}
   6289 			}
   6290 #endif
   6291 
   6292 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
   6293             if (is_local_subport) {
   6294 
   6295             } else
   6296 #endif
   6297             {
   6298                 BCM_IF_ERROR_RETURN(
   6299                     bcm_esw_port_local_get(unit, port_array[i], &port_in));
   6300         
   6301                 BCM_IF_ERROR_RETURN
   6302                     (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
   6303                                             my_modid, port_in, &mod_out, &port_out));
   6304                 BCM_GPORT_MODPORT_SET(port_array[i], mod_out, port_out);
   6305             }
   6306         }
   6307     }
   6308 
   6309     rv = BCM_E_NONE;
   6310 #endif
   6311 
   6312     return rv;
   6313 }   
   6314 
   6315 
   6316 
   6317 int
   6318 bcm_esw_multicast_repl_set(int unit, int mc_index, bcm_port_t port,
   6319                       bcm_vlan_vector_t vlan_vec)
   6320 {
   6321     return BCM_E_UNAVAIL;
   6322 }
   6323 
   6324 int
   6325 bcm_esw_multicast_repl_get(int unit, int index, bcm_port_t port,
   6326                       bcm_vlan_vector_t vlan_vec)
   6327 {
   6328     return BCM_E_UNAVAIL;
   6329 }
   6330 
   6331 /*
   6332  * Function:
   6333  *      bcm_esw_multicast_group_get
   6334  * Purpose:
   6335  *      Retrieve the flags associated with a multicast group.
   6336  * Parameters:
   6337  *      unit - (IN) Unit number.
   6338  *      group - (IN) Multicast group ID
   6339  *      flags - (OUT) BCM_MULTICAST_*
   6340  * Returns:
   6341  *      BCM_E_xxx
   6342  * Notes:
   6343  */
   6344 int 
   6345 bcm_esw_multicast_group_get(int unit, bcm_multicast_t group, uint32 *flags)
   6346 {
   6347     MULTICAST_INIT_CHECK(unit);
   6348 
   6349 #ifdef BCM_XGS3_FABRIC_SUPPORT
   6350     if (SOC_IS_XGS3_FABRIC(unit)) {
   6351         return _bcm_esw_fabric_multicast_group_get(unit, group, flags);
   6352     }
   6353 #endif	/* BCM_XGS3_FABRIC_SUPPORT */
   6354 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3)
   6355     if (SOC_IS_TRX(unit)) {
   6356         return bcm_trx_multicast_group_get(unit, group, flags);
   6357     }
   6358 #endif /* BCM_TRX_SUPPORT && INCLUDE_L3 */
   6359 #if defined(BCM_XGS3_SWITCH_SUPPORT) && defined(INCLUDE_L3)
   6360     if (SOC_IS_XGS3_SWITCH(unit)) {
   6361         return bcm_xgs3_multicast_group_get(unit, group, flags);
   6362     }
   6363 #endif /* BCM_XGS3_SWITCH_SUPPORT && INCLUDE_L3 */
   6364     return BCM_E_UNAVAIL;
   6365 }
   6366 
   6367 /*
   6368  * Function:
   6369  *      bcm_esw_multicast_group_is_free
   6370  * Purpose:
   6371  *      Request if the given multicast group is available on the
   6372  *      device
   6373  * Parameters:
   6374  *      unit - (IN) Unit number.
   6375  *      group - (IN) Multicast group ID.
   6376  * Returns:
   6377  *      BCM_E_NONE - multicast group is valid and available on the device
   6378  *      BCM_E_EXISTS - multicast group is valid but already in use
   6379  *                     on this device
   6380  *      BCM_E_PARAM - multicast group is not valid on this device 
   6381  * Notes:
   6382  */
   6383 int 
   6384 bcm_esw_multicast_group_is_free(int unit, bcm_multicast_t group)
   6385 {
   6386 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   6387     int             mc_index;
   6388     int             rv = BCM_E_PARAM;
   6389     int             is_set;
   6390 
   6391     mc_index = _BCM_MULTICAST_ID_GET(group);
   6392 
   6393 #ifdef BCM_XGS3_FABRIC_SUPPORT
   6394     if (SOC_IS_XGS3_FABRIC(unit)) {
   6395         rv = _bcm_esw_fabric_multicast_param_check(unit, group, &mc_index);
   6396         /* Remap return codes */
   6397         if (BCM_E_NOT_FOUND == rv) {
   6398             /* Multicast group is available, return without error */
   6399             rv = BCM_E_NONE;
   6400         } else if (BCM_E_NONE == rv) {
   6401             /* Multicast group is already configured */
   6402             rv = BCM_E_EXISTS;
   6403         }
   6404     } else 
   6405 #endif	/* BCM_XGS3_FABRIC_SUPPORT */
   6406     if (_BCM_MULTICAST_IS_L2(group)) {
   6407         rv = _bcm_xgs3_l2mc_index_is_set(unit, mc_index, &is_set);
   6408         if (BCM_SUCCESS(rv)) {
   6409             if (is_set) {
   6410                 rv = BCM_E_EXISTS;
   6411             }
   6412         }
   6413 #if defined(INCLUDE_L3)
   6414     } else if (_BCM_MULTICAST_IS_SET(group)) {
   6415         uint32 flags;
   6416         uint8 group_type;
   6417 
   6418         group_type = _BCM_MULTICAST_TYPE_GET(group);
   6419         flags = _bcm_esw_multicast_group_type_to_flags(group_type);
   6420         /* Check if this group type is supported on this device. */
   6421         BCM_IF_ERROR_RETURN(_bcm_esw_multicast_type_validate(unit, flags));
   6422 
   6423         rv = bcm_xgs3_ipmc_id_is_set(unit, mc_index, &is_set);
   6424         if (BCM_SUCCESS(rv)) {
   6425             if (is_set) {
   6426                 rv = BCM_E_EXISTS;
   6427             }
   6428         }
   6429 #endif /* INCLUDE_L3 */
   6430     }
   6431 
   6432     return rv; 
   6433 #else
   6434     return BCM_E_UNAVAIL;
   6435 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   6436 }
   6437 
   6438 /*
   6439  * Function:
   6440  *      bcm_esw_multicast_group_free_range_get
   6441  * Purpose:
   6442  *      Retrieve the minimum and maximum unallocated multicast groups
   6443  *      for a given multicast type.
   6444  * Parameters:
   6445  *      unit - (IN) Unit number.
   6446  *      type_flag - (IN) One of BCM_MULTICAST_TYPE_*.
   6447  *      group_min - (OUT) Minimum available multicast group of specified type.
   6448  *      group_max - (OUT) Maximum available multicast group of specified type.
   6449  * Returns:
   6450  *      BCM_E_xxx
   6451  * Notes:
   6452  */
   6453 int 
   6454 bcm_esw_multicast_group_free_range_get(int unit, uint32 type_flag, 
   6455                                        bcm_multicast_t *group_min,
   6456                                        bcm_multicast_t *group_max)
   6457 {
   6458 #if defined(BCM_XGS3_SWITCH_SUPPORT)
   6459     bcm_multicast_t dev_min, dev_max, group, free_min, free_max;
   6460     int             index_min, index_max, group_type, min_group_index;
   6461     int             rv = BCM_E_PARAM;
   6462     uint32          type;
   6463 
   6464     type = type_flag & BCM_MULTICAST_TYPE_MASK;
   6465     if (1 != _shr_popcount(type)) {
   6466         return BCM_E_PARAM;
   6467     }
   6468 
   6469 #ifdef BCM_XGS3_FABRIC_SUPPORT
   6470     if (SOC_IS_XGS3_FABRIC(unit)) {
   6471         if (type_flag == BCM_MULTICAST_TYPE_L2) {
   6472             index_min = BCM_FABRIC_MCAST_BASE(unit);
   6473             index_max =  BCM_FABRIC_MCAST_MAX(unit);
   6474             min_group_index = 1;
   6475         } else {
   6476             index_min = BCM_FABRIC_IPMC_BASE(unit);
   6477             index_max = BCM_FABRIC_IPMC_MAX(unit);
   6478             min_group_index = 0;
   6479         }
   6480     } else 
   6481 #endif	/* BCM_XGS3_FABRIC_SUPPORT */
   6482     if (type_flag == BCM_MULTICAST_TYPE_L2) {
   6483         index_min = soc_mem_index_min(unit, L2MCm);
   6484         index_max = soc_mem_index_max(unit, L2MCm);
   6485         min_group_index = 1;
   6486     } else {
   6487         index_min = soc_mem_index_min(unit, L3_IPMCm);
   6488         index_max = soc_mem_index_max(unit, L3_IPMCm);
   6489         min_group_index = 0;
   6490     }
   6491 
   6492     group_type = _bcm_esw_multicast_flags_to_group_type(type_flag);
   6493     _BCM_MULTICAST_GROUP_SET(dev_min, group_type, min_group_index);
   6494     _BCM_MULTICAST_GROUP_SET(dev_max, group_type, index_max - index_min);
   6495 
   6496 
   6497     free_min = free_max = 0; /* Invalid multicast group */
   6498     for (group = dev_min; group <= dev_max; group++) {
   6499         rv = bcm_esw_multicast_group_is_free(unit, group);
   6500         if (BCM_SUCCESS(rv)) {
   6501             if (0 == free_min) {
   6502                 free_min = group;
   6503             }
   6504             free_max = group;
   6505         } else if (BCM_E_EXISTS == rv) {
   6506             /* Nothing to do but clear the error */
   6507             rv = BCM_E_NONE;
   6508         } else {
   6509             /* Real error, return */
   6510             break;
   6511         }
   6512     }
   6513 
   6514     if (BCM_SUCCESS(rv)) {
   6515         if (0 == free_min) {
   6516             /* No available groups of this type */
   6517             return BCM_E_NOT_FOUND;
   6518         } else {
   6519             /* Copy the results */
   6520             *group_min = free_min;
   6521             *group_max = free_max;
   6522         }
   6523     }
   6524 
   6525     return rv; 
   6526 #else
   6527     return BCM_E_UNAVAIL;
   6528 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   6529 }
   6530 
   6531 /*
   6532  * Function:
   6533  *      bcm_esw_multicast_group_traverse
   6534  * Purpose:
   6535  *      Iterate over the defined multicast groups of the type
   6536  *      specified in 'flags'.  If all types are desired, use
   6537  *      MULTICAST_TYPE_MASK.
   6538  * Parameters:
   6539  *      unit - (IN) Unit number.
   6540  *      trav_fn - (IN) Callback function.
   6541  *      flags - (IN) BCM_MULTICAST_*
   6542  *      user_data - (IN) User data to be passed to callback function.
   6543  * Returns:
   6544  *      BCM_E_xxx
   6545  * Notes:
   6546  */
   6547 int 
   6548 bcm_esw_multicast_group_traverse(int unit,
   6549                                  bcm_multicast_group_traverse_cb_t trav_fn, 
   6550                                  uint32 flags, void *user_data)
   6551 {
   6552     MULTICAST_INIT_CHECK(unit);
   6553 
   6554 #ifdef BCM_XGS3_FABRIC_SUPPORT
   6555     if (SOC_IS_XGS3_FABRIC(unit)) {
   6556         return _bcm_esw_fabric_multicast_group_traverse(unit, trav_fn,
   6557                                                         flags, user_data);
   6558     }
   6559 #endif	/* BCM_XGS3_FABRIC_SUPPORT */
   6560 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3)
   6561     if (SOC_IS_TRX(unit)) {
   6562         return bcm_trx_multicast_group_traverse(unit, trav_fn,
   6563                                                 flags, user_data);
   6564     }
   6565 #endif /* BCM_TRX_SUPPORT && INCLUDE_L3 */
   6566 #if defined(BCM_XGS3_SWITCH_SUPPORT) && defined(INCLUDE_L3)
   6567     if (SOC_IS_XGS3_SWITCH(unit)) {
   6568         return bcm_xgs3_multicast_group_traverse(unit, trav_fn,
   6569                                                  flags, user_data);
   6570     }
   6571 #endif /* BCM_XGS3_SWITCH_SUPPORT && INCLUDE_L3 */
   6572     return BCM_E_UNAVAIL;
   6573 }
   6574 
   6575 #if defined(INCLUDE_L3)
   6576 /*
   6577  * Function:
   6578  *      _bcm_esw_multicast_remap_group_set
   6579  * Purpose:
   6580  *      Set an IPMC remapping.
   6581  * Parameters:
   6582  *      unit      - (IN) Unit number.
   6583  *      from      - (IN) Multicast group ID to map from
   6584  *      to        - (IN) Multicast group ID to map to
   6585  * Returns:
   6586  *      BCM_E_XXX
   6587  * Notes:
   6588  */
   6589 STATIC int
   6590 _bcm_esw_multicast_remap_group_set(int unit, bcm_multicast_t from, int to)
   6591 {
   6592     int rv = BCM_E_UNAVAIL;
   6593 
   6594 #if defined(BCM_TRIUMPH2_SUPPORT)
   6595     if (soc_feature(unit, soc_feature_ipmc_remap)) {
   6596 
   6597         rv = _bcm_esw_multicast_l3_group_check(unit, from, NULL);
   6598         BCM_IF_ERROR_RETURN(rv);
   6599 
   6600         rv = _bcm_esw_multicast_l3_group_check(unit, to, NULL);
   6601         BCM_IF_ERROR_RETURN(rv);
   6602 
   6603         rv = bcm_tr2_ipmc_remap_set(unit, from, to);
   6604     }
   6605 #endif
   6606 
   6607     return rv;
   6608 }
   6609 
   6610 
   6611 /*
   6612  * Function:
   6613  *      _bcm_esw_multicast_remap_group_get
   6614  * Purpose:
   6615  *      Set an IPMC remapping.
   6616  * Parameters:
   6617  *      unit      - (IN) Unit number.
   6618  *      from      - (IN) Multicast group ID being mapped
   6619  *      to        - (OUT) Pointer to Multicast group ID being mapped to,
   6620  *                        using the same group type as 'from'.
   6621  * Returns:
   6622  *      BCM_E_XXX
   6623  * Notes:
   6624  */
   6625 STATIC int
   6626 _bcm_esw_multicast_remap_group_get(int unit, bcm_multicast_t from, int *to)
   6627 {
   6628     int rv = BCM_E_UNAVAIL;
   6629 
   6630 #if defined(BCM_TRIUMPH2_SUPPORT)
   6631     if (soc_feature(unit, soc_feature_ipmc_remap)) {
   6632         
   6633         rv = _bcm_esw_multicast_l3_group_check(unit, from, NULL);
   6634         if (BCM_SUCCESS(rv)) {
   6635             rv = bcm_tr2_ipmc_remap_get(unit, from, to);
   6636         }
   6637     }
   6638 #endif
   6639 
   6640     return rv;
   6641 }
   6642 #endif
   6643 
   6644 /*
   6645  * Function:
   6646  *      bcm_multicast_control_set
   6647  * Purpose:
   6648  *      Set multicast group control.
   6649  * Parameters:
   6650  *      unit      - (IN) Unit number.
   6651  *      group     - (IN) Multicast group ID.
   6652  *      type      - (IN) Multicast group control type.
   6653  *      arg       - (IN) Multicast group control argument.
   6654  * Returns:
   6655  *      BCM_E_XXX
   6656  */
   6657 int
   6658 bcm_esw_multicast_control_set(int unit,
   6659         bcm_multicast_t group,
   6660         bcm_multicast_control_t type,
   6661         int arg)
   6662 {
   6663     int rv = BCM_E_UNAVAIL;
   6664 #if defined(BCM_XGS3_SWITCH_SUPPORT) 
   6665 #if defined(INCLUDE_L3)
   6666     int index;
   6667     mtu_values_entry_t l3_mtu_values_entry;
   6668 #endif
   6669 
   6670     MULTICAST_INIT_CHECK(unit);
   6671 
   6672     if (!SOC_IS_XGS3_SWITCH(unit)) {
   6673         return BCM_E_UNAVAIL;
   6674     }
   6675 
   6676 #if defined(INCLUDE_L3)
   6677     rv = (_bcm_esw_multicast_l3_group_check(unit, group, NULL));
   6678 #endif
   6679 
   6680     if (!_BCM_MULTICAST_IS_L2(group) && BCM_FAILURE(rv)) {
   6681         return rv;
   6682     }
   6683     
   6684     switch (type) {
   6685         case bcmMulticastControlMtu:
   6686             if (_BCM_MULTICAST_IS_L2(group)) {
   6687                 /* Not applicable to multicast types that uses a L2MC index.
   6688                  * Only applicable to multicast types that uses a L3MC index.
   6689                  */
   6690                 return BCM_E_PARAM;
   6691             }
   6692             if (SOC_MEM_IS_VALID(unit, L3_MTU_VALUESm)) {
   6693 #if defined(INCLUDE_L3) 
   6694                 index = _BCM_MULTICAST_MTU_TABLE_OFFSET(unit) +
   6695                         _BCM_MULTICAST_ID_GET(group);
   6696                 if (!soc_mem_index_valid(unit, L3_MTU_VALUESm, index)) {
   6697                     return BCM_E_PARAM;
   6698                 }
   6699 
   6700                 SOC_IF_ERROR_RETURN(READ_L3_MTU_VALUESm(unit, MEM_BLOCK_ANY,
   6701                             index, &l3_mtu_values_entry));
   6702 
   6703                 /* coverity[zero_return : FALSE] */
   6704                 /* coverity[large_shift : FALSE] */
   6705                 if(!SOC_MEM_FIELD32_VALUE_FIT(unit, L3_MTU_VALUESm,
   6706                             MTU_SIZEf, arg)) {
   6707                     return BCM_E_PARAM;
   6708                 }
   6709                 soc_L3_MTU_VALUESm_field32_set(unit, &l3_mtu_values_entry,
   6710                         MTU_SIZEf, arg);
   6711 
   6712                 rv = WRITE_L3_MTU_VALUESm(unit, MEM_BLOCK_ALL, 
   6713                                           index, &l3_mtu_values_entry);
   6714 #endif /* INCLUDE_L3 */
   6715             } else if (SOC_MEM_FIELD_VALID(unit, L3_IPMCm, IPMC_MTU_INDEXf) && 
   6716                        SOC_REG_IS_VALID(unit, IPMC_L3_MTUr)) {
   6717 #if defined(BCM_FIREBOLT_SUPPORT) || defined(BCM_SCORPION_SUPPORT)
   6718 #if defined(INCLUDE_L3) 
   6719                 uint64 rval64, *rval64s[1];
   6720                 uint32 pindex, entry[SOC_MAX_MEM_WORDS];
   6721 
   6722                 rval64s[0] = &rval64;
   6723                 COMPILER_64_ZERO(rval64);
   6724                 COMPILER_64_SET(rval64, 0, arg);
   6725                 index = _BCM_MULTICAST_ID_GET(group);
   6726                 if (!soc_mem_index_valid(unit, L3_IPMCm, index)) {
   6727                     return BCM_E_PARAM;
   6728                 }
   6729                 BCM_IF_ERROR_RETURN
   6730                     (soc_profile_reg_add(unit, _bcm_mtu_profile[unit], rval64s,
   6731                                          1, &pindex));
   6732                 BCM_IF_ERROR_RETURN
   6733                     (soc_mem_read(unit, L3_IPMCm,
   6734                                   MEM_BLOCK_ANY, index, &entry));
   6735                 soc_mem_field32_set(unit, L3_IPMCm, &entry,
   6736                                     IPMC_MTU_INDEXf, pindex);
   6737                 BCM_IF_ERROR_RETURN
   6738                     (soc_mem_write(unit, L3_IPMCm, MEM_BLOCK_ANY, index, 
   6739                                    &entry));
   6740 #endif /* INCLUDE_L3 */
   6741 #endif
   6742             } else if (soc_feature(unit, soc_feature_l3_nh_attr_table)) {
   6743 #if defined(BCM_TRIUMPH3_SUPPORT)
   6744 #if defined(INCLUDE_L3) 
   6745                 int mtu_profile_index;
   6746                 ing_l3_next_hop_attribute_1_index_entry_t mtu_idx_value_buf;
   6747                 void *null_idx_entry =
   6748                     soc_mem_entry_null(unit, ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm);
   6749 
   6750                 index = _BCM_TR3_MULTICAST_MTU_TABLE_OFFSET(unit) +
   6751                         _BCM_MULTICAST_ID_GET(group);
   6752 
   6753                 if (!soc_mem_index_valid(unit, 
   6754                             ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm, index)) {
   6755                     return BCM_E_PARAM;
   6756                 }
   6757 
   6758                 /* coverity[zero_return : FALSE] */
   6759                 /* coverity[large_shift : FALSE] */
   6760                 if (!SOC_MEM_FIELD32_VALUE_FIT(unit, 
   6761                             ING_L3_NEXT_HOP_ATTRIBUTE_1m,
   6762                             MTU_SIZEf, arg)) {
   6763                     return (BCM_E_PARAM);
   6764                 }
   6765 
   6766                 BCM_IF_ERROR_RETURN(
   6767                         _bcm_tr3_mtu_profile_index_get(unit, arg,
   6768                             (uint32 *)&mtu_profile_index));
   6769 
   6770                 sal_memcpy(&mtu_idx_value_buf, null_idx_entry,
   6771                         sizeof(ing_l3_next_hop_attribute_1_index_entry_t));
   6772                 soc_mem_field32_set(unit, ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm,
   6773                         &mtu_idx_value_buf, INDEXf, mtu_profile_index);
   6774 
   6775                 rv = WRITE_ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm(unit, MEM_BLOCK_ALL,
   6776                         index, &mtu_idx_value_buf);
   6777 
   6778 #endif /* INCLUDE_L3 */
   6779 #endif /* BCM_TRIUMPH3_SUPPORT */
   6780             } else {
   6781                 return BCM_E_UNAVAIL;
   6782             }
   6783             break;
   6784 
   6785         case bcmMulticastVpTrunkResolve:
   6786             if (_BCM_MULTICAST_IS_L2(group)) {
   6787                 /* Not applicable to multicast types that uses a L2MC index. */
   6788                 return BCM_E_PARAM;
   6789             }
   6790 #if defined(BCM_TRIDENT2_SUPPORT) && defined(INCLUDE_L3)
   6791             if (soc_feature(unit, soc_feature_vp_lag)) {
   6792                 egr_ipmc_entry_t egr_ipmc_entry;
   6793 
   6794                 index = _BCM_MULTICAST_ID_GET(group);
   6795                 BCM_IF_ERROR_RETURN(READ_EGR_IPMCm(unit, MEM_BLOCK_ANY, index,
   6796                             &egr_ipmc_entry));
   6797                 soc_EGR_IPMCm_field32_set(unit, &egr_ipmc_entry,
   6798                         ENABLE_VPLAG_RESOLUTIONf, arg ? TRUE : FALSE);
   6799                 BCM_IF_ERROR_RETURN(WRITE_EGR_IPMCm(unit, MEM_BLOCK_ALL, index,
   6800                             &egr_ipmc_entry));
   6801             } else
   6802 #endif /* BCM_TRIDENT2_SUPPORT && INCLUDE_L3 */
   6803             {
   6804                 return BCM_E_PARAM;
   6805             }
   6806             break;
   6807 
   6808 #if defined(INCLUDE_L3)
   6809         case bcmMulticastRemapGroup:
   6810             rv = _bcm_esw_multicast_remap_group_set(unit, group, arg);
   6811             break;
   6812 #endif
   6813 
   6814         default:
   6815             return BCM_E_PARAM;
   6816     }
   6817 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   6818     return rv;
   6819 }
   6820 
   6821 /*
   6822  * Function:
   6823  *      bcm_multicast_control_get
   6824  * Purpose:
   6825  *      Get multicast group control.
   6826  * Parameters:
   6827  *      unit      - (IN) Unit number.
   6828  *      group     - (IN) Multicast group ID.
   6829  *      type      - (IN) Multicast group control type.
   6830  *      arg       - (OUT) Multicast group control argument.
   6831  * Returns:
   6832  *      BCM_E_XXX
   6833  */
   6834 int
   6835 bcm_esw_multicast_control_get(int unit,
   6836         bcm_multicast_t group,
   6837         bcm_multicast_control_t type,
   6838         int *arg)
   6839 {
   6840     int rv = BCM_E_UNAVAIL;
   6841     
   6842 
   6843 #if defined(BCM_XGS3_SWITCH_SUPPORT) 
   6844 #if defined(INCLUDE_L3)
   6845     mtu_values_entry_t l3_mtu_values_entry;
   6846     int index;
   6847 #endif
   6848 
   6849     MULTICAST_INIT_CHECK(unit);
   6850 
   6851     if (!SOC_IS_XGS3_SWITCH(unit)) {
   6852         return BCM_E_UNAVAIL;
   6853     }
   6854 
   6855 #if defined(INCLUDE_L3)
   6856     rv = (_bcm_esw_multicast_l3_group_check(unit, group, NULL));
   6857 #endif
   6858 
   6859     if (!_BCM_MULTICAST_IS_L2(group) && BCM_FAILURE(rv)) {
   6860         return rv;
   6861     }
   6862 
   6863     switch (type) {
   6864         case bcmMulticastControlMtu:
   6865             if (_BCM_MULTICAST_IS_L2(group)) {
   6866                 /* Not applicable to multicast types that uses a L2MC index.
   6867                  * Only applicable to multicast types that uses a L3MC index.
   6868                  */
   6869                 return BCM_E_PARAM;
   6870             }
   6871 
   6872             if (SOC_MEM_IS_VALID(unit, L3_MTU_VALUESm)) {
   6873 #if defined(INCLUDE_L3) 
   6874                 index = _BCM_MULTICAST_MTU_TABLE_OFFSET(unit) +
   6875                         _BCM_MULTICAST_ID_GET(group);
   6876                 if (!soc_mem_index_valid(unit, L3_MTU_VALUESm, index)) {
   6877                     return BCM_E_PARAM;
   6878                 }
   6879 
   6880                 SOC_IF_ERROR_RETURN(READ_L3_MTU_VALUESm(unit, MEM_BLOCK_ANY,
   6881                             index, &l3_mtu_values_entry));
   6882                 *arg = soc_L3_MTU_VALUESm_field32_get(unit,
   6883                         &l3_mtu_values_entry, MTU_SIZEf);
   6884                 /* if no error assume success */
   6885                 rv = BCM_E_NONE;
   6886 #endif /* INCLUDE_L3 */
   6887             } else if (SOC_MEM_FIELD_VALID(unit, L3_IPMCm, IPMC_MTU_INDEXf) && 
   6888                        SOC_REG_IS_VALID(unit, IPMC_L3_MTUr)) {
   6889 #if defined(BCM_FIREBOLT_SUPPORT) || defined(BCM_SCORPION_SUPPORT)
   6890 #if defined(INCLUDE_L3) 
   6891                 uint64 rval64, *rval64s[1];
   6892                 uint32 pindex, entry[SOC_MAX_MEM_WORDS];
   6893 
   6894                 rval64s[0] = &rval64;
   6895                 index = _BCM_MULTICAST_ID_GET(group);
   6896                 if (!soc_mem_index_valid(unit, L3_IPMCm, index)) {
   6897                     return BCM_E_PARAM;
   6898                 }
   6899                 BCM_IF_ERROR_RETURN
   6900                     (soc_mem_read(unit, L3_IPMCm,
   6901                                   MEM_BLOCK_ANY, index, &entry));
   6902                 pindex = soc_mem_field32_get(unit, L3_IPMCm, &entry,
   6903                                              IPMC_MTU_INDEXf);
   6904                 BCM_IF_ERROR_RETURN
   6905                     (soc_profile_reg_get(unit, _bcm_mtu_profile[unit], pindex,
   6906                                          1, rval64s));
   6907                 *arg = COMPILER_64_LO(rval64);
   6908 #endif /* INCLUDE_L3 */
   6909 #endif
   6910             } else if (soc_feature(unit, soc_feature_l3_nh_attr_table)) {
   6911 #if defined(BCM_TRIUMPH3_SUPPORT)
   6912 #if defined(INCLUDE_L3) 
   6913 
   6914                 /* Buffer for mtu idx */
   6915                 ing_l3_next_hop_attribute_1_index_entry_t mtu_idx_value_buf;
   6916                 /* Buffer for mtu profile table entry */
   6917                 ing_l3_next_hop_attribute_1_entry_t mtu_value_buf;
   6918                 int mtu_profile_index;
   6919 
   6920                 index = _BCM_TR3_MULTICAST_MTU_TABLE_OFFSET(unit) +
   6921                         _BCM_MULTICAST_ID_GET(group);
   6922 
   6923                 if (!soc_mem_index_valid(unit, 
   6924                             ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm, index)) {
   6925                     return BCM_E_PARAM;
   6926                 }
   6927 
   6928                 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit,
   6929                             ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm,
   6930                             index,
   6931                             (uint32 *)&mtu_idx_value_buf));
   6932 
   6933                 mtu_profile_index =
   6934                     soc_mem_field32_get(unit, ING_L3_NEXT_HOP_ATTRIBUTE_1_INDEXm,
   6935                             (uint32 *)&mtu_idx_value_buf, INDEXf);
   6936 
   6937                 BCM_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, 
   6938                             ING_L3_NEXT_HOP_ATTRIBUTE_1m,
   6939                             mtu_profile_index, (uint32 *)&mtu_value_buf));
   6940                 *arg = 
   6941                     soc_mem_field32_get(unit, ING_L3_NEXT_HOP_ATTRIBUTE_1m,
   6942                             (uint32 *)&mtu_value_buf, MTU_SIZEf);
   6943 
   6944                 /* if no error assume success */
   6945                 rv = BCM_E_NONE;
   6946 #endif /* INCLUDE_L3 */
   6947 #endif /* BCM_TRIUMPH3_SUPPORT */
   6948             } else {
   6949                 return BCM_E_UNAVAIL;
   6950             }
   6951             break;
   6952 
   6953         case bcmMulticastVpTrunkResolve:
   6954             if (_BCM_MULTICAST_IS_L2(group)) {
   6955                 /* Not applicable to multicast types that uses a L2MC index. */
   6956                 return BCM_E_PARAM;
   6957             }
   6958 #if defined(BCM_TRIDENT2_SUPPORT) && defined(INCLUDE_L3)
   6959             if (soc_feature(unit, soc_feature_vp_lag)) {
   6960                 egr_ipmc_entry_t egr_ipmc_entry;
   6961 
   6962                 index = _BCM_MULTICAST_ID_GET(group);
   6963                 BCM_IF_ERROR_RETURN(READ_EGR_IPMCm(unit, MEM_BLOCK_ANY, index,
   6964                             &egr_ipmc_entry));
   6965                 *arg = soc_EGR_IPMCm_field32_get(unit, &egr_ipmc_entry,
   6966                         ENABLE_VPLAG_RESOLUTIONf);
   6967             } else
   6968 #endif /* BCM_TRIDENT2_SUPPORT && INCLUDE_L3 */
   6969             {
   6970                 return BCM_E_PARAM;
   6971             }
   6972             break;
   6973 
   6974 #if defined(INCLUDE_L3)
   6975         case bcmMulticastRemapGroup:
   6976             rv = _bcm_esw_multicast_remap_group_get(unit, group, arg);
   6977             break;
   6978 #endif
   6979 
   6980         default:
   6981             return BCM_E_PARAM;
   6982     }
   6983 
   6984 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   6985     return rv;
   6986 }
   6987 
   6988 /*
   6989  * Function:
   6990  *      _bcm_esw_ipmc_subscriber_egress_intf_add
   6991  * Purpose:
   6992  *      Helper function to add ipmc egress interface on different devices.
   6993  * Parameters:
   6994  *      unit       - (IN)   Device Number
   6995  *      ipmc_id    - (IN)   ipmc id
   6996  *      port       - (IN)  Port number
   6997  *      nh_index   - (IN)  Next Hop index
   6998  *      subscriber_queue - (IN) Subscriber gport
   6999  *      is_l3      - (IN)  Identifier of L2/L3 IPMC interface, relevant only for FB
   7000  *      queue_count - (OUT) number of queues in the extended queue list
   7001  * Returns:
   7002  *      BCM_E_XXX
   7003  */
   7004 int 
   7005 _bcm_esw_ipmc_subscriber_egress_intf_add(int unit, int ipmc_id, 
   7006                                          bcm_port_t port,
   7007                                          int nh_index, 
   7008                                          bcm_gport_t subscriber_queue,
   7009                                          int is_l3,
   7010                                          int *queue_count,
   7011                                          int *q_count_increased)
   7012 {
   7013 #if defined (INCLUDE_L3)
   7014 #if defined(BCM_KATANA_SUPPORT) 
   7015     int id;
   7016 
   7017 #if defined(BCM_SABER2_SUPPORT) 
   7018     if (SOC_IS_SABER2(unit)) {
   7019         id  = nh_index;
   7020         return _bcm_sb2_ipmc_subscriber_egress_intf_add(unit, ipmc_id, port, 
   7021                                                 id, subscriber_queue, is_l3,
   7022                                                 queue_count, q_count_increased);
   7023     }
   7024 #endif 
   7025     if (SOC_IS_KATANAX(unit)) {
   7026         id = nh_index;
   7027 
   7028         return _bcm_kt_ipmc_subscriber_egress_intf_set(unit, ipmc_id, port, 1,
   7029                                                 &id, subscriber_queue, is_l3,
   7030                                                 queue_count, q_count_increased);
   7031     }
   7032 #endif /* BCM_KATANA_SUPPORT */
   7033 #endif /* INCLUDE_L3 */
   7034         return BCM_E_UNAVAIL;
   7035 }
   7036 
   7037 /*
   7038  * Function:
   7039  *      _bcm_esw_ipmc_subscriber_egress_intf_delete
   7040  * Purpose:
   7041  *      Helper function to add ipmc egress interface on different devices.
   7042  * Parameters:
   7043  *      unit       - (IN)   Device Number
   7044  *      ipmc_id    - (IN)   ipmc id
   7045  *      port       - (IN)  Port number
   7046  *      nh_index   - (IN)  Next Hop index
   7047  *      subscriber_queue - (IN) Subscriber gport
   7048  *      is_l3      - (IN)  Identifier of L2/L3 IPMC interface, relevant only for FB
   7049  *      queue_count - (OUT) number of queues in the extended queue list
   7050  * Returns:
   7051  *      BCM_E_XXX
   7052  */
   7053 int 
   7054 _bcm_esw_ipmc_subscriber_egress_intf_delete(int unit, int ipmc_id, 
   7055                                             bcm_port_t port,
   7056                                             int nh_index, 
   7057                                             bcm_gport_t subscriber_queue, 
   7058                                             int is_l3,
   7059                                             int *queue_count,
   7060                                             int *q_count_decreased)
   7061 {
   7062 #if defined (INCLUDE_L3)
   7063     
   7064 #if defined(BCM_KATANA_SUPPORT)
   7065 #if defined(BCM_SABER2_SUPPORT)
   7066     if (SOC_IS_SABER2(unit)) {
   7067         return _bcm_sb2_ipmc_subscriber_egress_intf_delete(unit, ipmc_id, port, 
   7068                                                 nh_index, subscriber_queue,
   7069                                                 queue_count, q_count_decreased);
   7070 
   7071     }
   7072 #endif 
   7073 
   7074     if (SOC_IS_KATANAX(unit)) {
   7075         return _bcm_kt_ipmc_subscriber_egress_intf_delete(unit, ipmc_id, port, 
   7076                                                 nh_index, subscriber_queue,
   7077                                                 queue_count, q_count_decreased);
   7078     }
   7079 #endif /* BCM_KATANA_SUPPORT */
   7080 #endif /* INCLUDE_L3 */
   7081         return BCM_E_UNAVAIL;
   7082 }
   7083 
   7084 /*
   7085  * Function:
   7086  *      _bcm_esw_ipmc_subscriber_egress_intf_set
   7087  * Purpose:
   7088  *      Helper function to add ipmc egress interface on different devices.
   7089  * Parameters:
   7090  *      unit       - (IN)   Device Number
   7091  *      ipmc_id    - (IN)   ipmc id
   7092  *      port       - (IN)  Port number
   7093  *      nh_index   - (IN)  Next Hop index
   7094  *      subscriber_queue - (IN) Subscriber gport
   7095  *      is_l3      - (IN)  Identifier of L2/L3 IPMC interface, relevant only for FB
   7096  *      queue_count - (OUT) number of queues in the extended queue list
   7097  * Returns:
   7098  *      BCM_E_XXX
   7099  */
   7100 int 
   7101 _bcm_esw_ipmc_subscriber_egress_intf_set(int unit, int ipmc_id, 
   7102                                          bcm_port_t port,
   7103                                          int if_count,
   7104                                          int *if_array, 
   7105                                          bcm_gport_t subscriber_queue, 
   7106                                          int is_l3,
   7107                                          int *queue_count,
   7108                                          int *q_count_increased)
   7109 {
   7110 #if defined (INCLUDE_L3)
   7111 #if defined(BCM_KATANA_SUPPORT)
   7112 #if defined(BCM_SABER2_SUPPORT)
   7113     if (SOC_IS_SABER2(unit)) {
   7114         return _bcm_sb2_ipmc_subscriber_egress_intf_set(unit, ipmc_id, port, 
   7115                                                 if_count, if_array, 
   7116                                                 subscriber_queue, is_l3,
   7117                                                 queue_count,
   7118                                                 q_count_increased);
   7119 
   7120     }
   7121 #endif 
   7122 
   7123     if (SOC_IS_KATANAX(unit)) {
   7124         return _bcm_kt_ipmc_subscriber_egress_intf_set(unit, ipmc_id, port, 
   7125                                                 if_count, if_array, 
   7126                                                 subscriber_queue, is_l3,
   7127                                                 queue_count,
   7128                                                 q_count_increased);
   7129     }
   7130 #endif /* BCM_KATANA_SUPPORT */
   7131 #endif /* INCLUDE_L3 */
   7132         return BCM_E_UNAVAIL;
   7133 }
   7134 
   7135 /*
   7136  * Function:
   7137  *      _bcm_esw_ipmc_subscriber_egress_intf_get
   7138  * Purpose:
   7139  *      Helper function to add ipmc egress interface on different devices.
   7140  * Parameters:
   7141  *      unit       - (IN)   Device Number
   7142  *      ipmc_id    - (IN)   ipmc id
   7143  *      port       - (IN)  Port number
   7144  *      nh_index   - (IN)  Next Hop index
   7145  *      subscriber_queue - (IN) Subscriber gport
   7146  *      is_l3      - (IN)  Identifier of L2/L3 IPMC interface, relevant only for FB
   7147  * Returns:
   7148  *      BCM_E_XXX
   7149  */
   7150 int 
   7151 _bcm_esw_ipmc_subscriber_egress_intf_get(int unit, bcm_multicast_t group,
   7152                                          int port_count, 
   7153                                          bcm_gport_t *port_array,
   7154                                          bcm_if_t *encap_id_array,
   7155                                          bcm_gport_t *subscriber_queue_array, 
   7156                                          int *count) 
   7157 {
   7158 #if defined (INCLUDE_L3)
   7159 #if defined(BCM_KATANA_SUPPORT) 
   7160 #if defined(BCM_SABER2_SUPPORT) 
   7161     if (SOC_IS_SABER2(unit)) {
   7162         return _bcm_sb2_ipmc_subscriber_egress_intf_get(unit, group, port_count,
   7163                                                 port_array, encap_id_array, 
   7164                                                 subscriber_queue_array, count);
   7165     }
   7166 #endif 
   7167 
   7168     if (SOC_IS_KATANAX(unit)) {
   7169         return _bcm_kt_ipmc_subscriber_egress_intf_get(unit, group, port_count,
   7170                                                 port_array, encap_id_array, 
   7171                                                 subscriber_queue_array, count);
   7172     }
   7173 #endif /* BCM_KATANA_SUPPORT */
   7174 #endif /* INCLUDE_L3 */
   7175         return BCM_E_UNAVAIL;
   7176 }
   7177 
   7178 /*
   7179  * Function:
   7180  *      _bcm_esw_ipmc_mmu_mc_remap_ptr
   7181  * Purpose:
   7182  *      Helper function to set/get ipmc mmu remap pointer
   7183  * Parameters:
   7184  *      unit       - (IN)   Device Number
   7185  *      ipmc_id    - (IN)   ipmc id
   7186  *      remap_id - (IN/OUT) set/get remap id
   7187  *      set          -  (IN) set/get input
   7188  * Returns:
   7189  *      BCM_E_XXX
   7190  */
   7191 int 
   7192 _bcm_esw_ipmc_mmu_mc_remap_ptr(int unit, int ipmc_id, 
   7193                                            int *remap_id, int set)
   7194 {
   7195 #if defined (INCLUDE_L3)
   7196 #if defined(BCM_KATANA_SUPPORT) 
   7197     if (SOC_IS_KATANAX(unit)) {
   7198         return _bcm_kt_ipmc_mmu_mc_remap_ptr(unit, ipmc_id, 
   7199                                              remap_id, set); 
   7200     }
   7201 #endif /* BCM_KATANA_SUPPORT */
   7202 #endif /* INCLUDE_L3 */
   7203     return BCM_E_UNAVAIL;
   7204 }
   7205 
   7206 /*
   7207  * Function:
   7208  *      _bcm_esw_ipmc_set_remap_group
   7209  * Purpose:
   7210  *      Helper function to set/get ipmc mmu remap pointer
   7211  * Parameters:
   7212  *      unit       - (IN)   Device Number
   7213  *      ipmc_id    - (IN)   ipmc id
   7214  *      port      - (IN)  port id
   7215  *      count          -  (IN) count
   7216  * Returns:
   7217  *      BCM_E_XXX
   7218  */
   7219 int 
   7220 _bcm_esw_ipmc_set_remap_group(int unit, int ipmc_id, 
   7221                                        bcm_port_t port_out, 
   7222                                        int count)
   7223 {
   7224 #if defined (INCLUDE_L3)
   7225 #if defined(BCM_KATANA_SUPPORT) 
   7226 
   7227 #if defined(BCM_SABER2_SUPPORT) 
   7228     if (SOC_IS_SABER2(unit)) {
   7229         return _bcm_sb2_ipmc_set_remap_group(unit, ipmc_id, 
   7230                                     port_out, count); 
   7231     } 
   7232 #endif 
   7233 
   7234     if (SOC_IS_KATANAX(unit)) {
   7235         return _bcm_kt_ipmc_set_remap_group(unit, ipmc_id, 
   7236                                     port_out, count); 
   7237     }
   7238 #endif /* BCM_KATANA_SUPPORT */
   7239 #endif /* INCLUDE_L3 */
   7240     return BCM_E_UNAVAIL;
   7241 }
   7242 
   7243 #if defined(BCM_KATANA_SUPPORT)
   7244 
   7245 /* Macro to free memory and return code instead of using goto */
   7246 
   7247 #define BCM_SUBSCRIBER_MULTICAST_MEM_FREE_RETURN(_r_)   \
   7248     if (local_port_array) {                             \
   7249         sal_free(local_port_array);                     \
   7250     }                                                   \
   7251     if (temp_encap_list) {                              \
   7252         sal_free(temp_encap_list);                      \
   7253         temp_encap_list = NULL;                         \
   7254     }                                                   \
   7255     return _r_;
   7256 
   7257 /*
   7258  * Function:
   7259  *      _bcm_esw_multicast_egress_subscriber_set
   7260  * Purpose:
   7261  *      Set the  replication list
   7262  *      for the specified multicast index.
   7263  * Parameters:
   7264  *      unit      - (IN) Device Number
   7265  *      group     - (IN) Multicast group ID
   7266  *      port_max - (IN) Maximum ports
   7267  *      port_array      - (IN) GPORT array
   7268  *      encap_array  - (IN) Encap ID array.
   7269  *      subscriber_array - (IN) Subscriber array
   7270  * Returns:
   7271  *      BCM_E_XXX
   7272  */
   7273 
   7274 STATIC int
   7275 _bcm_esw_multicast_egress_subscriber_set(int unit, bcm_multicast_t group,
   7276                                          int port_count, 
   7277                                          bcm_gport_t *port_array,
   7278                                          bcm_if_t *encap_id_array,
   7279                                          bcm_gport_t *subscriber_queue_array) 
   7280 {
   7281     int mc_index, i, rv = BCM_E_NONE;
   7282     int gport_id, *temp_encap_list = NULL;
   7283     bcm_port_t *local_port_array = NULL;
   7284     bcm_module_t mod_out;
   7285     bcm_port_t port_out;
   7286     bcm_pbmp_t l2_pbmp;
   7287     l2mc_entry_t l2mc_entry; 
   7288     bcm_trunk_t trunk_id;
   7289     soc_mem_t   mem;
   7290     int modid_local = 0;
   7291 #if defined (INCLUDE_L3)
   7292     int list_count;
   7293     bcm_pbmp_t mc_eligible_pbmp, e_pbmp;
   7294     bcm_port_t port_iter;
   7295     int q_id = 0;
   7296     int remap_index;
   7297     int q_count = 0;
   7298     int q_count_increased = 0;
   7299 #endif /* INCLUDE_L3 */
   7300 #if defined(BCM_KATANA2_SUPPORT)
   7301     int pp_port;
   7302 #endif
   7303 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
   7304     int is_local_subport = FALSE;
   7305 #endif
   7306 
   7307     /* Input parameters check. */
   7308     mc_index = _BCM_MULTICAST_ID_GET(group);
   7309     mem = (_BCM_MULTICAST_L2_OR_FABRIC(unit, group)) ? L2MCm : L3_IPMCm; 
   7310     
   7311     /* BCM_XGS3_FABRIC_SUPPORT */
   7312     if ((mc_index < 0) || (mc_index >= soc_mem_index_count(unit, mem))) {
   7313         return (BCM_E_PARAM);
   7314     }
   7315 
   7316     if (port_count > 0) {
   7317         if (NULL == port_array) {
   7318             return (BCM_E_PARAM);
   7319         }
   7320         if (!_BCM_MULTICAST_L2_OR_FABRIC(unit, group) && 
   7321             (NULL == encap_id_array || NULL == subscriber_queue_array)) {
   7322             return (BCM_E_PARAM);
   7323         }
   7324     } else {
   7325         return (BCM_E_PARAM);
   7326     }   
   7327 
   7328 #if defined (INCLUDE_L3)
   7329     rv = _bcm_esw_multicast_l3_group_check(unit, group, NULL);
   7330 #endif /* INCLUDE_L3 */
   7331     if (BCM_FAILURE(rv) && (0 == _BCM_MULTICAST_IS_L2(group))) {
   7332          return BCM_E_PARAM;
   7333     }
   7334 
   7335     /* Convert GPORT array into local port numbers */
   7336     if (port_count > 0) {
   7337         local_port_array =
   7338             sal_alloc(sizeof(bcm_port_t) * port_count, "local_port array");
   7339         if (NULL == local_port_array) {
   7340             BCM_SUBSCRIBER_MULTICAST_MEM_FREE_RETURN(BCM_E_MEMORY);
   7341         }
   7342         
   7343         temp_encap_list =
   7344             sal_alloc(sizeof(int) * port_count, "temp_encap_list");
   7345         if (NULL == temp_encap_list) {
   7346             BCM_SUBSCRIBER_MULTICAST_MEM_FREE_RETURN(rv);
   7347         }
   7348     }
   7349 
   7350     for (i = 0; i < port_count ; i++) {
   7351         rv = _bcm_esw_gport_resolve(unit, port_array[i],
   7352                                     &mod_out, &port_out,
   7353                                     &trunk_id, &gport_id); 
   7354         if (BCM_FAILURE(rv)) {
   7355             BCM_SUBSCRIBER_MULTICAST_MEM_FREE_RETURN(rv);
   7356         }
   7357 
   7358 #if defined(BCM_HGPROXY_COE_SUPPORT)
   7359         if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   7360             BCM_GPORT_IS_SET(port_array[i]) &&
   7361             _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port_array[i])) {
   7362 
   7363             if(_bcm_xgs5_subport_coe_gport_local(unit, port_array[i])) {
   7364                 is_local_subport = TRUE;
   7365                 rv = _bcmi_coe_subport_physical_port_get(unit,
   7366                                                         port_array[i],
   7367                                                         &local_port_array[i]);
   7368                 if(rv != BCM_E_NONE) {
   7369                     BCM_SUBSCRIBER_MULTICAST_MEM_FREE_RETURN(BCM_E_PORT);
   7370                 }
   7371             } else {
   7372                 BCM_SUBSCRIBER_MULTICAST_MEM_FREE_RETURN(BCM_E_PORT);
   7373             }
   7374 
   7375         } else
   7376 #endif
   7377 
   7378 #if defined(BCM_KATANA2_SUPPORT)
   7379         if (soc_feature(unit, soc_feature_linkphy_coe) ||
   7380             soc_feature(unit, soc_feature_subtag_coe)) {
   7381             if (BCM_GPORT_IS_SET(port_array[i]) &&
   7382                 _BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit,
   7383                     port_array[i])) {
   7384                 if (_bcm_kt2_mod_is_coe_mod_check(unit, mod_out) == BCM_E_NONE) {
   7385                     pp_port = BCM_GPORT_SUBPORT_PORT_GET(port_array[i]);
   7386                     if (_bcm_kt2_is_pp_port_linkphy_subtag(unit, pp_port)) {
   7387                         is_local_subport = TRUE;
   7388                         local_port_array[i] = pp_port;
   7389                     }
   7390                 }
   7391                 if (is_local_subport == FALSE) {
   7392                     BCM_SUBSCRIBER_MULTICAST_MEM_FREE_RETURN(BCM_E_PORT);
   7393                 }
   7394             }
   7395         }
   7396 #endif
   7397 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
   7398         if (is_local_subport) {
   7399             /* Local subport assigned above */
   7400         } else
   7401 #endif
   7402         if (BCM_TRUNK_INVALID != trunk_id) {
   7403             BCM_SUBSCRIBER_MULTICAST_MEM_FREE_RETURN(BCM_E_PARAM);
   7404         } else {
   7405             rv = _bcm_esw_modid_is_local(unit, mod_out, &modid_local);
   7406             if (BCM_FAILURE(rv)) {
   7407                 BCM_SUBSCRIBER_MULTICAST_MEM_FREE_RETURN(rv);
   7408             }
   7409 
   7410             if ((0 == IS_E_PORT(unit, port_out)) &&
   7411                 !(_BCM_MULTICAST_IS_L2(group) ||
   7412                   (BCM_IF_INVALID == encap_id_array[i]))) {
   7413                 /* Stack ports should not perform interface replication */
   7414                 BCM_SUBSCRIBER_MULTICAST_MEM_FREE_RETURN(BCM_E_PARAM);
   7415             }
   7416             if (TRUE != modid_local) {
   7417                 BCM_SUBSCRIBER_MULTICAST_MEM_FREE_RETURN(BCM_E_PARAM);
   7418             }
   7419             local_port_array[i] = port_out;
   7420         }
   7421     }
   7422 
   7423     BCM_PBMP_CLEAR(l2_pbmp);
   7424     if (_BCM_MULTICAST_L2_OR_FABRIC(unit, group)) {
   7425         for (i = 0; i < port_count; i++) {
   7426             BCM_PBMP_PORT_ADD(l2_pbmp, local_port_array[i]);
   7427         }
   7428 
   7429         /* Update the L2MC port bitmap */
   7430         soc_mem_lock(unit, L2MCm);
   7431         rv = soc_mem_read(unit, L2MCm, MEM_BLOCK_ANY, mc_index, &l2mc_entry);
   7432         if (BCM_FAILURE(rv)) {
   7433             soc_mem_unlock(unit, L2MCm);
   7434             BCM_SUBSCRIBER_MULTICAST_MEM_FREE_RETURN(rv);
   7435         }
   7436         soc_mem_pbmp_field_set(unit, L2MCm, &l2mc_entry, PORT_BITMAPf,
   7437                                &l2_pbmp);
   7438         rv = soc_mem_write(unit, L2MCm, MEM_BLOCK_ALL,
   7439                            mc_index, &l2mc_entry);
   7440         soc_mem_unlock(unit, L2MCm);
   7441 #if defined(INCLUDE_L3)
   7442     } else {
   7443         BCM_PBMP_CLEAR(e_pbmp);
   7444         BCM_PBMP_ASSIGN(e_pbmp, PBMP_E_ALL(unit));
   7445         /* 
   7446          * For each port, walk through the list of GPORTs
   7447          * and collect the ones that match the port.
   7448          */
   7449         /* Valid SOC ports plus the CMIC port */
   7450         BCM_PBMP_ASSIGN(mc_eligible_pbmp, PBMP_PORT_ALL(unit));
   7451         BCM_PBMP_PORT_ADD(mc_eligible_pbmp, CMIC_PORT(unit));
   7452 #if defined(BCM_KATANA2_SUPPORT)
   7453         if (soc_feature(unit, soc_feature_subtag_coe) ||
   7454             soc_feature(unit, soc_feature_linkphy_coe)) {
   7455             _bcm_kt2_subport_pbmp_update(unit, &mc_eligible_pbmp);
   7456             _bcm_kt2_subport_pbmp_update(unit, &e_pbmp);
   7457         }
   7458 #endif
   7459 
   7460         BCM_PBMP_ITER(mc_eligible_pbmp, port_iter) {
   7461             list_count = 0;
   7462             for (i = 0; i < port_count ; i++) {
   7463                    if (local_port_array[i] != port_iter) {
   7464                      continue;
   7465                    } 
   7466                    if (encap_id_array[i] == BCM_IF_INVALID) {
   7467                        /* Add port to L2 pbmp */
   7468                        BCM_PBMP_PORT_ADD(l2_pbmp, port_iter);
   7469                    } else if (0 == BCM_PBMP_MEMBER(e_pbmp, port_iter)) {
   7470                        /* Must be a front-panel port to have an
   7471                         * interface replication list. */
   7472                        BCM_SUBSCRIBER_MULTICAST_MEM_FREE_RETURN(BCM_E_PARAM);
   7473                    } else {
   7474                         if (!list_count) {
   7475                             q_id = subscriber_queue_array[i];
   7476                         } else {
   7477                             if (q_id != subscriber_queue_array[i]) {
   7478                                 BCM_SUBSCRIBER_MULTICAST_MEM_FREE_RETURN(BCM_E_PARAM);
   7479                             }
   7480                         }
   7481                         temp_encap_list[list_count] = encap_id_array[i];
   7482                         list_count++;
   7483                     }
   7484                 }
   7485                 
   7486                 if (list_count) {
   7487                     rv = _bcm_esw_ipmc_mmu_mc_remap_ptr(unit, mc_index, &remap_index, FALSE);
   7488                     if (BCM_FAILURE(rv)) {
   7489                         BCM_SUBSCRIBER_MULTICAST_MEM_FREE_RETURN(rv);
   7490                     }
   7491 
   7492                     q_count_increased = 0;
   7493                     if (!SOC_PORT_VALID(unit, port_iter)) {
   7494                         rv = BCM_E_PORT;
   7495                         BCM_SUBSCRIBER_MULTICAST_MEM_FREE_RETURN(rv);
   7496                     }
   7497                     rv = _bcm_esw_ipmc_subscriber_egress_intf_set(unit,
   7498                              remap_index, port_iter, list_count,
   7499                              temp_encap_list,q_id, TRUE, &q_count,
   7500                              &q_count_increased);
   7501                     if (BCM_FAILURE(rv)) {
   7502                         BCM_SUBSCRIBER_MULTICAST_MEM_FREE_RETURN(rv);
   7503                     } else {
   7504                         if (q_count_increased) {
   7505 #if defined(BCM_SABER2_SUPPORT) 
   7506                             if (SOC_IS_SABER2(unit)) {
   7507                                 /* coverity[overrun-call : FALSE] */
   7508                                 _bcm_sb2_ipmc_port_ext_queue_count_increment(unit,
   7509                                                         mc_index, port_iter);
   7510                             } else 
   7511 #endif 
   7512                             {
   7513                                 /* coverity[overrun-call : FALSE] */
   7514                                 _bcm_kt_ipmc_port_ext_queue_count_increment(
   7515                                      unit, mc_index, port_iter);
   7516                             }
   7517                         }
   7518                         /* coverity[overrun-call : FALSE] */
   7519                         rv = _bcm_esw_ipmc_set_remap_group(unit, mc_index, 
   7520                                                          port_iter, q_count); 
   7521                         if (BCM_FAILURE(rv)) {
   7522                             BCM_SUBSCRIBER_MULTICAST_MEM_FREE_RETURN(rv);
   7523                         } 
   7524                     }
   7525                 }
   7526             }
   7527 #endif  /* INCLUDE_L3 */
   7528     }
   7529 
   7530     BCM_SUBSCRIBER_MULTICAST_MEM_FREE_RETURN(rv);
   7531 }
   7532 
   7533 /*
   7534  * Function:
   7535  *      _bcm_esw_multicast_egress_subscriber_get
   7536  * Purpose:
   7537  *      Get the  replication list
   7538  *      for the specified multicast index.
   7539  * Parameters:
   7540  *      unit      - (IN) Device Number
   7541  *      group     - (IN) Multicast group ID
   7542  *      port_max - (IN) Maximum ports
   7543  *      port_array      - (OUT) GPORT array
   7544  *      encap_array  - (OUT) Encap ID array.
   7545  *      subscriber_array - (OUT) Subscriber array
   7546  * Returns:
   7547  *      BCM_E_XXX
   7548  */
   7549 
   7550 STATIC int
   7551 _bcm_esw_multicast_egress_subscriber_get(int unit, bcm_multicast_t group,
   7552                                          int port_max, bcm_gport_t *port_array,
   7553                                          bcm_if_t *encap_id_array,
   7554                                          bcm_gport_t *queue_array,
   7555                                          int *port_count)
   7556 {
   7557     int             mc_index, i, rv;
   7558     int             count = 0;
   7559     bcm_port_t      port;
   7560     int             remap_index;
   7561     int             uc_queue ; 
   7562     int             temp_queue = 0;
   7563     i= 0;
   7564     rv = BCM_E_NONE;
   7565 
   7566     mc_index = _BCM_MULTICAST_ID_GET(group);
   7567     if ((mc_index < 0) ||
   7568         (mc_index >= soc_mem_index_count(unit, L3_IPMCm))) {
   7569         return BCM_E_PARAM;
   7570     }
   7571 
   7572 #if defined (INCLUDE_L3)
   7573     BCM_IF_ERROR_RETURN(_bcm_esw_multicast_l3_group_check(unit, group, NULL));
   7574 #endif /* INCLUDE_L3 */ 
   7575     if (port_max <= 0) {
   7576         return BCM_E_PARAM;
   7577     }
   7578 
   7579     BCM_IF_ERROR_RETURN
   7580     (_bcm_esw_ipmc_mmu_mc_remap_ptr(unit, mc_index, &remap_index, FALSE));
   7581     BCM_IF_ERROR_RETURN
   7582     (_bcm_esw_ipmc_subscriber_egress_intf_get(unit, remap_index, port_max, 
   7583                                     port_array, encap_id_array, 
   7584                                     queue_array, &count)); 
   7585 
   7586     *port_count = count;    
   7587     for (i = 0; i < count; i++) {
   7588         uc_queue = 0; 
   7589         if (NULL != port_array && NULL != queue_array) {
   7590            /* Convert to GPORT values */
   7591 #ifdef BCM_KATANA2_SUPPORT
   7592              if (SOC_IS_KATANA2(unit)) {
   7593                  BCM_IF_ERROR_RETURN
   7594                      (bcm_kt2_cosq_port_get(unit, queue_array[i], &port));
   7595              } else 
   7596 #endif /* BCM_KATANA2_SUPPORT */
   7597              {
   7598                  BCM_IF_ERROR_RETURN
   7599                      (bcm_kt_cosq_port_get(unit, queue_array[i], &port));
   7600              }
   7601 #ifdef BCM_KATANA2_SUPPORT
   7602              if (SOC_IS_KATANA2(unit)) {
   7603                  temp_queue = queue_array[i];
   7604                  rv = bcm_kt2_sw_hw_queue(unit, &queue_array[i]);
   7605                  if (BCM_FAILURE(rv)) {
   7606                      queue_array[i] = temp_queue;
   7607                      BCM_IF_ERROR_RETURN(_bcm_kt_hw_to_sw_queue(unit,
   7608                                                                 &queue_array[i],
   7609                                                                 &port));
   7610                      uc_queue = 0;
   7611                  } else {
   7612                      bcm_kt2_is_uc_queue(unit, queue_array[i], &uc_queue);
   7613                  }
   7614                  if(uc_queue){
   7615                      BCM_GPORT_UCAST_QUEUE_GROUP_SYSQID_SET(queue_array[i],port,
   7616                                                             queue_array[i]); 
   7617                  }
   7618                  else 
   7619                  {
   7620                      if (BCM_SUCCESS(rv)) {
   7621                          bcm_kt2_cosq_subscriber_qid_set(unit, &queue_array[i],
   7622                                                          queue_array[i]);
   7623                      } else {
   7624                          rv = _bcm_kt2_subscriber_sw_qid_set(unit,
   7625                                                              &queue_array[i],
   7626                                                              queue_array[i]);
   7627                      }
   7628                  }
   7629              } else 
   7630 #endif /* BCM_KATANA2_SUPPORT */
   7631              {
   7632                  temp_queue = queue_array[i];
   7633                  rv = bcm_kt_sw_hw_queue(unit, &queue_array[i]);
   7634                  if (BCM_FAILURE(rv)) {
   7635                      queue_array[i] = temp_queue;
   7636                      rv = _bcm_kt_hw_to_sw_queue(unit, &queue_array[i],
   7637                                                  &port);
   7638                      uc_queue = 0;
   7639                  } else {
   7640                      bcm_kt_is_uc_queue(unit, queue_array[i], &uc_queue);
   7641                  }
   7642                  if (uc_queue) 
   7643                  {
   7644                      BCM_GPORT_UCAST_QUEUE_GROUP_SYSQID_SET
   7645                             (queue_array[i],port,queue_array[i]);
   7646                  }
   7647                  else  
   7648                  {
   7649                      bcm_kt_cosq_subscriber_qid_set(unit, &queue_array[i],
   7650                          queue_array[i]);
   7651                  } 
   7652              }
   7653              if(!uc_queue){ 
   7654                 queue_array[i] |= (port << 16);
   7655              }
   7656 #if defined(BCM_KATANA2_SUPPORT)
   7657              /*
   7658               * Encode with subport type if this is a subport
   7659               */
   7660              if (_bcm_kt2_is_pp_port_linkphy_subtag(unit, port)) {
   7661                  _BCM_KT2_SUBPORT_PORT_ID_SET(port_array[i], port);
   7662                  if (BCM_PBMP_MEMBER(SOC_INFO(unit).linkphy_pp_port_pbm,
   7663                              port)) {
   7664                      _BCM_KT2_SUBPORT_PORT_TYPE_SET(port_array[i],
   7665                              _BCM_KT2_SUBPORT_TYPE_LINKPHY);
   7666                  } else if (BCM_PBMP_MEMBER(SOC_INFO(unit).subtag_pp_port_pbm,
   7667                              port)) {
   7668                      _BCM_KT2_SUBPORT_PORT_TYPE_SET(port_array[i],
   7669                              _BCM_KT2_SUBPORT_TYPE_SUBTAG);
   7670                  } else {
   7671                      return BCM_E_PORT;
   7672                  }
   7673              } else
   7674 #endif
   7675              {
   7676                  BCM_IF_ERROR_RETURN
   7677                      (bcm_esw_port_gport_get(unit, port, (port_array + i)));
   7678              }
   7679         }
   7680         if (i == port_max) {
   7681             *port_count = port_max;
   7682             break;
   7683         }
   7684     }
   7685 
   7686     return rv;    
   7687 }
   7688 
   7689 /*
   7690  * Function:
   7691  *   _bcm_esw_multicast_egress_subscriber_qos_map_set
   7692  * Purpose:
   7693  *   Assign the complete set of egress GPORTs in the
   7694  *   replication list for the specified multicast index.
   7695  * Parameters:
   7696  *   unit              - (IN) Device Number
   7697  *   group             - (IN) Multicast group ID
   7698  *   port              - (IN) GPORT Identifier
   7699  *   subscriber queue  - (IN) Subscriber queue group GPORT Identifiers
   7700  *   qos_map_id        - (IN) Qos Map ID
   7701  * Returns:
   7702  *    BCM_E_XXX
   7703  */
   7704 STATIC int
   7705 _bcm_esw_multicast_egress_subscriber_qos_map_set(int unit,
   7706                                         bcm_multicast_t group,
   7707                                         bcm_gport_t port,
   7708                                         bcm_gport_t subscriber_queue,
   7709                                         int qos_map_id)
   7710 {
   7711     int             mc_index;
   7712     int             remap_index;
   7713     int             rv = BCM_E_NONE;
   7714 
   7715     mc_index = _BCM_MULTICAST_ID_GET(group);
   7716     if ((mc_index < 0) ||
   7717         (mc_index >= soc_mem_index_count(unit, L3_IPMCm))) {
   7718         return BCM_E_PARAM;
   7719     }
   7720 
   7721 #if defined (INCLUDE_L3)
   7722     BCM_IF_ERROR_RETURN(_bcm_esw_multicast_l3_group_check(unit, group, NULL));
   7723 #endif /* INCLUDE_L3 */
   7724     BCM_IF_ERROR_RETURN
   7725     (_bcm_esw_ipmc_mmu_mc_remap_ptr(unit, mc_index, &remap_index, FALSE));
   7726 #if defined(BCM_KATANA2_SUPPORT) && defined(INCLUDE_L3)
   7727 #if defined(BCM_SABER2_SUPPORT)
   7728     if(SOC_IS_SABER2(unit)) {
   7729         rv = _bcm_sb2_ipmc_subscriber_egress_intf_qos_map_set(unit,
   7730                                             remap_index,
   7731 					    port, subscriber_queue,
   7732 					    qos_map_id);
   7733     } else
   7734 #endif
   7735     if (SOC_IS_KATANA2(unit)) {
   7736         rv = _bcm_kt2_ipmc_subscriber_egress_intf_qos_map_set(unit,
   7737                                             remap_index,
   7738 					    port, subscriber_queue,
   7739 					    qos_map_id);
   7740     }
   7741 #endif
   7742     return rv;
   7743 }
   7744 
   7745 /*
   7746  * Function:
   7747  *   _bcm_esw_multicast_egress_subscriber_qos_map_get
   7748  * Purpose:
   7749  *   Get QOS Map ID associated with
   7750  *   multicast subscriber queue replication list.
   7751  * Parameters:
   7752  *   unit              - (IN) Device Number
   7753  *   group             - (IN) Multicast group ID
   7754  *   port              - (IN) GPORT Identifier
   7755  *   subscriber queue  - (IN) Subscriber queue group GPORT Identifiers
   7756  *   qos_map_id        - (OUT) Qos Map ID
   7757  * Returns:
   7758  *    BCM_E_XXX
   7759  */
   7760 STATIC int
   7761 _bcm_esw_multicast_egress_subscriber_qos_map_get(int unit,
   7762                                         bcm_multicast_t group,
   7763                                         bcm_gport_t port,
   7764                                         bcm_gport_t subscriber_queue,
   7765                                         int *qos_map_id)
   7766 {
   7767     int             mc_index, rv;
   7768     int             remap_index;
   7769 
   7770     rv = BCM_E_NONE;
   7771 
   7772     mc_index = _BCM_MULTICAST_ID_GET(group);
   7773     if ((mc_index < 0) ||
   7774         (mc_index >= soc_mem_index_count(unit, L3_IPMCm))) {
   7775         return BCM_E_PARAM;
   7776     }
   7777 
   7778 #if defined (INCLUDE_L3)
   7779     BCM_IF_ERROR_RETURN(_bcm_esw_multicast_l3_group_check(unit, group, NULL));
   7780 #endif /* INCLUDE_L3 */
   7781     BCM_IF_ERROR_RETURN
   7782     (_bcm_esw_ipmc_mmu_mc_remap_ptr(unit, mc_index, &remap_index, FALSE));
   7783 #if defined (BCM_KATANA2_SUPPORT) && defined(INCLUDE_L3)
   7784 #if defined (BCM_SABER2_SUPPORT)
   7785     if (SOC_IS_SABER2(unit)) {
   7786         rv =_bcm_sb2_ipmc_subscriber_egress_intf_qos_map_get(unit, remap_index,
   7787                                     port, subscriber_queue,
   7788                                     qos_map_id);
   7789     } else
   7790 #endif
   7791     if (SOC_IS_KATANA2(unit)) {
   7792         rv =_bcm_kt2_ipmc_subscriber_egress_intf_qos_map_get(unit, remap_index,
   7793                                     port, subscriber_queue,
   7794                                     qos_map_id);
   7795     }
   7796 #endif
   7797     return rv;
   7798 }
   7799 
   7800 /*
   7801  * Function:
   7802  *      _bcm_esw_multicast_egress_subscriber_add
   7803  * Purpose:
   7804  *      Add a GPORT to the replication list
   7805  *      for the specified multicast index.
   7806  * Parameters:
   7807  *      unit      - (IN) Device Number
   7808  *      group     - (IN) Multicast group ID
   7809  *      port      - (IN) GPORT Identifier
   7810  *      encap_id  - (IN) Encap ID.
   7811  *      subscriber_queue - (IN) Subscriber gport
   7812  * Returns:
   7813  *      BCM_E_XXX
   7814  */
   7815 
   7816 STATIC int
   7817 _bcm_esw_multicast_egress_subscriber_add(int unit, bcm_multicast_t group,
   7818                                          bcm_gport_t port,
   7819                                          bcm_if_t encap_id,
   7820                                          bcm_gport_t subscriber_queue)
   7821 {
   7822     int mc_index, is_l3, gport_id;
   7823     bcm_module_t mod_out;
   7824     bcm_port_t port_out;
   7825     bcm_trunk_t trunk_id;
   7826     int modid_local, rv = BCM_E_NONE; 
   7827     bcm_pbmp_t l2_pbmp, l3_pbmp, old_pbmp, *new_pbmp;
   7828     int remap_index;
   7829     int q_count = 0;
   7830     int q_count_increased = 0;
   7831     int q_count_decreased = 0;
   7832     int if_max = BCM_MULTICAST_PORT_MAX;
   7833 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
   7834     int is_local_subport = FALSE;
   7835 #endif
   7836 #if defined(BCM_ENDURO_SUPPORT)
   7837     uint16              dev_id;
   7838     uint8               rev_id;
   7839 #if defined(BCM_KATANA2_SUPPORT)
   7840     int my_modid = 0, pp_port;
   7841 #endif
   7842 
   7843     if (SOC_IS_ENDURO(unit)) {
   7844         soc_cm_get_id(unit, &dev_id, &rev_id);
   7845 
   7846         if ((dev_id == BCM56230_DEVICE_ID) || (dev_id == BCM56231_DEVICE_ID)){
   7847             /* 
   7848              * Because the size of "L3 Next Hop Table" 
   7849              * is reduced to 2K only on Dagger (Enduro Variant), 
   7850              * the if_max needs to be changed to the size of "L3 Next Hop 
   7851              * Table (2K)" instead of "BCM_MULTICAST_PORT_MAX(4K)".
   7852              */ 
   7853             if_max = soc_mem_index_count(unit, ING_L3_NEXT_HOPm);
   7854         }
   7855     }
   7856 #endif /* BCM_ENDURO_SUPPORT */
   7857 
   7858     is_l3 = 0;      
   7859     modid_local = FALSE;
   7860 
   7861     mc_index = _BCM_MULTICAST_ID_GET(group);
   7862 
   7863     if ((mc_index < 0) ||
   7864         (mc_index >= soc_mem_index_count(unit, L3_IPMCm))) {
   7865         return BCM_E_PARAM;
   7866     }
   7867 
   7868     if (!(BCM_GPORT_IS_UCAST_SUBSCRIBER_QUEUE_GROUP(subscriber_queue)) 
   7869          && !(BCM_GPORT_IS_MCAST_SUBSCRIBER_QUEUE_GROUP(subscriber_queue))
   7870          && !(BCM_GPORT_IS_UCAST_QUEUE_GROUP(subscriber_queue))) {
   7871         return BCM_E_PARAM;
   7872     }
   7873 
   7874 #if defined (INCLUDE_L3)
   7875     BCM_IF_ERROR_RETURN(_bcm_esw_multicast_l3_group_check(unit, group, &is_l3));
   7876 #endif /* INCLUDE_L3 */
   7877 
   7878     BCM_IF_ERROR_RETURN
   7879         (_bcm_esw_gport_resolve(unit, port, &mod_out, &port_out, 
   7880                                 &trunk_id, &gport_id));
   7881 
   7882 #if defined(BCM_HGPROXY_COE_SUPPORT)
   7883     if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   7884         BCM_GPORT_IS_SET(port) &&
   7885         _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) {
   7886 
   7887         if(_bcm_xgs5_subport_coe_gport_local(unit, port)) {
   7888             is_local_subport = TRUE;
   7889             BCM_IF_ERROR_RETURN(
   7890                 _bcmi_coe_subport_physical_port_get(unit,
   7891                                                     port,
   7892                                                     &port_out));
   7893         } else {
   7894             return BCM_E_PORT;
   7895         }
   7896 
   7897     } else
   7898 #endif
   7899 
   7900 #if defined(BCM_KATANA2_SUPPORT)
   7901     if (soc_feature(unit, soc_feature_linkphy_coe) ||
   7902         soc_feature(unit, soc_feature_subtag_coe)) {
   7903         BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &my_modid));
   7904         if (BCM_GPORT_IS_SET(port) &&
   7905             _BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit, port)) {
   7906             if (_bcm_kt2_mod_is_coe_mod_check(unit, mod_out) == BCM_E_NONE) {
   7907                 pp_port = BCM_GPORT_SUBPORT_PORT_GET(port);
   7908                 if (_bcm_kt2_is_pp_port_linkphy_subtag(unit, pp_port)) {
   7909                         is_local_subport = TRUE;
   7910                         port_out = pp_port;
   7911                 }
   7912             }
   7913             if (is_local_subport == FALSE) {
   7914                 return BCM_E_PORT;
   7915             }
   7916         }
   7917     }
   7918 #endif
   7919 
   7920 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
   7921     if (is_local_subport) {
   7922         /* Local subport assigned above */
   7923     } else
   7924 #endif
   7925 
   7926     if (BCM_TRUNK_INVALID != trunk_id) {
   7927         return BCM_E_PARAM;
   7928     } else {
   7929         BCM_IF_ERROR_RETURN
   7930             (_bcm_esw_modid_is_local(unit, mod_out, &modid_local));
   7931 
   7932         if ((!IS_E_PORT(unit, port_out)) && (BCM_IF_INVALID != encap_id)) {
   7933             /* Stack ports should not perform interface replication */
   7934             return BCM_E_PORT;
   7935         }
   7936         if (TRUE != modid_local) {
   7937             /* Only add this to replication set if destination is local */
   7938             return BCM_E_PORT;
   7939         }
   7940         /* Convert system port to physical port */
   7941         if (soc_feature(unit, soc_feature_sysport_remap)) {
   7942             BCM_XLATE_SYSPORT_S2P(unit, &port_out);
   7943         }
   7944     }
   7945     if (!SOC_PORT_VALID(unit, port_out)) {
   7946         return BCM_E_PORT;
   7947     }
   7948     if (BCM_IF_INVALID != encap_id) {
   7949         /* Add  the required port to the multicast egress interface */
   7950         BCM_IF_ERROR_RETURN(_bcm_esw_ipmc_mmu_mc_remap_ptr(unit,
   7951             mc_index, &remap_index, FALSE));
   7952 
   7953         rv = _bcm_esw_ipmc_subscriber_egress_intf_add(unit, remap_index,
   7954                  port_out, encap_id, subscriber_queue, is_l3, &q_count,
   7955                  &q_count_increased);
   7956         if (BCM_SUCCESS(rv)) {
   7957             new_pbmp = &l3_pbmp;
   7958 #if defined(INCLUDE_L3)
   7959             if (q_count_increased) {
   7960 #if defined(BCM_SABER2_SUPPORT) 
   7961                 if (SOC_IS_SABER2(unit)) {
   7962                     /* coverity[overrun-call : FALSE] */
   7963                     _bcm_sb2_ipmc_port_ext_queue_count_increment(unit,
   7964                              mc_index, port_out);
   7965                 } else 
   7966 #endif 
   7967                 {
   7968                     /* coverity[overrun-call : FALSE] */
   7969                     _bcm_kt_ipmc_port_ext_queue_count_increment(unit, mc_index,
   7970                                                                 port_out);
   7971                 }
   7972             }
   7973 #endif
   7974         } else {
   7975             return rv;
   7976         }
   7977     } else {
   7978         if (!_BCM_MULTICAST_IS_VPLS(group)) {
   7979             /* Updating the L2 bitmap */
   7980             new_pbmp = &l2_pbmp;
   7981         } else {
   7982             return BCM_E_PARAM;
   7983         }
   7984     }
   7985     /* coverity[overrun-call : FALSE] */
   7986     BCM_IF_ERROR_RETURN
   7987         (_bcm_esw_ipmc_set_remap_group(unit, mc_index, port_out, q_count));
   7988 
   7989     rv = _bcm_esw_multicast_ipmc_read(unit, mc_index, &l2_pbmp, &l3_pbmp);
   7990 
   7991     if (BCM_SUCCESS(rv) && (BCM_IF_INVALID == encap_id)) {
   7992         BCM_PBMP_ASSIGN(old_pbmp, *new_pbmp);
   7993         BCM_PBMP_PORT_ADD(*new_pbmp, port_out);
   7994         
   7995         if (BCM_PBMP_NEQ(old_pbmp, *new_pbmp)) {
   7996 
   7997             /* Inside ipmc_write update num_copies, int, ext and 
   7998              * redirection pointer need to manage the work around
   7999              */
   8000             rv = _bcm_esw_multicast_ipmc_write(unit, mc_index, l2_pbmp, 
   8001                                                l3_pbmp, TRUE);
   8002         }
   8003     }
   8004 
   8005     if (BCM_FAILURE(rv)) {
   8006         (void) _bcm_esw_ipmc_subscriber_egress_intf_delete(unit, mc_index, 
   8007                                    port_out, if_max, 
   8008                                    encap_id, is_l3, &q_count,
   8009                                    &q_count_decreased);
   8010     }
   8011 
   8012     return rv;
   8013 }
   8014 
   8015 #if defined (BCM_KATANA_SUPPORT) && defined(INCLUDE_L3)
   8016 STATIC int
   8017 _bcm_esw_ipmc_subscriber_egress_intf_delete_all(int unit, int remap_index,
   8018                                      bcm_port_t *port_array,
   8019                                      int *encap_array,
   8020                                      bcm_if_t *q_array,
   8021                                      int port_count, int mc_index)
   8022 {
   8023     int q_count_decrease = 0;
   8024     int index;
   8025     bcm_port_t temp_port = BCM_GPORT_INVALID;  
   8026     int temp_queue, rv = BCM_E_NONE;
   8027 
   8028 #if defined (BCM_SABER2_SUPPORT)
   8029     if (SOC_IS_SABER2(unit)) {
   8030         BCM_IF_ERROR_RETURN(
   8031             _bcm_sb2_ipmc_subscriber_egress_intf_delete_all(unit, remap_index,
   8032                  port_array, encap_array, q_array, &q_count_decrease));
   8033 
   8034     } else
   8035 #endif /* BCM_SABER2_SUPPORT */
   8036     {
   8037         BCM_IF_ERROR_RETURN(
   8038             _bcm_kt_ipmc_subscriber_egress_intf_delete_all(unit, remap_index,
   8039                  port_count, port_array, encap_array, q_array,
   8040                  &q_count_decrease));
   8041     }
   8042 
   8043     if (q_count_decrease) {
   8044         for (index = 0; index < port_count; index++) {
   8045 #ifdef BCM_KATANA2_SUPPORT
   8046             if (SOC_IS_KATANA2(unit) || SOC_IS_SABER2(unit)) {
   8047                 BCM_IF_ERROR_RETURN(bcm_kt2_cosq_port_get(unit, q_array[index],
   8048                                                           &temp_port));
   8049             } else
   8050 #endif /* BCM_KATANA2_SUPPORT */
   8051             {
   8052                 BCM_IF_ERROR_RETURN(bcm_kt_cosq_port_get(unit, q_array[index],
   8053                                                          &temp_port));
   8054             }
   8055 #if defined (BCM_SABER2_SUPPORT)
   8056             if (SOC_IS_SABER2(unit)) {
   8057                 if (SOC_PORT_VALID(unit, temp_port)) {
   8058                     /* coverity[overrun-call : FALSE] */
   8059                     _bcm_sb2_ipmc_port_ext_queue_count_decrement(unit, mc_index,
   8060                                                                  temp_port);
   8061                 } else {
   8062                     return BCM_E_PORT;
   8063                 }
   8064             } else
   8065 #endif /* BCM_SABER2_SUPPORT */
   8066             {
   8067                 temp_queue = q_array[index];
   8068 #ifdef BCM_KATANA2_SUPPORT
   8069                 if (SOC_IS_KATANA2(unit)) {
   8070                     rv = bcm_kt2_sw_hw_queue(unit, &q_array[index]);
   8071                 } else
   8072 #endif /* BCM_KATANA2_SUPPORT */
   8073                 {
   8074                     rv = bcm_kt_sw_hw_queue(unit, &q_array[index]);
   8075                 }
   8076                 if (BCM_FAILURE(rv)) {
   8077                     q_array[index] = temp_queue;
   8078                     BCM_IF_ERROR_RETURN(_bcm_kt_hw_to_sw_queue(unit,
   8079                                                                &q_array[index],
   8080                                                                &temp_port));
   8081                 }
   8082                 if (SOC_PORT_VALID(unit, temp_port)) {
   8083                     /* coverity[overrun-call : FALSE] */
   8084                     _bcm_kt_ipmc_port_ext_queue_count_decrement(unit, mc_index,
   8085                                                                 temp_port);
   8086                 } else {
   8087                     return BCM_E_PORT;
   8088                 }
   8089             }
   8090         }
   8091         if (temp_port != BCM_GPORT_INVALID) {
   8092             /* coverity[overrun-call : FALSE] */
   8093             BCM_IF_ERROR_RETURN(_bcm_esw_ipmc_set_remap_group(unit, mc_index,
   8094                         temp_port, 0));
   8095         }
   8096     }
   8097     return BCM_E_NONE;
   8098 }
   8099 
   8100 
   8101 STATIC int
   8102 _bcm_esw_multicast_egress_subscriber_delete_all(int unit, 
   8103                                 bcm_multicast_t group)
   8104 {
   8105     int mc_index;
   8106     bcm_gport_t *port_array;
   8107     bcm_if_t *encap_array;
   8108     int *q_array;
   8109     int if_max = BCM_MULTICAST_PORT_MAX;
   8110     int remap_index;
   8111     bcm_error_t rv = BCM_E_NONE;
   8112     int port_count = 0;
   8113     /*get multicast index for multicast group */
   8114     mc_index = _BCM_MULTICAST_ID_GET(group);
   8115     if ((mc_index < 0) ||
   8116             (mc_index >= soc_mem_index_count(unit, L3_IPMCm))) {
   8117         return BCM_E_UNAVAIL;
   8118     }
   8119 
   8120     /*get the port_array, encap array and q_array */
   8121     port_array = sal_alloc(if_max * sizeof(bcm_gport_t),
   8122             "mcast port array");
   8123     if (port_array == NULL) {
   8124         return BCM_E_MEMORY;
   8125     }
   8126     encap_array = sal_alloc(if_max * sizeof(bcm_if_t),
   8127             "mcast encap array");
   8128     if (encap_array == NULL) {
   8129         sal_free (port_array);
   8130         return BCM_E_MEMORY;
   8131     }
   8132     q_array = sal_alloc(if_max * sizeof(bcm_if_t),
   8133             "mcast q array");
   8134     if (q_array == NULL) {
   8135         sal_free (port_array);
   8136         sal_free (encap_array);
   8137         return BCM_E_MEMORY;
   8138     }
   8139     sal_memset(q_array, 0, (if_max * sizeof(bcm_if_t)));
   8140 
   8141     /*get the encap array and port array associated with the group*/
   8142     rv = _bcm_esw_ipmc_mmu_mc_remap_ptr(unit, mc_index, &remap_index, FALSE);
   8143     if (BCM_FAILURE(rv)) {
   8144         goto failure;
   8145     }
   8146     
   8147     rv = (_bcm_esw_ipmc_subscriber_egress_intf_get(unit, remap_index, (if_max -1),
   8148                                     port_array, encap_array,
   8149                                     q_array, &port_count));
   8150 
   8151     if (BCM_FAILURE(rv)) {
   8152         goto failure;
   8153     }
   8154 
   8155     if (port_count) {
   8156         rv = _bcm_esw_ipmc_subscriber_egress_intf_delete_all (unit, 
   8157                               remap_index,port_array, 
   8158                               encap_array, q_array, port_count, mc_index);                                               
   8159     } 
   8160 failure:
   8161     sal_free (port_array);
   8162     sal_free (encap_array);
   8163     sal_free (q_array);
   8164     return rv;
   8165 }
   8166 #endif
   8167 
   8168 
   8169 /*
   8170  * Function:
   8171  *      _bcm_esw_multicast_egress_subscriber_delete
   8172  * Purpose:
   8173  *      Delete a GPORT from the replication list
   8174  *      for the specified multicast index.
   8175  * Parameters:
   8176  *      unit      - (IN) Device Number
   8177  *      group     - (IN) Multicast group ID
   8178  *      port      - (IN) GPORT Identifier
   8179  *      encap_id  - (IN) Encap ID.
   8180  *      subscriber_queue - (IN) Subscriber gport
   8181  * Returns:
   8182  *      BCM_E_XXX
   8183  */
   8184 
   8185 STATIC int
   8186 _bcm_esw_multicast_egress_subscriber_delete(int unit, bcm_multicast_t group,
   8187                                             bcm_gport_t port,
   8188                                             bcm_if_t encap_id,
   8189                                             bcm_gport_t subscriber_queue) 
   8190 {
   8191     int mc_index, is_l3, gport_id;
   8192     bcm_module_t mod_out;
   8193     bcm_port_t port_out;
   8194     bcm_trunk_t trunk_id;
   8195     int modid_local, rv = BCM_E_NONE;
   8196     bcm_pbmp_t l2_pbmp, l3_pbmp, old_pbmp;
   8197     int remap_index;
   8198     int q_count = 0;
   8199     int q_count_decreased = 0;
   8200 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
   8201     int is_local_subport = FALSE;
   8202 #endif
   8203 #if defined(BCM_KATANA2_SUPPORT)
   8204     int pp_port;
   8205 #endif
   8206 
   8207     is_l3 = 0;      
   8208     modid_local = FALSE;
   8209 
   8210     mc_index = _BCM_MULTICAST_ID_GET(group);
   8211 
   8212     if ((mc_index < 0) ||
   8213         (mc_index >= soc_mem_index_count(unit, L3_IPMCm))) {
   8214         return BCM_E_PARAM;
   8215     }
   8216 
   8217 #if defined (INCLUDE_L3)
   8218     BCM_IF_ERROR_RETURN(_bcm_esw_multicast_l3_group_check(unit, group, &is_l3));
   8219 #endif /* INCLUDE_L3 */
   8220     BCM_IF_ERROR_RETURN
   8221         (_bcm_esw_gport_resolve(unit, port, &mod_out, &port_out, 
   8222                                 &trunk_id, &gport_id)); 
   8223 
   8224 
   8225 #if defined(BCM_HGPROXY_COE_SUPPORT)
   8226     if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   8227         BCM_GPORT_IS_SET(port) &&
   8228         _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) {
   8229 
   8230         if(_bcm_xgs5_subport_coe_gport_local(unit, port)) {
   8231             is_local_subport = TRUE;
   8232             BCM_IF_ERROR_RETURN(
   8233                 _bcmi_coe_subport_physical_port_get(unit,
   8234                                                     port,
   8235                                                     &port_out));
   8236         } else {
   8237             return BCM_E_PORT;
   8238         }
   8239 
   8240     } else
   8241 #endif
   8242 
   8243 #if defined(BCM_KATANA2_SUPPORT)
   8244     if (soc_feature(unit, soc_feature_linkphy_coe) ||
   8245         soc_feature(unit, soc_feature_subtag_coe)) {
   8246         if (BCM_GPORT_IS_SET(port) &&
   8247             _BCM_KT2_GPORT_IS_LINKPHY_OR_SUBTAG_SUBPORT_GPORT(unit, port)) {
   8248             if (_bcm_kt2_mod_is_coe_mod_check(unit, mod_out) == BCM_E_NONE) {
   8249                 pp_port = BCM_GPORT_SUBPORT_PORT_GET(port);
   8250                 if (_bcm_kt2_is_pp_port_linkphy_subtag(unit, pp_port)) {
   8251                     is_local_subport = TRUE;
   8252                     port_out = pp_port;
   8253                 }
   8254             }
   8255             if (is_local_subport == FALSE) {
   8256                 return BCM_E_PORT;
   8257             }
   8258         }
   8259     }
   8260 #endif
   8261 
   8262 #if defined(BCM_KATANA2_SUPPORT) || defined(BCM_HGPROXY_COE_SUPPORT)
   8263     if (is_local_subport) {
   8264         /* Local subport assigned above */
   8265     } else
   8266 #endif
   8267 
   8268     if (BCM_TRUNK_INVALID != trunk_id) {
   8269         return BCM_E_PARAM;
   8270     } else {
   8271         BCM_IF_ERROR_RETURN
   8272             (_bcm_esw_modid_is_local(unit, mod_out, &modid_local));
   8273 
   8274         if ((!IS_E_PORT(unit, port_out)) && (BCM_IF_INVALID != encap_id)) {
   8275             /* Stack ports should not perform interface replication */
   8276             return BCM_E_PORT;
   8277         }
   8278         if (TRUE != modid_local) {
   8279             /* Only add this to replication set if destination is local */
   8280             return BCM_E_PORT;
   8281         }
   8282         /* Convert system port to physical port */
   8283         if (soc_feature(unit, soc_feature_sysport_remap)) {
   8284             BCM_XLATE_SYSPORT_S2P(unit, &port_out);
   8285         }
   8286     }
   8287 
   8288     if (encap_id == BCM_IF_INVALID) {
   8289         /* Remove L2 port */
   8290         if (_BCM_MULTICAST_IS_VPLS(group)) {
   8291             return BCM_E_PARAM;
   8292         }
   8293 
   8294         soc_mem_lock(unit, L3_IPMCm);
   8295         /* Delete the port from the IPMC L2_BITMAP */
   8296         rv = _bcm_esw_multicast_ipmc_read(unit, mc_index, 
   8297                                           &l2_pbmp, &l3_pbmp);
   8298         if (BCM_SUCCESS(rv)) {
   8299             BCM_PBMP_ASSIGN(old_pbmp, l2_pbmp);
   8300 
   8301             BCM_PBMP_PORT_REMOVE(l2_pbmp, port_out);
   8302 
   8303             if (BCM_PBMP_NEQ(old_pbmp, l2_pbmp)) {
   8304                 rv = _bcm_esw_multicast_ipmc_write(unit, mc_index,
   8305                                         l2_pbmp, l3_pbmp, TRUE);
   8306             } else {
   8307                 rv = BCM_E_NOT_FOUND;
   8308             }
   8309         }
   8310         soc_mem_unlock(unit, L3_IPMCm);
   8311         return rv;
   8312     }
   8313 
   8314     BCM_IF_ERROR_RETURN
   8315         (_bcm_esw_ipmc_mmu_mc_remap_ptr(unit, mc_index, &remap_index, FALSE));
   8316     if (!SOC_PORT_VALID(unit, port_out)) {
   8317         return BCM_E_PORT;
   8318     }
   8319     rv = _bcm_esw_ipmc_subscriber_egress_intf_delete(unit,
   8320              remap_index, port_out, encap_id, subscriber_queue,
   8321              is_l3, &q_count, &q_count_decreased);
   8322     if (BCM_SUCCESS(rv)) {
   8323 #if defined(INCLUDE_L3)
   8324         if (q_count_decreased) {
   8325 #if defined(BCM_SABER2_SUPPORT) 
   8326              if (SOC_IS_SABER2(unit)) {
   8327                  /* coverity[overrun-call : FALSE] */
   8328                  _bcm_sb2_ipmc_port_ext_queue_count_decrement(unit,
   8329                              mc_index, port_out);
   8330              } else 
   8331 #endif 
   8332              {
   8333                  /* coverity[overrun-call : FALSE] */
   8334                  _bcm_kt_ipmc_port_ext_queue_count_decrement(unit, mc_index,
   8335                                                              port_out);
   8336              }
   8337         }
   8338 #endif
   8339         /* coverity[overrun-call : FALSE] */
   8340         BCM_IF_ERROR_RETURN(_bcm_esw_ipmc_set_remap_group(unit, mc_index, 
   8341                                                        port_out, q_count)); 
   8342     }
   8343    
   8344     return rv;
   8345 }
   8346 
   8347 #endif /* BCM_KATANA_SUPPORT */
   8348 
   8349 /*
   8350  * Function:
   8351  *      bcm_esw_multicast_egress_subscriber_add
   8352  * Purpose:
   8353  *      Add a GPORT to the replication list
   8354  *      for the specified multicast index.
   8355  * Parameters:
   8356  *      unit      - (IN) Device Number
   8357  *      group     - (IN) Multicast group ID
   8358  *      port      - (IN) GPORT Identifier
   8359  *      encap_id  - (IN) Encap ID.
   8360  *      subscriber_queue - (IN) Subscriber gport
   8361  * Returns:
   8362  *      BCM_E_XXX
   8363  */
   8364 int
   8365 bcm_esw_multicast_egress_subscriber_add(int unit, bcm_multicast_t group,
   8366                                         bcm_gport_t port,
   8367                                         bcm_if_t encap_id,
   8368                                         bcm_gport_t subscriber_queue)
   8369 {
   8370     MULTICAST_INIT_CHECK(unit);
   8371 
   8372 #if defined(BCM_KATANA_SUPPORT) && defined(INCLUDE_L3)
   8373     if (SOC_IS_KATANAX(unit)) {    
   8374        return _bcm_esw_multicast_egress_subscriber_add(unit, group, port, 
   8375                                                        encap_id, subscriber_queue);
   8376     }
   8377 #endif /* BCM_KATANA_SUPPORT && INCLUDE_L3 */
   8378         return BCM_E_UNAVAIL;
   8379 }
   8380 
   8381 /*
   8382  * Function:
   8383  *      bcm_esw_multicast_egress_subscriber_delete
   8384  * Purpose:
   8385  *      Delete a GPORT from the replication list
   8386  *      for the specified multicast index.
   8387  * Parameters:
   8388  *      unit      - (IN) Device Number
   8389  *      group     - (IN) Multicast group ID
   8390  *      port      - (IN) GPORT Identifier
   8391  *      encap_id  - (IN) Encap ID.
   8392  *      subscriber_queue - (IN) Subscriber gport
   8393  * Returns:
   8394  *      BCM_E_XXX
   8395  */
   8396 int
   8397 bcm_esw_multicast_egress_subscriber_delete(int unit, bcm_multicast_t group,
   8398                                            bcm_gport_t port,
   8399                                            bcm_if_t encap_id,
   8400                                            bcm_gport_t subscriber_queue) 
   8401 {
   8402     MULTICAST_INIT_CHECK(unit);
   8403 
   8404 #if defined(BCM_KATANA_SUPPORT) && defined(INCLUDE_L3)
   8405     if (SOC_IS_KATANAX(unit)) {    
   8406         return _bcm_esw_multicast_egress_subscriber_delete(unit, group, port, 
   8407                                                     encap_id, subscriber_queue);
   8408     }
   8409 #endif /* BCM_KATANA_SUPPORT && INCLUDE_L3 */
   8410             return BCM_E_UNAVAIL;
   8411 }
   8412 
   8413 #if defined(BCM_KATANA_SUPPORT) && defined(INCLUDE_L3)
   8414 
   8415 int
   8416 _bcm_esw_multicast_egress_subscriber_set_update(int unit, bcm_multicast_t group,
   8417     int port_count, bcm_gport_t *port_array, bcm_if_t *encap_id_array,
   8418     bcm_gport_t *subscriber_queue_array)
   8419 
   8420 {
   8421     bcm_gport_t *cur_port_array, *new_port_array;
   8422     bcm_if_t *cur_encap_array, *new_encap_array;
   8423     bcm_gport_t *cur_q_array, *new_q_array;
   8424     int if_max = BCM_MULTICAST_PORT_MAX;
   8425     bcm_error_t rv = BCM_E_NONE;
   8426     int if_index, if_cur_index, cur_port_count = 0, new_port_count = 0;
   8427 
   8428     /*Allocate memory for current and new port_array, encap array and q_array */
   8429     cur_port_array = sal_alloc(if_max * sizeof(bcm_gport_t),
   8430                                "current mcast port array");
   8431     if (cur_port_array == NULL) {
   8432         return BCM_E_MEMORY;
   8433     }
   8434     cur_encap_array = sal_alloc(if_max * sizeof(bcm_if_t),
   8435                                 "current mcast encap array");
   8436     if (cur_encap_array == NULL) {
   8437         sal_free (cur_port_array);
   8438         return BCM_E_MEMORY;
   8439     }
   8440     cur_q_array = sal_alloc(if_max * sizeof(bcm_gport_t),
   8441                             "current mcast q array");
   8442     if (cur_q_array == NULL) {
   8443         sal_free (cur_port_array);
   8444         sal_free (cur_encap_array);
   8445         return BCM_E_MEMORY;
   8446     }
   8447 
   8448     sal_memset(cur_port_array, 0, (if_max * sizeof(bcm_gport_t)));
   8449     sal_memset(cur_encap_array, 0, (if_max * sizeof(bcm_if_t)));
   8450     sal_memset(cur_q_array, 0, (if_max * sizeof(bcm_gport_t)));
   8451 
   8452     new_port_array = sal_alloc(port_count * sizeof(bcm_gport_t),
   8453                                "new mcast port array");
   8454     if (new_port_array == NULL) {
   8455         sal_free (cur_port_array);
   8456         sal_free (cur_encap_array);
   8457         sal_free (cur_q_array);
   8458         return BCM_E_MEMORY;
   8459     }
   8460     new_encap_array = sal_alloc(port_count * sizeof(bcm_if_t),
   8461                                 "new mcast encap array");
   8462     if (new_encap_array == NULL) {
   8463         sal_free (cur_port_array);
   8464         sal_free (cur_encap_array);
   8465         sal_free (cur_q_array);
   8466         sal_free (new_port_array);
   8467         return BCM_E_MEMORY;
   8468     }
   8469     new_q_array = sal_alloc(port_count * sizeof(bcm_gport_t),
   8470                             "new mcast q array");
   8471     if (new_q_array == NULL) {
   8472         sal_free (cur_port_array);
   8473         sal_free (cur_encap_array);
   8474         sal_free (cur_q_array);
   8475         sal_free (new_port_array);
   8476         sal_free (new_encap_array);
   8477         return BCM_E_MEMORY;
   8478     }
   8479 
   8480     sal_memset(new_port_array, 0, (port_count * sizeof(bcm_gport_t)));
   8481     sal_memset(new_encap_array, 0, (port_count * sizeof(bcm_if_t)));
   8482     sal_memset(new_q_array, 0, (port_count * sizeof(bcm_gport_t)));
   8483 
   8484     /* get the port array, encap array, queue array associated with the group */
   8485     rv = _bcm_esw_multicast_egress_subscriber_get(unit, group, (if_max -1),
   8486                                                   cur_port_array,
   8487                                                   cur_encap_array, cur_q_array,
   8488                                                   &cur_port_count);
   8489     if (BCM_FAILURE(rv)) {
   8490         goto done;
   8491     }
   8492 
   8493     for (if_index = 0; if_index < port_count; if_index++) {
   8494         for (if_cur_index=0; if_cur_index < cur_port_count; if_cur_index++) {
   8495             if ((encap_id_array[if_index] == cur_encap_array[if_cur_index]) &&
   8496                 (subscriber_queue_array[if_index] ==
   8497                  cur_q_array[if_cur_index])) {
   8498                 /* This replication is already attached to the queue and should
   8499                  * not be deleted.
   8500                  */
   8501                 cur_encap_array[if_cur_index] = -1;
   8502                 break;
   8503             }
   8504         }
   8505 
   8506         if (if_cur_index == cur_port_count) {
   8507             /* This is the new replication yet to be attached to the queue */
   8508             new_port_array[new_port_count] = port_array[if_index];
   8509             new_encap_array[new_port_count] = encap_id_array[if_index];
   8510             new_q_array[new_port_count] = subscriber_queue_array[if_index];
   8511             new_port_count++;
   8512         }
   8513     }
   8514 
   8515     if (new_port_count != 0) {
   8516         rv = _bcm_esw_multicast_egress_subscriber_set(unit, group,
   8517                  new_port_count, new_port_array, new_encap_array,
   8518                  new_q_array);
   8519         if (BCM_FAILURE(rv)) {
   8520             goto done;
   8521         }
   8522     }
   8523 
   8524     for (if_cur_index=0; if_cur_index < cur_port_count; if_cur_index++) {
   8525         if (cur_encap_array[if_cur_index] == -1) {
   8526             /* Skip deleting the replication entry already attached */
   8527             continue;
   8528         } else {
   8529             /* Delete the replication which is not present in the input list */
   8530             rv = _bcm_esw_multicast_egress_subscriber_delete(unit, group,
   8531                      cur_port_array[if_cur_index],
   8532                      cur_encap_array[if_cur_index], cur_q_array[if_cur_index]);
   8533             if (BCM_FAILURE(rv)) {
   8534                 goto done;
   8535             }
   8536         }
   8537     }
   8538 done:
   8539     if (cur_port_array) {
   8540         sal_free (cur_port_array);
   8541     }
   8542     if (cur_encap_array) {
   8543         sal_free (cur_encap_array);
   8544     }
   8545     if (cur_q_array) {
   8546         sal_free (cur_q_array);
   8547     }
   8548     if (new_port_array) {
   8549         sal_free (new_port_array);
   8550     }
   8551     if (new_encap_array) {
   8552         sal_free (new_encap_array);
   8553     }
   8554     if (new_q_array) {
   8555         sal_free (new_q_array);
   8556     }
   8557     return rv;
   8558 }
   8559 
   8560 #endif
   8561 
   8562 /*  
   8563  * Function:
   8564  *      bcm_esw_multicast_egress_subscriber_set
   8565  * Purpose:
   8566  *      Assign the complete set of egress GPORTs in the
   8567  *      replication list for the specified multicast index.
   8568  * Parameters:
   8569  *      unit       - (IN) Device Number
   8570  *      group      - (IN) Multicast group ID
   8571  *      port_count - (IN) Number of ports in replication list
   8572  *      port_array - (IN) List of GPORT Identifiers
   8573  *      encap_id_array - (IN) List of encap identifiers
   8574  *      subscriber_queue_array - (IN) Subscriber array
   8575  * Returns:
   8576  *      BCM_E_XXX
   8577  */     
   8578 int
   8579 bcm_esw_multicast_egress_subscriber_set(int unit, bcm_multicast_t group,
   8580                                         int port_count, bcm_gport_t *port_array,
   8581                                         bcm_if_t *encap_id_array,
   8582                                         bcm_gport_t *subscriber_queue_array) 
   8583 {
   8584     bcm_error_t rv = BCM_E_UNAVAIL;
   8585     MULTICAST_INIT_CHECK(unit);
   8586 #if defined(BCM_KATANA_SUPPORT) && defined(INCLUDE_L3)
   8587     if (SOC_IS_KATANAX(unit)) {
   8588         if (port_count == 0) {
   8589             BCM_IF_ERROR_RETURN(_bcm_esw_multicast_egress_subscriber_delete_all
   8590                     (unit, group));
   8591 
   8592             /* If port_count is 0, then there is nothing to set and we can
   8593              * return BCM_E_NONE since all replications were already deleted
   8594              * using _bcm_esw_multicast_egress_subscriber_delete_all.
   8595              */
   8596             return BCM_E_NONE;
   8597         }
   8598         rv = _bcm_esw_multicast_egress_subscriber_set_update(unit, group,
   8599                  port_count, port_array, encap_id_array,
   8600                  subscriber_queue_array);
   8601     }
   8602 #endif /* BCM_KATANA_SUPPORT && INCLUDE_L3 */
   8603     return rv;
   8604 }
   8605 
   8606 /*  
   8607  * Function:
   8608  *      bcm_esw_multicast_egress_subscriber_get
   8609  * Purpose:
   8610  *      Get the complete set of egress GPORTs in the
   8611  *      replication list for the specified multicast index.
   8612  * Parameters:
   8613  *      unit       - (IN) Device Number
   8614  *      group      - (IN) Multicast group ID
   8615  *      port_count - (IN) Number of ports in replication list
   8616  *      port_array - (OUT) List of GPORT Identifiers
   8617  *      encap_id_array - (OUT) List of encap identifiers
   8618   *      subscriber_queue_array - (OUT) Subscriber array
   8619  * Returns:
   8620  *      BCM_E_XXX
   8621  */ 
   8622 int
   8623 bcm_esw_multicast_egress_subscriber_get(int unit, bcm_multicast_t group,
   8624                                         int port_max,
   8625                                         bcm_gport_t *port_array,
   8626                                         bcm_if_t *encap_id_array,
   8627                                         bcm_gport_t *subscriber_queue_array,
   8628                                         int *port_count)
   8629 {
   8630     MULTICAST_INIT_CHECK(unit);
   8631 
   8632 #if defined(BCM_KATANA_SUPPORT) && defined(INCLUDE_L3)
   8633     if (SOC_IS_KATANAX(unit)) {            
   8634         return _bcm_esw_multicast_egress_subscriber_get(unit, group, 
   8635                                                         port_max, port_array, 
   8636                                                         encap_id_array, 
   8637                                                         subscriber_queue_array,
   8638                                                         port_count);
   8639     }
   8640 #endif /* BCM_KATANA_SUPPORT && INCLUDE_L3 */
   8641             return BCM_E_UNAVAIL;  
   8642 }
   8643 
   8644 /*
   8645  * Function:
   8646  *      bcm_esw_multicast_egress_subscriber_qos_map_set
   8647  * Purpose:
   8648  *      Assign the complete set of egress GPORTs in the
   8649  *      replication list for the specified multicast index.
   8650  * Parameters:
   8651  *      unit              - (IN) Device Number
   8652  *      group             - (IN) Multicast group ID
   8653  *      port              - (IN) GPORT Identifier
   8654  *      subscriber queue  - (IN) Subscriber queue group GPORT Identifiers
   8655  *      qos_map_id        - (IN) Qos Map ID
   8656  * Returns:
   8657  *      BCM_E_XXX
   8658  */
   8659 int
   8660 bcm_esw_multicast_egress_subscriber_qos_map_set(int unit,
   8661                                         bcm_multicast_t group,
   8662                                         bcm_gport_t port,
   8663                                         bcm_gport_t subscriber_queue,
   8664                                         int qos_map_id)
   8665 {
   8666     MULTICAST_INIT_CHECK(unit);
   8667 
   8668 #if defined(BCM_KATANA2_SUPPORT) && defined(INCLUDE_L3)
   8669         if (SOC_IS_KATANA2(unit)) {
   8670             return _bcm_esw_multicast_egress_subscriber_qos_map_set(unit,
   8671                                                     group, port,
   8672                                                     subscriber_queue,
   8673                                                     qos_map_id);
   8674         }
   8675 #endif /* BCM_KATANA_SUPPORT && INCLUDE_L3 */
   8676         return BCM_E_UNAVAIL;
   8677 
   8678 }
   8679 
   8680 /*
   8681  * Function:
   8682  *      bcm_esw_multicast_egress_subscriber_qos_map_get
   8683  * Purpose:
   8684  *      Get QOS Map ID associated with
   8685  *      multicast subscriber queue replication list.
   8686  * Parameters:
   8687  *      unit              - (IN) Device Number
   8688  *      group             - (IN) Multicast group ID
   8689  *      port              - (IN) GPORT Identifier
   8690  *      subscriber queue  - (IN) Subscriber queue group GPORT Identifiers
   8691  *      qos_map_id        - (OUT) Qos Map ID
   8692  * Returns:
   8693  *      BCM_E_XXX
   8694  */
   8695 int
   8696 bcm_esw_multicast_egress_subscriber_qos_map_get(int unit,
   8697                                         bcm_multicast_t group,
   8698                                         bcm_gport_t port,
   8699                                         bcm_gport_t subscriber_queue,
   8700                                         int *qos_map_id)
   8701 {
   8702     MULTICAST_INIT_CHECK(unit);
   8703 
   8704 #if defined(BCM_KATANA2_SUPPORT) && defined(INCLUDE_L3)
   8705     if (SOC_IS_KATANA2(unit)) {
   8706         return _bcm_esw_multicast_egress_subscriber_qos_map_get(unit, group,
   8707                                                      port,
   8708                                                     subscriber_queue,
   8709                                                     qos_map_id);
   8710     }
   8711 #endif /* BCM_KATANA_SUPPORT && INCLUDE_L3 */
   8712             return BCM_E_UNAVAIL;
   8713 }
   8714 
   8715 /*
   8716  * Function:
   8717  *      bcm_esw_multicast_multi_alloc
   8718  * Purpose:
   8719  *      Allocates multiple multicast groups consecutively.
   8720  * Parameters:
   8721  *      unit           - (IN)   Device Number
   8722  *      mc_multi_info  - (IN)   informtaion to create multicast mc groups.
   8723  *      base_mc_group  - (IN/OUT)  base group id for allocated multiple groups.
   8724  * Returns:
   8725  *      BCM_E_XXX
   8726  */
   8727 int
   8728 bcm_esw_multicast_multi_alloc( int unit,
   8729         bcm_multicast_multi_info_t mc_multi_info,
   8730         bcm_multicast_t *base_mc_group)
   8731 {
   8732     int rv = BCM_E_UNAVAIL;
   8733 #ifdef BCM_MULTI_LEVEL_FAILOVER_SUPPORT
   8734     MULTICAST_INIT_CHECK(unit);
   8735     rv = bcmi_esw_multicast_multi_alloc(unit, mc_multi_info, base_mc_group);
   8736 #endif
   8737     return rv;
   8738 }
   8739 
   8740 /*
   8741  * Function:
   8742  *      bcm_esw_multicast_multi_free
   8743  * Purpose:
   8744  *      Frees multiple multicast groups.
   8745  * Parameters:
   8746  *      unit           - (IN)   Device Number
   8747  *      base_mc_group  - (IN)  base group id for multiple groups.
   8748  * Returns:
   8749  *      BCM_E_XXX
   8750  */
   8751 int
   8752 bcm_esw_multicast_multi_free(int unit, bcm_multicast_t base_mc_group)
   8753 {
   8754     int rv = BCM_E_UNAVAIL;
   8755 #ifdef BCM_MULTI_LEVEL_FAILOVER_SUPPORT
   8756     MULTICAST_INIT_CHECK(unit);
   8757     rv = bcmi_esw_multicast_multi_free(unit, base_mc_group);
   8758 #endif
   8759     return rv;
   8760 
   8761 }
   8762 
   8763 
   8764 
   8765 #ifndef BCM_SW_STATE_DUMP_DISABLE
   8766 /*
   8767  * Function:
   8768  *      _bcm_esw_multicast_sw_dump_cb
   8769  * Purpose:
   8770  *      Callback to print Multicast info
   8771  * Parameters:
   8772  *      unit       - (IN)   Device Number
   8773  *      group      - (IN)   Group ID
   8774  *      flags      - (OUT)  BCM_MULTICAST_*
   8775  *      user_data  - (IN)   User data to be passed to callback function.
   8776  * Returns:
   8777  *      BCM_E_XXX
   8778  */
   8779 STATIC int
   8780 _bcm_esw_multicast_sw_dump_cb(int unit, bcm_multicast_t group, 
   8781                               uint32 flags, void *user_data)
   8782 {
   8783     LOG_CLI((BSL_META_U(unit,
   8784                         "    0x%08x    0x%08x     "), group, flags));
   8785     if (flags & BCM_MULTICAST_TYPE_L2) {
   8786         LOG_CLI((BSL_META_U(unit,
   8787                             " L2")));
   8788     }
   8789     if (flags & BCM_MULTICAST_TYPE_L3) {
   8790         LOG_CLI((BSL_META_U(unit,
   8791                             " L3")));
   8792     }
   8793     if (flags & BCM_MULTICAST_TYPE_VPLS) {
   8794         LOG_CLI((BSL_META_U(unit,
   8795                             " VPLS")));
   8796     }
   8797     if (flags & BCM_MULTICAST_TYPE_SUBPORT) {
   8798         LOG_CLI((BSL_META_U(unit,
   8799                             " SUBPORT")));
   8800     }
   8801     if (flags & BCM_MULTICAST_TYPE_MIM) {
   8802         LOG_CLI((BSL_META_U(unit,
   8803                             " MIM")));
   8804     }
   8805     if (flags & BCM_MULTICAST_TYPE_WLAN) {
   8806         LOG_CLI((BSL_META_U(unit,
   8807                             " WLAN")));
   8808     }
   8809     if (flags & BCM_MULTICAST_TYPE_VLAN) {
   8810         LOG_CLI((BSL_META_U(unit,
   8811                             " VLAN")));
   8812     }
   8813     if (flags & BCM_MULTICAST_TYPE_TRILL) {
   8814         LOG_CLI((BSL_META_U(unit,
   8815                             " TRILL")));
   8816     }
   8817     if (flags & BCM_MULTICAST_TYPE_NIV) {
   8818         LOG_CLI((BSL_META_U(unit,
   8819                             " NIV")));
   8820     }
   8821     if (flags &  BCM_MULTICAST_TYPE_EGRESS_OBJECT) {
   8822         LOG_CLI((BSL_META_U(unit,
   8823                             " MPLS P2MP")));
   8824     }
   8825     if (flags &  BCM_MULTICAST_TYPE_L2GRE) {
   8826         LOG_CLI((BSL_META_U(unit,
   8827                             " L2GRE")));
   8828     }
   8829     if (flags &  BCM_MULTICAST_TYPE_VXLAN) {
   8830         LOG_CLI((BSL_META_U(unit,
   8831                             " VXLAN")));
   8832     }
   8833     if (flags & BCM_MULTICAST_TYPE_EXTENDER) {
   8834         LOG_CLI((BSL_META_U(unit,
   8835                             " EXTENDER")));
   8836     }
   8837     if (flags & BCM_MULTICAST_WITH_ID) {
   8838         LOG_CLI((BSL_META_U(unit,
   8839                             " ID")));
   8840     }
   8841     LOG_CLI((BSL_META_U(unit,
   8842                         "\n")));
   8843     return BCM_E_NONE;
   8844 }
   8845 
   8846 /*
   8847  * Function:
   8848  *     _bcm_multicast_sw_dump
   8849  * Purpose:
   8850  *     Displays Multicast information maintained by software.
   8851  * Parameters:
   8852  *     unit - Device unit number
   8853  * Returns:
   8854  *     None
   8855  * Note:
   8856  *    The multicast info is really handled by other modules, but
   8857  *    this is a handy summary of the information.
   8858  *    Dump of l2_data is skipped.
   8859  */
   8860 void
   8861 _bcm_multicast_sw_dump(int unit)
   8862 {
   8863     int rv;
   8864 
   8865     LOG_CLI((BSL_META_U(unit,
   8866                         "\nSW Information Multicast - Unit %d\n"), unit));
   8867     LOG_CLI((BSL_META_U(unit,
   8868                         "    Initialized: %d\n"), multicast_initialized[unit]));
   8869     LOG_CLI((BSL_META_U(unit,
   8870                         "    Groups:       Flag value:     Flags:\n")));
   8871 
   8872     rv = bcm_esw_multicast_group_traverse(unit,
   8873                                           &_bcm_esw_multicast_sw_dump_cb,
   8874                                           BCM_MULTICAST_TYPE_MASK, NULL);
   8875 
   8876     if (BCM_FAILURE(rv)) {
   8877         LOG_CLI((BSL_META_U(unit,
   8878                             "\n  *** Multicast traverse error ***: %s\n"),
   8879                  bcm_errmsg(rv)));
   8880     }
   8881 
   8882 #if defined(BCM_FIREBOLT_SUPPORT) || defined(BCM_SCORPION_SUPPORT)
   8883 #if defined(INCLUDE_L3)
   8884     if (SOC_REG_IS_VALID(unit, IPMC_L3_MTUr) && (NULL != _bcm_mtu_profile)) {
   8885         int i, num_entries, ref_count;
   8886         uint64 rval64, *rval64s[1];
   8887 
   8888         rval64s[0] = &rval64;
   8889         num_entries = SOC_REG_NUMELS(unit, IPMC_L3_MTUr);
   8890         LOG_CLI((BSL_META_U(unit,
   8891                             "  IPMC_L3_MTU\n")));
   8892         LOG_CLI((BSL_META_U(unit,
   8893                             "    Number of entries: %d\n"), num_entries));
   8894         LOG_CLI((BSL_META_U(unit,
   8895                             "    Index RefCount -  IPMC_L3_MTU\n")));
   8896         
   8897         for (i = 0; i < num_entries; i++) {
   8898             rv = soc_profile_reg_ref_count_get(unit,
   8899                                                _bcm_mtu_profile[unit],
   8900                                                i, &ref_count);
   8901             if (SOC_FAILURE(rv)) {
   8902                 LOG_CLI((BSL_META_U(unit,
   8903                                     " *** Error retrieving profile reference: %d ***\n"),
   8904                          rv));
   8905                 break;
   8906             }
   8907             if (ref_count <= 0) {
   8908                 continue;
   8909             }
   8910             rv = soc_profile_reg_get(unit, _bcm_mtu_profile[unit], i,
   8911                                      1, rval64s);
   8912             if (SOC_FAILURE(rv)) {
   8913                 LOG_CLI((BSL_META_U(unit,
   8914                                     " *** Error retrieving profile value: %d ***\n"),
   8915                          rv));
   8916                 break;
   8917             }
   8918             LOG_CLI((BSL_META_U(unit,
   8919                                 "  %5d %8d       0x%08x\n"),
   8920                      i, ref_count, COMPILER_64_LO(rval64)));
   8921         }
   8922         LOG_CLI((BSL_META_U(unit,
   8923                             "\n")));
   8924     }
   8925 #endif /* INCLUDE_L3 */
   8926 #endif
   8927 
   8928 #if defined(BCM_TRIDENT2_SUPPORT) && defined(INCLUDE_L3) 
   8929     if (soc_feature(unit, soc_feature_virtual_port_routing)) {
   8930 #ifdef BCM_WARM_BOOT_SUPPORT_SW_DUMP
   8931         bcm_td2_multicast_l3_vp_sw_dump(unit);
   8932 #endif /* BCM_WARM_BOOT_SUPPORT_SW_DUMP */
   8933     }
   8934 #endif /* BCM_TRIDENT2_SUPPORT && INCLUDE_L3 */
   8935 
   8936     return;
   8937 }
   8938 int
   8939 _bcm_fabric_multicast_ipmc_group_types_dump(int unit)
   8940 {
   8941 #ifdef BCM_XGS3_FABRIC_SUPPORT
   8942     int search_index, index_min, index_max,ipmc_id;
   8943     if (SOC_IS_XGS3_FABRIC(unit)) {
   8944 
   8945         index_min = BCM_FABRIC_IPMC_BASE(unit);
   8946         index_max = BCM_FABRIC_IPMC_MAX(unit);
   8947 
   8948         for (search_index = index_min; search_index <= index_max;
   8949                 search_index++) {
   8950 
   8951             ipmc_id = search_index - index_min;
   8952 
   8953             /* If that mc index exists */
   8954             if (SHR_BITGET(BCM_FABRIC_MC_USED_BITMAP(unit),
   8955                         search_index)) {
   8956                 LOG_CLI((BSL_META_U(unit, "Unit %d IPMC ID %d Group type %d\r\n"),
   8957                         unit, ipmc_id,
   8958                      _fabric_multicast_ipmc_group_types[unit][ipmc_id]));
   8959             }
   8960         }
   8961     }else {
   8962         return BCM_E_PARAM;
   8963     }
   8964 #endif
   8965     return BCM_E_NONE;
   8966 }
   8967 #endif /* BCM_SW_STATE_DUMP_DISABLE */