openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

ipmc.c (238046B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:        ipmc.c
      8  * Purpose:     Tomahawk multicast replication implementation.
      9  */
     10 
     11 #include <shared/bsl.h>
     12 
     13 #include <soc/defs.h>
     14 #include <sal/core/libc.h>
     15 
     16 #if defined(BCM_TOMAHAWK_SUPPORT) && defined(INCLUDE_L3)
     17 
     18 #include <soc/drv.h>
     19 #include <soc/mem.h>
     20 
     21 #include <bcm/types.h>
     22 #include <bcm/error.h>
     23 
     24 #include <bcm_int/esw_dispatch.h>
     25 #include <bcm_int/esw/ipmc.h>
     26 #include <bcm_int/esw/tomahawk.h>
     27 #include <bcm_int/esw/firebolt.h>
     28 
     29 #include <bcm_int/esw/stack.h>
     30 #include <bcm_int/esw/l3.h>
     31 #include <soc/tomahawk.h>
     32 #include <soc/trident3.h>
     33 
     34 #ifdef BCM_TOMAHAWK3_SUPPORT
     35 #include <bcm_int/esw/tomahawk3.h>
     36 #include <soc/tomahawk3.h>
     37 #include <bcm_int/esw/multicast.h>
     38 #endif
     39 #if defined(BCM_HGPROXY_COE_SUPPORT)
     40 #include <bcm_int/esw/xgs5.h>
     41 #endif /* BCM_HGPROXY_COE_SUPPORT */
     42 
     43 #if defined(BCM_TRIDENT3_SUPPORT)
     44 #include <bcm_int/esw/multicast.h>
     45 #include <bcm_int/common/multicast.h>
     46 #endif
     47 
     48 /* Structures for managing REPL_HEAD table resources */
     49 
     50 typedef struct _th_repl_head_free_block_s {
     51     int index; /* Starting index of a free block of REPL_HEAD table entries */
     52     int size;  /* Number of entries in the free block */
     53     struct _th_repl_head_free_block_s *next; /* Pointer to next free block */
     54 } _th_repl_head_free_block_t;
     55 
     56 typedef struct _th_repl_head_info_s {
     57     _th_repl_head_free_block_t **free_list_array;
     58                               /* Array of lists of free blocks */
     59     int array_size;           /* Number of lists in the array */
     60 } _th_repl_head_info_t;
     61 
     62 STATIC _th_repl_head_info_t *_th_repl_head_info[BCM_MAX_NUM_UNITS];
     63 
     64 #define REPL_HEAD_FREE_LIST(_u_, _pipe_, _index_) \
     65     _th_repl_head_info[_u_][_pipe_].free_list_array[_index_]
     66 
     67 /* Structures for managing REPL_LIST table resources */
     68 
     69 typedef struct _th_repl_list_entry_info_s {
     70     SHR_BITDCL *bitmap_entries_used; /* A bitmap indicating which REPL_LIST
     71                                         entries are used */
     72     int num_entries; /* Total number of entries in REPL_LIST table */
     73 } _th_repl_list_entry_info_t;
     74 
     75 STATIC _th_repl_list_entry_info_t \
     76            *_th_repl_list_entry_info[BCM_MAX_NUM_UNITS];
     77 
     78 #define REPL_LIST_ENTRY_USED_GET(_u_, _pipe_, _i_) \
     79         SHR_BITGET(_th_repl_list_entry_info[_u_][_pipe_].bitmap_entries_used, _i_)
     80 #define REPL_LIST_ENTRY_USED_SET(_u_, _pipe_, _i_) \
     81         SHR_BITSET(_th_repl_list_entry_info[_u_][_pipe_].bitmap_entries_used, _i_)
     82 #define REPL_LIST_ENTRY_USED_CLR(_u_, _pipe_, _i_) \
     83         SHR_BITCLR(_th_repl_list_entry_info[_u_][_pipe_].bitmap_entries_used, _i_)
     84 
     85 #define TH_IPMC_NO_SRC_CHECK_PORT      0xFF
     86 
     87 /* Structures containing replication info */
     88 
     89 typedef struct _th_repl_port_info_s {
     90     int *intf_count; /* Array of interface counts, one per replication group */
     91 } _th_repl_port_info_t;
     92 
     93 typedef struct _th_repl_info_s {
     94     int num_pipes;       /* Number of pipelines */
     95     int num_repl_groups; /* Number of replication groups on this device */
     96     uint32 num_intf;     /* Number of interfaces on this device */
     97     _bcm_repl_list_info_t **repl_list_info_array;
     98                          /* Array of linked list of replication list info */
     99     _th_repl_port_info_t *port_info[SOC_MAX_NUM_PORTS];
    100                          /* Per port replication info */
    101     int *l3_intf_next_hop_ipmc; /* Array of next hop indices, one for each
    102                             L3 interface that's added to an IPMC group */ 
    103     int *l3_intf_next_hop_trill; /* Array of next hop indices, one for each
    104                             L3 interface that's added to a Trill group */ 
    105 } _th_repl_info_t;
    106 
    107 static _th_repl_info_t *_th_repl_info[BCM_MAX_NUM_UNITS];
    108 static int mmu_port_stride[BCM_MAX_NUM_UNITS];
    109 #ifdef BCM_TOMAHAWK3_SUPPORT
    110 static _bcm_repl_list_info_t *_repl_list_recycle_array[BCM_MAX_NUM_UNITS];
    111 #endif
    112 
    113 #define REPL_LOCK(_u_)                         \
    114     {                                          \
    115         soc_mem_lock(_u_, MMU_REPL_LIST_TBLm); \
    116     }
    117 #define REPL_UNLOCK(_u_)                         \
    118     {                                            \
    119         soc_mem_unlock(_u_, MMU_REPL_LIST_TBLm); \
    120     }
    121 
    122 #define REPL_INIT(_u_) \
    123         if (_th_repl_info[_u_] == NULL) { return BCM_E_INIT; }
    124 
    125 #define NUM_PIPES(_u_) _th_repl_info[_u_]->num_pipes
    126 
    127 #define REPL_GROUP_ID(_u_, _id_) \
    128         if ((_id_ < 0) || (_id_ >= _th_repl_info[_u_]->num_repl_groups)) \
    129             { return BCM_E_PARAM; }
    130 
    131 #define REPL_INTF_TOTAL(_u_) _th_repl_info[_u_]->num_intf
    132 
    133 #define REPL_LIST_INFO(_u_, _pipe_) \
    134     _th_repl_info[_u_]->repl_list_info_array[_pipe_]
    135 
    136 #define REPL_PORT_GROUP_INFO(_u_, _port_) \
    137     _th_repl_info[_u_]->port_info[_port_]
    138 
    139 #define REPL_PORT_GROUP_INTF_COUNT(_u_, _port_, _group_id_) \
    140     _th_repl_info[_u_]->port_info[_port_]->intf_count[_group_id_]
    141 
    142 #define REPL_L3_INTF_NEXT_HOP_IPMC(_u_, _intf_) \
    143     _th_repl_info[_u_]->l3_intf_next_hop_ipmc[_intf_]
    144 #define REPL_L3_INTF_NEXT_HOP_TRILL(_u_, _intf_) \
    145     _th_repl_info[_u_]->l3_intf_next_hop_trill[_intf_]
    146 
    147 #define REPL_PORT_CHECK(_u_, _port_) \
    148     if (!IS_PORT(_u_, _port_) && !IS_AXP_PORT(_u_, _port_)) { \
    149         return BCM_E_PARAM; \
    150     }
    151 
    152 #define REPL_HEAD_TBL_PIPE(_u_, _pipe_)                                 \
    153     ((SOC_IS_TOMAHAWK3(_u_)) ? MMU_REPL_HEAD_TBLm : \
    154     (SOC_MEM_UNIQUE_ACC(_u_, MMU_REPL_HEAD_TBLm)[_pipe_]))
    155 
    156 #define REPL_HEAD_TBL(_u_)  (MMU_REPL_HEAD_TBLm)
    157 
    158 #define REPL_HEAD_TBL_SPLIT_PIPE(_u_, _split, _pipe_)                   \
    159     (_split == 0 ?                                                      \
    160      SOC_MEM_UNIQUE_ACC(_u_, MMU_REPL_HEAD_TBL_SPLIT0m)[_pipe_] :       \
    161      SOC_MEM_UNIQUE_ACC(_u_, MMU_REPL_HEAD_TBL_SPLIT1m)[_pipe_])
    162 
    163 #define REPL_HEAD_TBL_SPLIT(_u_, _split)                                \
    164     (_split == 0 ? MMU_REPL_HEAD_TBL_SPLIT0m : MMU_REPL_HEAD_TBL_SPLIT1m)
    165 
    166 #define REPL_LIST_TBL_PIPE(_u_, _pipe_)                                 \
    167     (SOC_MEM_UNIQUE_ACC(_u_, MMU_REPL_LIST_TBLm)[_pipe_])
    168 
    169 #define REPL_LIST_TBL(_u_)  (MMU_REPL_LIST_TBLm)
    170 
    171 #define REPL_GROUP_INITIAL_COPY_COUNT_TBL_SLICE(_u_, _slice_)           \
    172     (SOC_MEM_UNIQUE_ACC(_u_, MMU_REPL_GROUP_INITIAL_COPY_COUNTm)[_slice_])
    173 
    174 #define REPL_GROUP_INITIAL_COPY_COUNT_TBL(_u_)                          \
    175     (MMU_REPL_GROUP_INITIAL_COPY_COUNTm)
    176 
    177 #define REPL_GROUP_INFO_TBL_PIPE(_u_, _pipe_)                           \
    178     (SOC_MEM_UNIQUE_ACC(_u_, MMU_REPL_GROUP_INFO_TBLm)[_pipe_])
    179 
    180 #define REPL_GROUP_INFO_TBL(_u_)    (MMU_REPL_GROUP_INFO_TBLm)
    181 
    182 #define REPL_NH_INDEX_UNALLOCATED -1
    183 #define REPL_NH_INDEX_L3_EGRESS_ALLOCATED -2
    184 
    185 STATIC void _bcm_th_repl_head_info_deinit(int unit);
    186 
    187 STATIC int
    188 _bcm_th_repl_list_entry_alloc(int unit, int pipe, int *entry_index);
    189 
    190 STATIC int
    191 _bcm_th_repl_list_free(int unit, int pipe, int start_ptr);
    192 
    193 STATIC int
    194 _bcm_th_repl_list_entry_free(int unit, int pipe, int entry_index);
    195 
    196 #ifdef BCM_TOMAHAWK3_SUPPORT
    197 
    198 #define _TH3_IPMC_MIN_INTF_COUNT 4
    199 
    200 #define _TH3_IPMC_UINT32_LEN 32
    201 #define _TH3_NUM_NH_SPARSE_MODE 4
    202 #define _TH3_NUM_REPL_QUEUE 9
    203 #define _TH3_REPL_LIST_ENTRY_UINT32_TOTAL 128
    204 
    205 /*
    206  * Function:
    207  *      bcm_th3_ipmc_repl_port_attach
    208  * Purpose:
    209  *      Initialize replication per-port configuration in the runtime.
    210  * Parameters:
    211  *      unit - (IN) BCM device number.
    212  *      port - local port number
    213  * Returns:
    214  *      BCM_E_XXX
    215  */
    216 int
    217 bcm_th3_ipmc_repl_port_attach(int unit, bcm_port_t port)
    218 {
    219     int rv = BCM_E_NONE;
    220     int alloc_size;
    221     uint32 regval;
    222     soc_reg_t reg = MMU_RQE_REPL_PORT_AGG_MAPr;
    223     if (_th_repl_info[unit] == NULL) {
    224         return BCM_E_INIT;
    225     }
    226 
    227     /* Detach the IPMC REPL in case it is already attached. */
    228     SOC_IF_ERROR_RETURN
    229         (bcm_th3_ipmc_repl_port_detach(unit, port));
    230 
    231     _th_repl_info[unit]->port_info[port] =
    232                     sal_alloc(sizeof(_th_repl_port_info_t), "repl port info");
    233     if (NULL == _th_repl_info[unit]->port_info[port]) {
    234         return BCM_E_MEMORY;
    235     }
    236     sal_memset(_th_repl_info[unit]->port_info[port], 0,
    237                                                 sizeof(_th_repl_port_info_t));
    238 
    239     alloc_size = sizeof(int) * _th_repl_info[unit]->num_repl_groups;
    240     _th_repl_info[unit]->port_info[port]->intf_count =
    241                                 sal_alloc(alloc_size, "repl port intf count");
    242     if (NULL == _th_repl_info[unit]->port_info[port]->intf_count) {
    243         sal_free(_th_repl_info[unit]->port_info[port]);
    244         return BCM_E_MEMORY;
    245     }
    246     sal_memset(_th_repl_info[unit]->port_info[port]->intf_count, 0, alloc_size);
    247 
    248     /* configure device port to repl aggregateId map */
    249     regval = 0;
    250     soc_reg_field_set(unit, reg, &regval, L3MC_PORT_AGG_IDf,
    251                             BCM_MC_PER_TRUNK_REPL_MODE(unit) ?
    252                                              TH3_AGG_ID_HW_INVALID : port);
    253     rv = soc_reg32_set(unit, reg, port, 0, regval);
    254     if (BCM_FAILURE(rv)) {
    255         (void)bcm_th3_ipmc_repl_port_detach(unit, port);
    256     }
    257 
    258     return rv;
    259 }
    260 
    261 /*
    262  * Function:
    263  *      bcm_th3_ipmc_repl_port_detach
    264  * Purpose:
    265  *      Clear replication per-port configuration in the runtime.
    266  * Parameters:
    267  *      unit - (IN) BCM device number.
    268  *      port - local port number
    269  * Returns:
    270  *      BCM_E_XXX
    271  */
    272 int
    273 bcm_th3_ipmc_repl_port_detach(int unit, bcm_port_t port)
    274 {
    275     if (_th_repl_info[unit] == NULL) {
    276         return BCM_E_INIT;
    277     }
    278 
    279     if (_th_repl_info[unit]->port_info[port] != NULL) {
    280         if (_th_repl_info[unit]->port_info[port]->intf_count != NULL) {
    281             sal_free(_th_repl_info[unit]->port_info[port]->intf_count);
    282             _th_repl_info[unit]->port_info[port]->intf_count = NULL;
    283         }
    284         sal_free(_th_repl_info[unit]->port_info[port]);
    285         _th_repl_info[unit]->port_info[port] = NULL;
    286     }
    287 
    288     /* Reset L3MC_PORT_AGG_IDf to HW invalid */
    289     SOC_IF_ERROR_RETURN
    290         (soc_reg32_set(unit, MMU_RQE_REPL_PORT_AGG_MAPr, port, 0,
    291                     TH3_AGG_ID_HW_INVALID));
    292 
    293     return BCM_E_NONE;
    294 }
    295 
    296 STATIC void
    297 _bcm_th3_repl_list_recycle_candidate_deinit(int unit)
    298 {
    299     _bcm_repl_list_info_t *rli_current, *rli_free;
    300     rli_current = _repl_list_recycle_array[unit];
    301     while(rli_current != NULL) {
    302         rli_free = rli_current;
    303         rli_current = rli_current->next;
    304         sal_free(rli_free);
    305     }
    306     _repl_list_recycle_array[unit] = NULL;
    307 }
    308 
    309 STATIC int
    310 _bcm_th3_repl_list_hw_in_use_check(int unit,
    311                                 SHR_BITDCL *entry_vec, int *in_use)
    312 {
    313 
    314     int i, j, list_ptr_used;
    315     uint32 entry_done, list_ptr;
    316     mmu_repl_state_tbl_entry_t entry;
    317     soc_mem_t repl_q_mem[] = {MMU_REPL_STATE_TBL_ITM0m, MMU_REPL_STATE_TBL_ITM1m};
    318     soc_info_t *si = &SOC_INFO(unit);
    319     uint32 itm_map = si->itm_map;
    320 
    321     for(i = 0; i < NUM_ITM(unit); i++) {
    322         if (itm_map & (1U << i)) {
    323             for(j = 0; j < _TH3_NUM_REPL_QUEUE; j++) {
    324                 list_ptr_used = 0;
    325                 SOC_IF_ERROR_RETURN(soc_mem_read(unit, repl_q_mem[i],
    326                                 MEM_BLOCK_ANY, j, &entry));
    327                 entry_done = soc_MMU_REPL_STATE_TBLm_field32_get(unit, &entry,
    328                                         ENTRY_DONEf);
    329                 if(entry_done) {
    330                     continue;
    331                 } else {
    332                     list_ptr = soc_MMU_REPL_STATE_TBLm_field32_get(unit,
    333                                                         &entry, LIST_PTRf);
    334                     if(SHR_BITGET(entry_vec, list_ptr)) {
    335                         list_ptr_used = 1;
    336                     }
    337 
    338                 }
    339                 if(list_ptr_used) {
    340                     *in_use = list_ptr_used;
    341                     return BCM_E_NONE;
    342                 }
    343             }
    344         }
    345     }
    346     *in_use = 0;
    347     return BCM_E_NONE;
    348 }
    349 
    350 STATIC int
    351 _bcm_th3_repl_list_entry_vec_construct(int unit, SHR_BITDCL *entry_vec,
    352                                             int start_ptr)
    353 {
    354     int prev_repl_entry_ptr, repl_entry_ptr;
    355     soc_mem_t repl_list_table;
    356     mmu_repl_list_tbl_entry_t repl_list_entry;
    357 
    358     prev_repl_entry_ptr = -1;
    359     repl_entry_ptr = start_ptr;
    360     repl_list_table = MMU_REPL_LIST_TBLm;
    361     /* get the entry vector based on the current candidate list */
    362     while (repl_entry_ptr != prev_repl_entry_ptr) {
    363         SHR_BITSET(entry_vec, repl_entry_ptr);
    364         SOC_IF_ERROR_RETURN
    365             (soc_mem_read(unit, repl_list_table, MEM_BLOCK_ANY,
    366                           repl_entry_ptr, &repl_list_entry));
    367 
    368         prev_repl_entry_ptr = repl_entry_ptr;
    369         repl_entry_ptr = soc_MMU_REPL_LIST_TBLm_field32_get(unit,
    370                 &repl_list_entry, NEXTPTRf);
    371     }
    372     return BCM_E_NONE;
    373 
    374 }
    375 
    376 STATIC int
    377 _bcm_th3_repl_list_recycle(int unit, int *entry_id)
    378 {
    379 
    380     _bcm_repl_list_info_t *rli_current, *rli_prev;
    381     int in_use;
    382 
    383     rli_current = _repl_list_recycle_array[unit]->next;
    384     rli_prev = NULL;
    385     while (rli_current != NULL) {
    386 
    387         SHR_BITDCL entry_vec[_TH3_REPL_LIST_ENTRY_UINT32_TOTAL] = {0};
    388 
    389         /* get the entry vector based on the current candidate list */
    390         BCM_IF_ERROR_RETURN
    391             (_bcm_th3_repl_list_entry_vec_construct(unit, entry_vec,
    392                                                rli_current->index));
    393 
    394         /* check if this list is still being used by HW */
    395         SOC_IF_ERROR_RETURN(_bcm_th3_repl_list_hw_in_use_check
    396                                 (unit, entry_vec, &in_use));
    397         if(!in_use) {
    398             /* recycle list */
    399             SOC_IF_ERROR_RETURN(_bcm_th_repl_list_free(unit, 0,
    400                             rli_current->index));
    401             *entry_id = rli_current->index;
    402             if(rli_prev == NULL) {
    403                 _repl_list_recycle_array[unit]->next = rli_current->next;
    404             } else {
    405                 rli_prev->next = rli_current->next;
    406             }
    407             (_repl_list_recycle_array[unit]->list_size)--;
    408             sal_free(rli_current);
    409             return BCM_E_NONE;
    410         }
    411         rli_prev = rli_current;
    412         rli_current = rli_current->next;
    413     }
    414     *entry_id = -1;
    415     return BCM_E_RESOURCE;
    416 }
    417 /*
    418  * Function:
    419  *      _bcm_th3_repl_head_info_init
    420  * Purpose:
    421  *      Initialize replication head info.
    422  * Parameters:
    423  *      unit - (IN)SOC unit number.
    424  * Returns:
    425  *      BCM_E_xxx
    426  */
    427 STATIC int
    428 _bcm_th3_repl_head_info_init(int unit)
    429 {
    430     int alloc_size;
    431     int repl_head_tbl_size;
    432     int max_array_index = 0;
    433     soc_mem_t repl_head_table = MMU_REPL_HEAD_TBLm;
    434 
    435 
    436     mmu_port_stride[unit] = SOC_TH3_MMU_PORT_STRIDE;
    437 
    438     /* REPL_HEAD table is pipeline independent */
    439     alloc_size = sizeof(_th_repl_head_info_t);
    440     if (NULL == _th_repl_head_info[unit]) {
    441         _th_repl_head_info[unit] = sal_alloc(alloc_size, "repl_head_info");
    442         if (NULL == _th_repl_head_info[unit]) {
    443             _bcm_th_repl_head_info_deinit(unit);
    444             return BCM_E_MEMORY;
    445         }
    446     }
    447     sal_memset(_th_repl_head_info[unit], 0, alloc_size);
    448 
    449 
    450     if (NULL == _th_repl_head_info[unit][0].free_list_array) {
    451         /* Each element of the array is a linked list of free blocks.
    452          * Array element N is a linked list of free blocks of size N.
    453          * When allocating a block of REPL_HEAD table entries, the max
    454          * number of entries needed is equal to the max number of members
    455          * in a replication group. This will also be the max index of the
    456          * array. Of course, the REPL_HEAD table may contain bigger blocks
    457          * of free entries. Array element 0 wil be a linked list of free
    458          * blocks with size greater than the max number of members in a
    459          * replication group.
    460          */
    461         max_array_index = soc_mem_field_length(unit,
    462                 MMU_REPL_GROUP_INFO_TBLm, MEMBER_BMPf);
    463         alloc_size = (max_array_index + 1) *
    464             sizeof(_th_repl_head_free_block_t *);
    465         _th_repl_head_info[unit][0].free_list_array =
    466             sal_alloc(alloc_size, "repl head free list array");
    467         if (NULL == _th_repl_head_info[unit][0].free_list_array) {
    468             _bcm_th_repl_head_info_deinit(unit);
    469             return BCM_E_MEMORY;
    470         }
    471         _th_repl_head_info[unit][0].array_size = max_array_index + 1;
    472     }
    473     sal_memset(_th_repl_head_info[unit][0].free_list_array, 0,
    474             alloc_size);
    475 
    476     REPL_HEAD_FREE_LIST(unit, 0, 0) =
    477         sal_alloc(sizeof(_th_repl_head_free_block_t), "repl head free block");
    478     if (NULL == REPL_HEAD_FREE_LIST(unit, 0, 0)) {
    479         _bcm_th_repl_head_info_deinit(unit);
    480         return BCM_E_MEMORY;
    481     }
    482 
    483     /* Initially, there is only one free block, starting at entry 1 of
    484      * REPL_HEAD table and ending at the last entry. Entry 0 is reserved.
    485      */
    486     REPL_HEAD_FREE_LIST(unit, 0, 0)->index = 1;
    487     repl_head_tbl_size = 1 << soc_mem_field_length(unit,
    488             MMU_REPL_GROUP_INFO_TBLm, BASE_PTRf);
    489     REPL_HEAD_FREE_LIST(unit, 0, 0)->size = repl_head_tbl_size - 1;
    490     REPL_HEAD_FREE_LIST(unit, 0, 0)->next = NULL;
    491 
    492     /* Clear entry 0 of REPL_HEAD table */
    493     SOC_IF_ERROR_RETURN
    494         (soc_mem_write(unit, repl_head_table, MEM_BLOCK_ALL, 0,
    495                        soc_mem_entry_null(unit, repl_head_table)));
    496 
    497     return BCM_E_NONE;
    498 }
    499 
    500 STATIC int
    501 _bcm_th3_repl_list_compare(int unit, int pipe, int start_ptr,
    502                           SHR_BITDCL *intf_vec)
    503 {
    504 
    505     soc_mem_t   repl_list_table;
    506     uint32  hw_msb;
    507     uint32  hw_ls_bits[2];
    508     mmu_repl_list_tbl_entry_t repl_list_entry;
    509     int i, repl_entry_ptr, prev_repl_entry_ptr;
    510     SHR_BITDCL *hw_intf_vec = NULL;
    511     int alloc_size;
    512     int max_msb = -1;
    513     uint32 repl_mode, mode_bitmap;
    514     soc_field_t nh_fields[_TH3_NUM_NH_SPARSE_MODE] = {
    515                                 NEXT_HOP_INDEX_0f, NEXT_HOP_INDEX_1f,
    516                                 NEXT_HOP_INDEX_2f, NEXT_HOP_INDEX_3f
    517                                };
    518     repl_list_table = MMU_REPL_LIST_TBLm;
    519     prev_repl_entry_ptr = -1;
    520     repl_entry_ptr = start_ptr;
    521 
    522     alloc_size = SHR_BITALLOCSIZE(REPL_INTF_TOTAL(unit));
    523     hw_intf_vec = sal_alloc(alloc_size, "HW repl interface vector");
    524     if(hw_intf_vec == NULL) {
    525         return BCM_E_MEMORY;
    526     }
    527     if(start_ptr < 0 ) {
    528         return BCM_E_PARAM;
    529     }
    530     sal_memset(hw_intf_vec, 0, alloc_size);
    531     /* first read out the entire repl list */
    532     while(repl_entry_ptr != prev_repl_entry_ptr) {
    533         SOC_IF_ERROR_RETURN
    534                 (soc_mem_read(unit, repl_list_table, MEM_BLOCK_ANY,
    535                               repl_entry_ptr, &repl_list_entry));
    536         repl_mode = soc_MMU_REPL_LIST_TBLm_field32_get(unit,
    537                     &repl_list_entry, MODEf);
    538         if(repl_mode) {
    539             /* sparse mode */
    540             mode_bitmap = soc_MMU_REPL_LIST_TBLm_field32_get(unit,
    541                     &repl_list_entry, MODE_1_BITMAPf);
    542             for(i = 0; i < _TH3_NUM_NH_SPARSE_MODE; i++) {
    543                 if(mode_bitmap & (1U << i)) {
    544                     uint32 temp_nh = soc_MMU_REPL_LIST_TBLm_field32_get(unit,
    545                                         &repl_list_entry, nh_fields[i]);
    546                     SHR_BITSET(hw_intf_vec, temp_nh);
    547                     max_msb = (max_msb > (temp_nh / 64)) ? max_msb :
    548                                             (temp_nh / 64);
    549                 }
    550             }
    551         } else {
    552             /* dense mode */
    553             hw_msb = soc_MMU_REPL_LIST_TBLm_field32_get(unit,
    554                                         &repl_list_entry, MSB_VLANf);
    555             max_msb = max_msb > hw_msb ? max_msb : hw_msb;
    556             soc_MMU_REPL_LIST_TBLm_field_get(unit, &repl_list_entry,
    557                     LSB_VLAN_BMf, hw_ls_bits);
    558             hw_intf_vec[2 * hw_msb + 0] |= hw_ls_bits[0];
    559             hw_intf_vec[2 * hw_msb + 1] |= hw_ls_bits[1];
    560         }
    561         prev_repl_entry_ptr = repl_entry_ptr;
    562         repl_entry_ptr = soc_MMU_REPL_LIST_TBLm_field32_get(unit,
    563                                             &repl_list_entry, NEXTPTRf);
    564 
    565     }
    566     /* compare two lists */
    567     for(i = 0; i < max_msb; i++) {
    568         if((hw_intf_vec[2 * i] != intf_vec[2 * i])
    569                 ||(hw_intf_vec[2 * i + 1] != intf_vec[2 * i + 1])) {
    570             return BCM_E_NOT_FOUND;
    571         }
    572     }
    573     return BCM_E_NONE;
    574 }
    575 
    576 /* return the pos of first bit 1 within an unsigned integer */
    577 STATIC int
    578 _bcm_th3_uint32_first_bit_get(int unit, uint32 val) {
    579     int i;
    580     for(i = 0; i < 32; i++) {
    581         if(val & (1U << i)) {
    582             return i;
    583         }
    584     }
    585     return -1;
    586 }
    587 
    588 STATIC void
    589 _bcm_th3_nh_list_get(int unit,  mmu_repl_list_tbl_entry_t *entry, int max_count,
    590         uint32 *nh_list, uint32 *count)
    591 {
    592     uint32 l_count = 0;
    593     uint32 ls_bits[2];
    594     uint32 msb, mode, mode_1_bm;
    595     int i, ls_pos;
    596     soc_field_t nh_fields[_TH3_NUM_NH_SPARSE_MODE] = {
    597                                 NEXT_HOP_INDEX_0f, NEXT_HOP_INDEX_1f,
    598                                 NEXT_HOP_INDEX_2f, NEXT_HOP_INDEX_3f
    599                                };
    600     mode = soc_MMU_REPL_LIST_TBLm_field32_get(unit, entry, MODEf);
    601     if(mode) {
    602         /* sparse mode */
    603         mode_1_bm = soc_MMU_REPL_LIST_TBLm_field32_get(unit, entry,
    604                                         MODE_1_BITMAPf);
    605         for(i = 0; i < _TH3_NUM_NH_SPARSE_MODE; i++) {
    606             if(mode_1_bm & (1U << i)) {
    607                 nh_list[l_count++] = soc_MMU_REPL_LIST_TBLm_field32_get
    608                                         (unit, entry, nh_fields[i]);
    609             }
    610             if(l_count >= max_count) {
    611                 break;
    612             }
    613         }
    614 
    615     } else {
    616         /* dense mode */
    617         soc_MMU_REPL_LIST_TBLm_field_get(unit, entry, LSB_VLAN_BMf, ls_bits);
    618         msb = soc_MMU_REPL_LIST_TBLm_field32_get(unit, entry,
    619                 MSB_VLANf);
    620         for (ls_pos = 0; ls_pos < 64; ls_pos++) {
    621             if (ls_bits[ls_pos / 32] & (1 << (ls_pos % 32))) {
    622 
    623                 nh_list[l_count++] = msb * 64 + ls_pos;
    624             }
    625             if(l_count >= max_count) {
    626                 break;
    627             }
    628         }
    629     }
    630     *count = l_count;
    631 }
    632 
    633 STATIC void
    634 _bcm_th3_ls_bit_pos_get(int unit, uint32 ls_bits[2], int *ls_bit_pos)
    635 {
    636     *ls_bit_pos = -1;
    637     if (ls_bits[0] != 0) {
    638         *ls_bit_pos = _bcm_th3_uint32_first_bit_get(unit,
    639                                         ls_bits[0]);
    640     }
    641     else if (ls_bits[1] != 0) {
    642         *ls_bit_pos = _TH3_IPMC_UINT32_LEN
    643                 + _bcm_th3_uint32_first_bit_get(unit,
    644                                             ls_bits[1]);
    645     }
    646 }
    647 /*
    648  * Function:
    649  *  _bcm_th3_repl_list_write
    650  * Purpose:
    651  *  Write the replication list contained in intf_vec into REPL_LIST table.
    652  *      Return the start_ptr and total interface count.
    653  * Parameters:
    654  *  unit       - StrataSwitch PCI device unit number.
    655  *  pipe       - Pipeline number.
    656  *  start_ptr  - (OUT) Replication list's start pointer to
    657  *	             REPL_LIST table.
    658  *      intf_count - (OUT) Interface count.
    659  *  intf_vec   - (IN) Vector of interfaces.
    660  * Returns:
    661  *  BCM_E_XXX
    662  */
    663 STATIC int
    664 _bcm_th3_repl_list_write(int unit, int pipe, int *start_ptr, int *intf_count,
    665                         SHR_BITDCL *intf_vec)
    666 {
    667     int i;
    668     int remaining_count;
    669     int prev_repl_entry_ptr, repl_entry_ptr;
    670     uint32 msb_max, msb;
    671     uint32 ls_bits[2];
    672     int rv = BCM_E_NONE;
    673     int no_more_free_repl_entries;
    674     mmu_repl_list_tbl_entry_t repl_list_entry;
    675     soc_mem_t repl_list_table;
    676     int max_rem_count = 31;
    677     int ls_bit_pos, nh_id;
    678     uint32 nh_list[_TH3_IPMC_MIN_INTF_COUNT];
    679     uint32 prev_count = 0;
    680     soc_field_t nh_fields[_TH3_NUM_NH_SPARSE_MODE] = {
    681                                 NEXT_HOP_INDEX_0f, NEXT_HOP_INDEX_1f,
    682                                 NEXT_HOP_INDEX_2f, NEXT_HOP_INDEX_3f
    683                                };
    684 
    685     *intf_count = 0;
    686     for (i = 0; i < _SHR_BITDCLSIZE(REPL_INTF_TOTAL(unit)); i++) {
    687         *intf_count += _shr_popcount(intf_vec[i]);
    688     }
    689 
    690     if (*intf_count == 0) {
    691         return BCM_E_NONE;
    692     }
    693     repl_list_table = MMU_REPL_LIST_TBLm;
    694     pipe = 0;
    695     remaining_count = *intf_count;
    696     prev_repl_entry_ptr = -1;
    697     msb_max = _SHR_BITDCLSIZE(REPL_INTF_TOTAL(unit)) / 2; /* 32 -> 64 */
    698     for (msb = 0; msb < msb_max; msb++) {
    699         ls_bits[0] = intf_vec[2 * msb + 0];
    700         ls_bits[1] = intf_vec[2 * msb + 1];
    701         if ((ls_bits[0] != 0) || (ls_bits[1] != 0)) {
    702             rv = _bcm_th_repl_list_entry_alloc(unit, pipe, &repl_entry_ptr);
    703             if (rv == BCM_E_RESOURCE) {
    704                 no_more_free_repl_entries = TRUE;
    705             } else if (BCM_FAILURE(rv)) {
    706                 return rv;
    707             } else {
    708                 no_more_free_repl_entries = FALSE;
    709             }
    710             if (prev_repl_entry_ptr == -1) {
    711                 if (no_more_free_repl_entries) {
    712                     return BCM_E_RESOURCE;
    713                 }
    714                 *start_ptr = repl_entry_ptr;
    715             } else {
    716                 if (no_more_free_repl_entries) {
    717                     /* Terminate replication list */
    718                     soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry,
    719                             NEXTPTRf, prev_repl_entry_ptr);
    720                 } else {
    721                     /* check the intf count in the previous list */
    722                     uint32 mode_bitmap = 0;
    723                     _bcm_th3_nh_list_get(unit, &repl_list_entry,
    724                             _TH3_IPMC_MIN_INTF_COUNT, nh_list, &prev_count);
    725 
    726                     if (prev_count < _TH3_IPMC_MIN_INTF_COUNT) {
    727                         /* convert to sparse mode  when count < 4 */
    728                         /* rewrite previous entry */
    729                         for(i = 0; i < prev_count; i++) {
    730                             soc_MMU_REPL_LIST_TBLm_field32_set(unit,
    731                                  &repl_list_entry, nh_fields[i], nh_list[i]);
    732                             mode_bitmap |= (1U << i);
    733                         }
    734                         /*  borrow NH ids from the current list */
    735                         for(i = prev_count; i < _TH3_NUM_NH_SPARSE_MODE; i++) {
    736                             _bcm_th3_ls_bit_pos_get(unit, ls_bits, &ls_bit_pos);
    737                             if(ls_bit_pos == -1) {
    738                                 /* no more NH id in the current list */
    739                                 break;
    740                             }
    741                             nh_id = msb * TH3_IPMC_MAX_INTF_COUNT_PER_ENTRY
    742                                                             + ls_bit_pos;
    743 
    744                             mode_bitmap |= (1U << i);
    745                             soc_MMU_REPL_LIST_TBLm_field32_set(unit,
    746                                  &repl_list_entry, nh_fields[i], nh_id);
    747                             /* remove borrowed NH id from current lists */
    748                             ls_bits[ls_bit_pos / 32] &=
    749                                                 ~(1U << (ls_bit_pos % 32));
    750 
    751                         }
    752 
    753                         soc_MMU_REPL_LIST_TBLm_field32_set(unit,
    754                                  &repl_list_entry, MODE_1_BITMAPf, mode_bitmap);
    755                         soc_MMU_REPL_LIST_TBLm_field32_set(unit,
    756                                  &repl_list_entry, MODEf, 0x1);
    757                         /*update remaining count */
    758                         remaining_count = remaining_count - (i - prev_count);
    759                         if ( remaining_count > max_rem_count) {
    760                         /* Set the RMNG_REPS field to all zeroes */
    761                              soc_MMU_REPL_LIST_TBLm_field32_set(unit,
    762                                         &repl_list_entry, RMNG_REPSf, 0);
    763                         } else if(remaining_count > 0){
    764                                 soc_MMU_REPL_LIST_TBLm_field32_set(unit,
    765                                         &repl_list_entry,
    766                                             RMNG_REPSf, remaining_count);
    767                         } else {
    768                             break;
    769                         }
    770                         if(i < _TH3_NUM_NH_SPARSE_MODE) {
    771                             /* no NH id in the current list */
    772                             _bcm_th_repl_list_entry_free(unit, pipe, repl_entry_ptr);
    773                             continue;
    774                         }
    775 
    776                     }
    777                     soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry,
    778                             NEXTPTRf, repl_entry_ptr);
    779 
    780                 }
    781                 SOC_IF_ERROR_RETURN
    782                     (soc_mem_write(unit, repl_list_table, MEM_BLOCK_ALL,
    783                                    prev_repl_entry_ptr, &repl_list_entry));
    784                 if (no_more_free_repl_entries) {
    785                     /* Free the list already written */
    786                     _bcm_th_repl_list_free(unit, pipe, *start_ptr);
    787                     return BCM_E_RESOURCE;
    788                 }
    789             }
    790             prev_repl_entry_ptr = repl_entry_ptr;
    791             sal_memset(&repl_list_entry, 0, sizeof(repl_list_entry));
    792             soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry,
    793                     MSB_VLANf, msb);
    794             soc_MMU_REPL_LIST_TBLm_field_set(unit, &repl_list_entry,
    795                     LSB_VLAN_BMf, ls_bits);
    796 
    797             remaining_count -= (_shr_popcount(ls_bits[0]) +
    798                     _shr_popcount(ls_bits[1]));
    799             if (remaining_count > max_rem_count) {
    800                 /* Set the RMNG_REPS field to all zeroes */
    801                 soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry,
    802                         RMNG_REPSf, 0);
    803             } else if (remaining_count > 0) {
    804                 soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry,
    805                         RMNG_REPSf, remaining_count);
    806             } else { /* No more intefaces left to be written */
    807                 break;
    808             }
    809         }
    810     }
    811 
    812     if (prev_repl_entry_ptr > 0) {
    813         /* Write final entry */
    814         soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry, NEXTPTRf,
    815                 prev_repl_entry_ptr);
    816         SOC_IF_ERROR_RETURN
    817             (soc_mem_write(unit, repl_list_table, MEM_BLOCK_ALL,
    818                            prev_repl_entry_ptr, &repl_list_entry));
    819     }
    820 
    821     return BCM_E_NONE;
    822 }
    823 
    824 STATIC int
    825 _bcm_th3_sparse_mode_egress_intf_get(int unit, int repl_entry_ptr,
    826                                 int nh_id, bcm_if_t *if_array, int *if_count)
    827 {
    828     soc_mem_t mem = MMU_REPL_LIST_TBLm;
    829     int entry_type;
    830     uint32 mode_bitmap, nh_val, l3_intf;
    831     mmu_repl_list_tbl_entry_t repl_list_entry;
    832     egr_l3_next_hop_2_entry_t egr_nh2;
    833     egr_l3_next_hop_entry_t egr_nh;
    834     soc_field_t nh_fields[4] = {NEXT_HOP_INDEX_0f, NEXT_HOP_INDEX_1f,
    835                                 NEXT_HOP_INDEX_2f, NEXT_HOP_INDEX_3f};
    836 
    837     SOC_IF_ERROR_RETURN
    838         (soc_mem_read(unit, mem, MEM_BLOCK_ANY,
    839                           repl_entry_ptr, &repl_list_entry));
    840 
    841     mode_bitmap = soc_MMU_REPL_LIST_TBLm_field32_get(unit,
    842                             &repl_list_entry, MODE_1_BITMAPf);
    843     if(mode_bitmap & (1U << nh_id)) {
    844         nh_val = soc_MMU_REPL_LIST_TBLm_field32_get(unit,
    845                     &repl_list_entry, nh_fields[nh_id]);
    846         if_array[*if_count] = nh_val + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
    847 
    848         SOC_IF_ERROR_RETURN(
    849                 READ_EGR_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY,
    850                                 nh_val, &egr_nh));
    851         entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit,
    852                             &egr_nh, ENTRY_TYPEf);
    853 
    854         SOC_IF_ERROR_RETURN(
    855                     READ_EGR_L3_NEXT_HOP_2m(unit, MEM_BLOCK_ANY,
    856                                             nh_val, &egr_nh2));
    857 
    858         l3_intf = soc_EGR_L3_NEXT_HOP_2m_field32_get(unit,
    859                         &egr_nh2, INTF_NUMf);
    860         if(entry_type == 0) {
    861             if (REPL_L3_INTF_NEXT_HOP_TRILL(unit, l3_intf) ==
    862                                 nh_val) {
    863                     if_array[*if_count] = l3_intf;
    864             }
    865         } else if (entry_type == 3) {
    866 
    867             if (REPL_L3_INTF_NEXT_HOP_IPMC(unit, l3_intf) == nh_val) {
    868                 if_array[*if_count] = l3_intf;
    869             }
    870 
    871         }
    872         (*if_count)++;
    873     }
    874 
    875     return BCM_E_NONE;
    876 }
    877 
    878 STATIC int
    879 _bcm_th3_ipmc_egress_intf_add_for_trunk(int unit, int repl_group,
    880     bcm_trunk_t tgid, int encap_id, int is_l3)
    881 {
    882 #if defined(BCM_ESW_SUPPORT) && (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS)
    883     bcm_port_t      trunk_local_member_ports[SOC_MAX_NUM_PP_PORTS] = {0};
    884     int             max_num_ports = SOC_MAX_NUM_PP_PORTS;
    885 #else
    886     bcm_port_t      trunk_local_member_ports[SOC_MAX_NUM_PORTS] = {0};
    887     int             max_num_ports = SOC_MAX_NUM_PORTS;
    888 #endif
    889 
    890     int idx;
    891     int member_count, port_iter;
    892     int aggid;
    893     int old_intf_count, new_intf_count, diff_count = 0;
    894     BCM_IF_ERROR_RETURN(
    895         _bcm_esw_trunk_local_members_get(unit, tgid, max_num_ports,
    896                                          trunk_local_member_ports,
    897                                          &member_count));
    898 
    899     for (idx = 0; idx < member_count; idx++) {
    900         port_iter = trunk_local_member_ports[idx];
    901         if (REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group) == 0) {
    902             BCM_IF_ERROR_RETURN(
    903                 bcm_th_port_aggid_add(unit, port_iter, tgid, &aggid));
    904         }
    905         old_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group);
    906 
    907         if(idx == 0) {
    908             /* all ports within the trunk should mapped to the same AGG_ID
    909              * encap ID only needs to be inserted once
    910  */
    911             BCM_IF_ERROR_RETURN(
    912                 _bcm_th_ipmc_egress_intf_add(
    913                     unit, repl_group, port_iter, encap_id, is_l3));
    914             new_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group);
    915             diff_count = new_intf_count - old_intf_count;
    916         } else {
    917             new_intf_count = old_intf_count + diff_count;
    918             REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group) =
    919                                                         new_intf_count;
    920         }
    921 
    922      }
    923 
    924     return BCM_E_NONE;
    925 }
    926 
    927 STATIC int
    928 _bcm_th3_ipmc_egress_intf_del_for_trunk(int unit, int repl_group,
    929     bcm_trunk_t tgid, int if_max, int encap_id, int is_l3)
    930 {
    931 #if defined(BCM_ESW_SUPPORT) && (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS)
    932     bcm_port_t      trunk_local_member_ports[SOC_MAX_NUM_PP_PORTS] = {0};
    933     int             max_num_ports = SOC_MAX_NUM_PP_PORTS;
    934 #else
    935     bcm_port_t      trunk_local_member_ports[SOC_MAX_NUM_PORTS] = {0};
    936     int             max_num_ports = SOC_MAX_NUM_PORTS;
    937 #endif
    938 
    939     int idx;
    940     int member_count, port_iter;
    941     int old_intf_count, new_intf_count, diff_count = 0;
    942 
    943     BCM_IF_ERROR_RETURN(
    944         _bcm_esw_trunk_local_members_get(unit, tgid, max_num_ports,
    945                                          trunk_local_member_ports,
    946                                          &member_count));
    947 
    948     for (idx = 0; idx < member_count; idx++) {
    949         port_iter = trunk_local_member_ports[idx];
    950         old_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group);
    951         if (idx == 0) {
    952             BCM_IF_ERROR_RETURN(
    953                 _bcm_th_ipmc_egress_intf_delete(
    954                      unit, repl_group, trunk_local_member_ports[idx],
    955                      if_max, encap_id, is_l3));
    956             new_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group);
    957             diff_count = old_intf_count - new_intf_count;
    958         } else {
    959             new_intf_count = old_intf_count - diff_count;
    960             REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group) =
    961                                                             new_intf_count;
    962         }
    963         if (new_intf_count == 0 && old_intf_count > 0) {
    964                 BCM_IF_ERROR_RETURN(
    965                     bcm_th_port_aggid_del(unit, port_iter));
    966         }
    967 
    968     }
    969 
    970     return BCM_E_NONE;
    971 }
    972 
    973 STATIC int
    974 _bcm_th3_ipmc_egress_intf_set_for_same_trunk_member(
    975     int unit, int repl_group, bcm_port_t port,
    976     bcm_port_t first_port, bcm_trunk_t tgid)
    977 {
    978     int aggid;
    979     int old_intf_count, new_intf_count;
    980 
    981     old_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group);
    982     new_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, first_port, repl_group);
    983     if (old_intf_count == new_intf_count) {
    984         return BCM_E_NONE;
    985     }
    986 
    987     if ((old_intf_count == 0) && (new_intf_count > 0)) {
    988         BCM_IF_ERROR_RETURN(bcm_th_port_aggid_add(unit, port, tgid, &aggid));
    989     } else if ((old_intf_count > 0) && (new_intf_count == 0)) {
    990         BCM_IF_ERROR_RETURN(bcm_th_port_aggid_del(unit, port));
    991     }
    992 
    993     REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group) = new_intf_count;
    994 
    995     return BCM_E_NONE;
    996 }
    997 #endif
    998 
    999 /* --------------------------------------------------------------
   1000  * The following set of routines manage REPL_HEAD table resource.
   1001  * --------------------------------------------------------------
   1002  */
   1003 
   1004 /*
   1005  * Function:
   1006  *      _bcm_th_repl_head_info_deinit
   1007  * Purpose:
   1008  *      De-initialize replication head info.
   1009  * Parameters:
   1010  *      unit - (IN)SOC unit number. 
   1011  * Returns:
   1012  *      None
   1013  */
   1014 STATIC void 
   1015 _bcm_th_repl_head_info_deinit(int unit)
   1016 {
   1017     int pipe, i;
   1018     _th_repl_head_free_block_t *block_ptr;
   1019     _th_repl_head_free_block_t *next_block_ptr;
   1020 
   1021     if (NULL != _th_repl_head_info[unit]) {
   1022         for (pipe = 0; pipe < NUM_PIPES(unit); pipe++) {
   1023             if (NULL != _th_repl_head_info[unit][pipe].free_list_array) {
   1024                 for (i = 0; i < _th_repl_head_info[unit][pipe].array_size; i++) {
   1025                     block_ptr = REPL_HEAD_FREE_LIST(unit, pipe, i);
   1026                     while (NULL != block_ptr) {
   1027                         next_block_ptr = block_ptr->next;
   1028                         sal_free(block_ptr);
   1029                         block_ptr = next_block_ptr;
   1030                     }
   1031                     REPL_HEAD_FREE_LIST(unit, pipe, i) = NULL;
   1032                 }
   1033                 sal_free(_th_repl_head_info[unit][pipe].free_list_array);
   1034                 _th_repl_head_info[unit][pipe].free_list_array = NULL;
   1035                 _th_repl_head_info[unit][pipe].array_size = 0;
   1036             }
   1037 
   1038         }
   1039         sal_free(_th_repl_head_info[unit]);
   1040         _th_repl_head_info[unit] = NULL;
   1041     }
   1042 }
   1043 
   1044 /*
   1045  * Function:
   1046  *      _bcm_th_repl_head_info_init
   1047  * Purpose:
   1048  *      Initialize replication head info.
   1049  * Parameters:
   1050  *      unit - (IN)SOC unit number. 
   1051  * Returns:
   1052  *      BCM_E_xxx
   1053  */
   1054 STATIC int 
   1055 _bcm_th_repl_head_info_init(int unit)
   1056 {
   1057     int alloc_size;
   1058     int pipe;
   1059     int max_array_index = 0;
   1060     int per_pipe_repl_head_tbl_size; 
   1061     soc_mem_t repl_head_table;
   1062 
   1063 #ifdef BCM_TRIDENT3_SUPPORT
   1064     if (SOC_IS_TRIDENT3X(unit)) {
   1065         mmu_port_stride[unit] = _TD3_TDM_MMU_PORTS_PER_DEV;
   1066     } else
   1067 #endif /* BCM_TRIDENT3_SUPPORT */
   1068     {
   1069         mmu_port_stride[unit] = SOC_TH_MMU_PORT_STRIDE;
   1070     }
   1071 
   1072     /* Each pipeline has its own REPL_HEAD table. */
   1073     alloc_size = NUM_PIPES(unit) * sizeof(_th_repl_head_info_t);
   1074     if (NULL == _th_repl_head_info[unit]) {
   1075         _th_repl_head_info[unit] = sal_alloc(alloc_size, "repl_head_info");
   1076         if (NULL == _th_repl_head_info[unit]) {
   1077             _bcm_th_repl_head_info_deinit(unit);
   1078             return BCM_E_MEMORY;
   1079         }
   1080     }
   1081     sal_memset(_th_repl_head_info[unit], 0, alloc_size);
   1082 
   1083     for (pipe = 0; pipe < NUM_PIPES(unit); pipe++) {
   1084 
   1085         if (NULL == _th_repl_head_info[unit][pipe].free_list_array) {
   1086             /* Each element of the array is a linked list of free blocks.
   1087              * Array element N is a linked list of free blocks of size N.
   1088              * When allocating a block of REPL_HEAD table entries, the max
   1089              * number of entries needed is equal to the max number of members
   1090              * in a replication group. This will also be the max index of the
   1091              * array. Of course, the REPL_HEAD table may contain bigger blocks
   1092              * of free entries. Array element 0 wil be a linked list of free
   1093              * blocks with size greater than the max number of members in a
   1094              * replication group.
   1095              */ 
   1096             max_array_index = soc_mem_field_length(unit,
   1097                     MMU_REPL_GROUP_INFO_TBLm, PIPE_MEMBER_BMPf);
   1098             alloc_size = (max_array_index + 1) *
   1099                 sizeof(_th_repl_head_free_block_t *);
   1100             _th_repl_head_info[unit][pipe].free_list_array =
   1101                 sal_alloc(alloc_size, "repl head free list array");
   1102             if (NULL == _th_repl_head_info[unit][pipe].free_list_array) {
   1103                 _bcm_th_repl_head_info_deinit(unit);
   1104                 return BCM_E_MEMORY;
   1105             }
   1106             _th_repl_head_info[unit][pipe].array_size = max_array_index + 1;
   1107         }
   1108         sal_memset(_th_repl_head_info[unit][pipe].free_list_array, 0,
   1109                 alloc_size);
   1110 
   1111         REPL_HEAD_FREE_LIST(unit, pipe, 0) = 
   1112             sal_alloc(sizeof(_th_repl_head_free_block_t), "repl head free block");
   1113         if (NULL == REPL_HEAD_FREE_LIST(unit, pipe, 0)) {
   1114             _bcm_th_repl_head_info_deinit(unit);
   1115             return BCM_E_MEMORY;
   1116         }
   1117 
   1118         /* Initially, there is only one free block, starting at entry 1 of 
   1119          * REPL_HEAD table and ending at the last entry. Entry 0 is reserved.
   1120          */
   1121         REPL_HEAD_FREE_LIST(unit, pipe, 0)->index = 1;
   1122         per_pipe_repl_head_tbl_size = 1 << soc_mem_field_length(unit,
   1123                 MMU_REPL_GROUP_INFO_TBLm, PIPE_BASE_PTRf);
   1124         REPL_HEAD_FREE_LIST(unit, pipe, 0)->size =
   1125             per_pipe_repl_head_tbl_size - 1;
   1126         REPL_HEAD_FREE_LIST(unit, pipe, 0)->next = NULL;
   1127 
   1128         if (soc_feature(unit, soc_feature_split_repl_head_table)) {
   1129             repl_head_table = REPL_HEAD_TBL_SPLIT_PIPE(unit, 0, pipe);
   1130             SOC_IF_ERROR_RETURN
   1131                 (soc_mem_write(unit, repl_head_table, MEM_BLOCK_ALL, 0,
   1132                                soc_mem_entry_null(unit, repl_head_table)));
   1133             repl_head_table = REPL_HEAD_TBL_SPLIT_PIPE(unit, 1, pipe);
   1134             SOC_IF_ERROR_RETURN
   1135                 (soc_mem_write(unit, repl_head_table, MEM_BLOCK_ALL, 0,
   1136                                soc_mem_entry_null(unit, repl_head_table)));
   1137 
   1138         } else {
   1139             repl_head_table = REPL_HEAD_TBL_PIPE(unit, pipe);
   1140             /* Clear entry 0 of REPL_HEAD table */
   1141             SOC_IF_ERROR_RETURN
   1142                 (soc_mem_write(unit, repl_head_table, MEM_BLOCK_ALL, 0,
   1143                                soc_mem_entry_null(unit, repl_head_table)));
   1144         }
   1145     }
   1146 
   1147     return BCM_E_NONE;
   1148 }
   1149 
   1150 /*
   1151  * Function:
   1152  *      _bcm_th_repl_head_block_free
   1153  * Purpose:
   1154  *      Free a block of REPL_HEAD table entries.
   1155  * Parameters:
   1156  *      unit  - (IN) SOC unit number. 
   1157  *      pipe  - (IN) Pipeline number. 
   1158  *      index - (IN) Index of the first entry of the block.
   1159  *      size  - (IN) Size of the block.
   1160  * Returns:
   1161  *      BCM_E_xxx
   1162  */
   1163 STATIC int 
   1164 _bcm_th_repl_head_block_free(int unit, int pipe, int index, int size)
   1165 {
   1166     int i;
   1167     int block_index, block_size;
   1168     int coalesced_index, coalesced_size;
   1169     _th_repl_head_free_block_t *block_ptr;
   1170     _th_repl_head_free_block_t *prev_block_ptr;
   1171     _th_repl_head_free_block_t *next_block_ptr;
   1172     _th_repl_head_free_block_t *coalesced_block_ptr;
   1173 
   1174     if (size <= 0) {
   1175         return BCM_E_INTERNAL;
   1176     }
   1177 
   1178     /* First, coalesce the block with any existing free blocks
   1179      * that are contiguous with the block.
   1180      */ 
   1181     coalesced_index = index;
   1182     coalesced_size = size;
   1183     for (i = 0; i < _th_repl_head_info[unit][pipe].array_size; i++) {
   1184         block_ptr = REPL_HEAD_FREE_LIST(unit, pipe, i);
   1185         prev_block_ptr = NULL;
   1186         while (NULL != block_ptr) {
   1187             block_index = block_ptr->index;
   1188             block_size = block_ptr->size;
   1189             next_block_ptr = block_ptr->next;
   1190             if ((block_index + block_size) == coalesced_index) {
   1191                 coalesced_index = block_index;
   1192                 coalesced_size += block_size;
   1193                 if (block_ptr == REPL_HEAD_FREE_LIST(unit, pipe, i)) {
   1194                     REPL_HEAD_FREE_LIST(unit, pipe, i) = next_block_ptr;
   1195                 } else {
   1196                     /* 
   1197                      * In the following line of code, Coverity thinks the
   1198                      * prev_block_ptr may still be NULL when dereferenced.
   1199                      * This situation will never occur because 
   1200                      * if block_ptr is not pointing to the head of the 
   1201                      * linked list, prev_block_ptr would not be NULL.
   1202                      */
   1203                     /* coverity[var_deref_op : FALSE] */
   1204                     prev_block_ptr->next = next_block_ptr;
   1205                 } 
   1206                 sal_free(block_ptr);
   1207             } else if ((coalesced_index + coalesced_size) == block_index) {
   1208                 coalesced_size += block_size;
   1209                 if (block_ptr == REPL_HEAD_FREE_LIST(unit, pipe, i)) {
   1210                     REPL_HEAD_FREE_LIST(unit, pipe, i) = next_block_ptr;
   1211                 } else {
   1212                     /* 
   1213                      * In the following line of code, Coverity thinks the
   1214                      * prev_block_ptr may still be NULL when dereferenced.
   1215                      * This situation will never occur because 
   1216                      * if block_ptr is not pointing to the head of the 
   1217                      * linked list, prev_block_ptr would not be NULL.
   1218                      */
   1219                     /* coverity[var_deref_op : FALSE] */
   1220                     prev_block_ptr->next = next_block_ptr;
   1221                 } 
   1222                 sal_free(block_ptr);
   1223             } else {
   1224                 prev_block_ptr = block_ptr;
   1225             }
   1226             block_ptr = next_block_ptr;
   1227         }
   1228     }
   1229 
   1230     /* Insert coalesced free block */
   1231     coalesced_block_ptr = sal_alloc(sizeof(_th_repl_head_free_block_t),
   1232             "coalesced repl head free block");
   1233     if (NULL == coalesced_block_ptr) {
   1234         return BCM_E_MEMORY;
   1235     }
   1236     coalesced_block_ptr->index = coalesced_index;
   1237     coalesced_block_ptr->size = coalesced_size;
   1238     if (coalesced_size > (_th_repl_head_info[unit][pipe].array_size - 1)) {
   1239         /* Insert into free list 0 */
   1240         coalesced_block_ptr->next = REPL_HEAD_FREE_LIST(unit, pipe, 0);
   1241         REPL_HEAD_FREE_LIST(unit, pipe, 0) = coalesced_block_ptr;
   1242     } else {
   1243         coalesced_block_ptr->next = REPL_HEAD_FREE_LIST(unit, pipe,
   1244                 coalesced_size);
   1245         REPL_HEAD_FREE_LIST(unit, pipe, coalesced_size) = coalesced_block_ptr;
   1246     }
   1247 
   1248     return BCM_E_NONE;
   1249 }
   1250 
   1251 /*
   1252  * Function:
   1253  *      _bcm_th_repl_head_block_alloc
   1254  * Purpose:
   1255  *      Allocate a free block of REPL_HEAD table entries.
   1256  * Parameters:
   1257  *      unit - (IN) SOC unit number. 
   1258  *      pipe - (IN) Pipeline number. 
   1259  *      size - (IN) Size of free block requested.
   1260  *      index - (OUT) Index of the first entry of the free block.
   1261  * Returns:
   1262  *      BCM_E_xxx
   1263  */
   1264 STATIC int 
   1265 _bcm_th_repl_head_block_alloc(int unit, int pipe, int size, int *index)
   1266 {
   1267     int max_array_index;
   1268     int i;
   1269     int block_index, block_size;
   1270     _th_repl_head_free_block_t *next_block_ptr;
   1271 
   1272     if (size == 0) {
   1273         return BCM_E_PARAM;
   1274     }
   1275     if (NULL == index) {
   1276         return BCM_E_PARAM;
   1277     }
   1278 
   1279     max_array_index = _th_repl_head_info[unit][pipe].array_size - 1;
   1280     for (i = size; i <= max_array_index; i++) {
   1281         if (NULL != REPL_HEAD_FREE_LIST(unit, pipe, i)) {
   1282            block_index = REPL_HEAD_FREE_LIST(unit, pipe, i)->index; 
   1283            block_size = REPL_HEAD_FREE_LIST(unit, pipe, i)->size; 
   1284            next_block_ptr = REPL_HEAD_FREE_LIST(unit, pipe, i)->next; 
   1285            sal_free(REPL_HEAD_FREE_LIST(unit, pipe, i));
   1286            REPL_HEAD_FREE_LIST(unit, pipe, i) = next_block_ptr;
   1287 
   1288            /* If the obtained free block contains more entries
   1289             * than requested, insert the remainder back into
   1290             * the free list array.
   1291             */
   1292            if (block_size > size) {
   1293                BCM_IF_ERROR_RETURN(_bcm_th_repl_head_block_free(unit,
   1294                            pipe, block_index + size, block_size - size));
   1295            }
   1296 
   1297            *index = block_index;
   1298            return BCM_E_NONE;
   1299         }
   1300     }
   1301 
   1302     /* Get free block from free list 0 */
   1303     if (NULL != REPL_HEAD_FREE_LIST(unit, pipe, 0)) {
   1304         block_index = REPL_HEAD_FREE_LIST(unit, pipe, 0)->index;
   1305         block_size = REPL_HEAD_FREE_LIST(unit, pipe, 0)->size;
   1306         next_block_ptr = REPL_HEAD_FREE_LIST(unit, pipe, 0)->next;
   1307         if (block_size < size) {
   1308             /* Free blocks on list 0 should never be
   1309              * smaller than requested size.
   1310              */
   1311             return BCM_E_INTERNAL;
   1312         } 
   1313 
   1314         sal_free(REPL_HEAD_FREE_LIST(unit, pipe, 0));
   1315         REPL_HEAD_FREE_LIST(unit, pipe, 0) = next_block_ptr;
   1316 
   1317         /* If the obtained free block contains more entries
   1318          * than requested, insert the remainder back into
   1319          * the free list array.
   1320          */
   1321         if (block_size > size) {
   1322             BCM_IF_ERROR_RETURN(_bcm_th_repl_head_block_free(unit,
   1323                         pipe, block_index + size, block_size - size));
   1324         }
   1325 
   1326         *index = block_index;
   1327         return BCM_E_NONE;
   1328     }
   1329 
   1330     /* No free block of sufficient size can be found */
   1331     return BCM_E_RESOURCE;
   1332 }
   1333 
   1334 #ifdef BCM_WARM_BOOT_SUPPORT
   1335 
   1336 /*
   1337  * Function:
   1338  *      _bcm_th_ipmc_repl_l3_intf_scache_size_get
   1339  * Purpose:
   1340  *      Get the required scache size for storing a bitmap
   1341  *      of L3 interfaces.
   1342  * Parameters:
   1343  *      unit - StrataSwitch unit #
   1344  *      size - (OUT) Number of bytes
   1345  * Returns:
   1346  *      BCM_E_xxx
   1347  */
   1348 int 
   1349 _bcm_th_ipmc_repl_l3_intf_scache_size_get(
   1350     int unit, 
   1351     uint32 *size)
   1352 {
   1353     int num_l3_intf;
   1354 
   1355     *size = 0;
   1356     num_l3_intf = soc_mem_index_count(unit, EGR_L3_INTFm);
   1357     *size += SHR_BITALLOCSIZE(num_l3_intf);
   1358 
   1359     return BCM_E_NONE;
   1360 }
   1361 
   1362 /*
   1363  * Function:
   1364  *      _bcm_th_ipmc_repl_l3_intf_sync
   1365  * Purpose:
   1366  *      Record L3 interface bitmap into the scache.
   1367  * Parameters:
   1368  *      unit - StrataSwitch unit #
   1369  *      scache_ptr - (IN/OUT) Scache pointer
   1370  * Returns:
   1371  *      BCM_E_xxx
   1372  */
   1373 int 
   1374 _bcm_th_ipmc_repl_l3_intf_sync(
   1375     int unit, 
   1376     uint8 **scache_ptr)
   1377 {
   1378     int num_l3_intf, i;
   1379     SHR_BITDCL *l3_intf_bitmap = NULL;
   1380 
   1381     REPL_INIT(unit);
   1382     /* Create a bitmap of L3 interfaces */
   1383     num_l3_intf = soc_mem_index_count(unit, EGR_L3_INTFm);
   1384     l3_intf_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_l3_intf),
   1385             "L3 interface bitmap");
   1386     if (NULL == l3_intf_bitmap) {
   1387         return BCM_E_MEMORY;
   1388     }
   1389     sal_memset(l3_intf_bitmap, 0, SHR_BITALLOCSIZE(num_l3_intf));
   1390 
   1391     /* For the L3 interfaces that were allocated next hop indices by
   1392      * bcm_l3_egress_create API, set the bit in the bitmap.
   1393      */
   1394     for (i = 0; i < num_l3_intf; i++) {
   1395         if (REPL_L3_INTF_NEXT_HOP_IPMC(unit, i) ==
   1396                 REPL_NH_INDEX_L3_EGRESS_ALLOCATED) {
   1397             SHR_BITSET(l3_intf_bitmap, i);
   1398         }
   1399     }
   1400 
   1401     /* Store the bitmap into scache */
   1402     sal_memcpy((*scache_ptr), l3_intf_bitmap, SHR_BITALLOCSIZE(num_l3_intf));
   1403     (*scache_ptr) += SHR_BITALLOCSIZE(num_l3_intf);
   1404 
   1405     sal_free(l3_intf_bitmap);
   1406     return BCM_E_NONE;
   1407 }
   1408 
   1409 /*
   1410  * Function:
   1411  *      _bcm_th_ipmc_repl_l3_intf_scache_recover
   1412  * Purpose:
   1413  *      Recover L3 interface bitmap from scache.
   1414  * Parameters:
   1415  *      unit - (IN) SOC unit number.
   1416  *      scache_ptr - (IN/OUT) Scache pointer
   1417  * Returns:
   1418  *      BCM_E_XXX
   1419  */
   1420 int
   1421 _bcm_th_ipmc_repl_l3_intf_scache_recover(int unit, uint8 **scache_ptr)
   1422 {
   1423     int num_l3_intf, i;
   1424     SHR_BITDCL *l3_intf_bitmap = NULL;
   1425 
   1426     /* Recover L3 interface bitmap */
   1427     num_l3_intf = soc_mem_index_count(unit, EGR_L3_INTFm);
   1428     l3_intf_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_l3_intf),
   1429             "L3 interface bitmap");
   1430     if (NULL == l3_intf_bitmap) {
   1431         return BCM_E_MEMORY;
   1432     }
   1433     sal_memcpy(l3_intf_bitmap, (*scache_ptr), SHR_BITALLOCSIZE(num_l3_intf));
   1434     (*scache_ptr) += SHR_BITALLOCSIZE(num_l3_intf);
   1435 
   1436     for (i = 0; i < num_l3_intf; i++) {
   1437         if (SHR_BITGET(l3_intf_bitmap, i)) {
   1438             REPL_L3_INTF_NEXT_HOP_IPMC(unit, i) =
   1439                 REPL_NH_INDEX_L3_EGRESS_ALLOCATED;
   1440         }
   1441     }
   1442 
   1443     sal_free(l3_intf_bitmap);
   1444     return BCM_E_NONE;
   1445 }
   1446 
   1447 /*
   1448  * Function:
   1449  *      _bcm_th_ipmc_repl_l3_intf_nh_map_scache_size_get
   1450  * Purpose:
   1451  *      Get the required scache size for storing map from L3 interfaces
   1452  *      to SDK managed next hop.
   1453  * Parameters:
   1454  *      unit - StrataSwitch unit #
   1455  *      size - (OUT) Number of bytes
   1456  * Returns:
   1457  *      BCM_E_xxx
   1458  */
   1459 int
   1460 _bcm_th_ipmc_repl_l3_intf_nh_map_scache_size_get(
   1461     int unit,
   1462     uint32 *size)
   1463 {
   1464     int num_l3_intf;
   1465 
   1466     *size = 0;
   1467     num_l3_intf = soc_mem_index_count(unit, EGR_L3_INTFm);
   1468     *size += (num_l3_intf * sizeof(int));
   1469 
   1470     return BCM_E_NONE;
   1471 }
   1472 
   1473 /*
   1474  * Function:
   1475  *      _bcm_th_ipmc_repl_l3_intf_nh_map_sync
   1476  * Purpose:
   1477  *      Record L3 interface map to SDK managed nexthop into the scache.
   1478  * Parameters:
   1479  *      unit - StrataSwitch unit #
   1480  *      scache_ptr - (IN/OUT) Scache pointer
   1481  * Returns:
   1482  *      BCM_E_xxx
   1483  */
   1484 int
   1485 _bcm_th_ipmc_repl_l3_intf_nh_map_sync(
   1486     int unit,
   1487     uint8 **scache_ptr)
   1488 {
   1489     int num_l3_intf, i;
   1490 
   1491     REPL_INIT(unit);
   1492 
   1493     num_l3_intf = soc_mem_index_count(unit, EGR_L3_INTFm);
   1494 
   1495     for (i = 0; i < num_l3_intf; i++) {
   1496         *(int *) (*scache_ptr) = REPL_L3_INTF_NEXT_HOP_IPMC(unit, i);
   1497         (*scache_ptr) += sizeof(int);
   1498     }
   1499 
   1500     return BCM_E_NONE;
   1501 }
   1502 
   1503 /*
   1504  * Function:
   1505  *      _bcm_th_ipmc_repl_l3_intf_nh_map_scache_recover
   1506  * Purpose:
   1507  *      Recover L3 interface nexthop map from scache.
   1508  * Parameters:
   1509  *      unit - (IN) SOC unit number.
   1510  *      scache_ptr - (IN/OUT) Scache pointer
   1511  * Returns:
   1512  *      BCM_E_XXX
   1513  */
   1514 int
   1515 _bcm_th_ipmc_repl_l3_intf_nh_map_scache_recover(int unit, uint8 **scache_ptr)
   1516 {
   1517     int  num_l3_intf, i;
   1518 
   1519     num_l3_intf = soc_mem_index_count(unit, EGR_L3_INTFm);
   1520 
   1521     for (i = 0; i < num_l3_intf; i++) {
   1522         REPL_L3_INTF_NEXT_HOP_IPMC(unit, i) = *(int *)(*scache_ptr);
   1523         (*scache_ptr) += sizeof(int);
   1524     }
   1525 
   1526     return BCM_E_NONE;
   1527 }
   1528 
   1529 /*
   1530  * Function:
   1531  *      _bcm_th_ipmc_repl_l3_intf_trill_nh_map_scache_size_get
   1532  * Purpose:
   1533  *      Get the required scache size for storing map from L3 interfaces
   1534  *      to SDK managed trill next hop.
   1535  * Parameters:
   1536  *      unit - StrataSwitch unit #
   1537  *      size - (OUT) Number of bytes
   1538  * Returns:
   1539  *      BCM_E_xxx
   1540  */
   1541 int
   1542 _bcm_th_ipmc_repl_l3_intf_trill_nh_map_scache_size_get(
   1543     int unit,
   1544     uint32 *size)
   1545 {
   1546     int num_l3_intf;
   1547 
   1548     *size = 0;
   1549     num_l3_intf = soc_mem_index_count(unit, EGR_L3_INTFm);
   1550     *size += (num_l3_intf * sizeof(int));
   1551 
   1552     return BCM_E_NONE;
   1553 }
   1554 
   1555 /*
   1556  * Function:
   1557  *      _bcm_th_ipmc_repl_l3_intf_trill_nh_map_sync
   1558  * Purpose:
   1559  *      Record L3 interface map to SDK managed trill nexthop into the scache.
   1560  * Parameters:
   1561  *      unit - StrataSwitch unit #
   1562  *      scache_ptr - (IN/OUT) Scache pointer
   1563  * Returns:
   1564  *      BCM_E_xxx
   1565  */
   1566 int
   1567 _bcm_th_ipmc_repl_l3_intf_trill_nh_map_sync(
   1568     int unit,
   1569     uint8 **scache_ptr)
   1570 {
   1571     int num_l3_intf, i;
   1572 
   1573     REPL_INIT(unit);
   1574 
   1575     num_l3_intf = soc_mem_index_count(unit, EGR_L3_INTFm);
   1576 
   1577     for (i = 0; i < num_l3_intf; i++) {
   1578         *(int *) (*scache_ptr) = REPL_L3_INTF_NEXT_HOP_TRILL(unit, i);
   1579         (*scache_ptr) += sizeof(int);
   1580     }
   1581 
   1582     return BCM_E_NONE;
   1583 }
   1584 
   1585 /*
   1586  * Function:
   1587  *      _bcm_th_ipmc_repl_l3_intf_trill_nh_map_scache_recover
   1588  * Purpose:
   1589  *      Recover L3 interface trill nexthop map from scache.
   1590  * Parameters:
   1591  *      unit - (IN) SOC unit number.
   1592  *      scache_ptr - (IN/OUT) Scache pointer
   1593  * Returns:
   1594  *      BCM_E_XXX
   1595  */
   1596 int
   1597 _bcm_th_ipmc_repl_l3_intf_trill_nh_map_scache_recover(int unit, uint8 **scache_ptr)
   1598 {
   1599     int  num_l3_intf, i;
   1600 
   1601     num_l3_intf = soc_mem_index_count(unit, EGR_L3_INTFm);
   1602 
   1603     for (i = 0; i < num_l3_intf; i++) {
   1604         REPL_L3_INTF_NEXT_HOP_TRILL(unit, i) = *(int *)(*scache_ptr);
   1605         (*scache_ptr) += sizeof(int);
   1606     }
   1607 
   1608     return BCM_E_NONE;
   1609 }
   1610 
   1611 /*
   1612  * Function:
   1613  *      _bcm_th_repl_head_block_insert
   1614  * Purpose:
   1615  *      Insert a free block of REPL_HEAD table entries into free array list.
   1616  * Parameters:
   1617  *      unit - (IN) SOC unit number. 
   1618  *      pipe - (IN) Pipeline number. 
   1619  *      index - (IN) Index of the first entry of the block.
   1620  *      size - (IN) Size of block.
   1621  * Returns:
   1622  *      BCM_E_xxx
   1623  */
   1624 STATIC int 
   1625 _bcm_th_repl_head_block_insert(int unit, int pipe, int index, int size)
   1626 {
   1627     _th_repl_head_free_block_t *block_ptr;
   1628 
   1629     block_ptr = sal_alloc(sizeof(_th_repl_head_free_block_t),
   1630             "repl head free block");
   1631     if (NULL == block_ptr) {
   1632         return BCM_E_MEMORY;
   1633     }
   1634     block_ptr->index = index;
   1635     block_ptr->size = size;
   1636     if (size > (_th_repl_head_info[unit][pipe].array_size - 1)) {
   1637         /* Insert into free list 0 */
   1638         block_ptr->next = REPL_HEAD_FREE_LIST(unit, pipe, 0);
   1639         REPL_HEAD_FREE_LIST(unit, pipe, 0) = block_ptr;
   1640     } else {
   1641         block_ptr->next = REPL_HEAD_FREE_LIST(unit, pipe, size);
   1642         REPL_HEAD_FREE_LIST(unit, pipe, size) = block_ptr;
   1643     }
   1644 
   1645     return BCM_E_NONE;
   1646 }
   1647 
   1648 /*
   1649  * Function:
   1650  *      _bcm_th_repl_head_block_used_set
   1651  * Purpose:
   1652  *      Mark a block of REPL_HEAD table entries as used.
   1653  * Parameters:
   1654  *      unit - (IN) SOC unit number. 
   1655  *      pipe - (IN) Pipeline number. 
   1656  *      index - (IN) Index of the first entry of the block.
   1657  *      size - (IN) Size of block.
   1658  * Returns:
   1659  *      BCM_E_xxx
   1660  */
   1661 STATIC int 
   1662 _bcm_th_repl_head_block_used_set(int unit, int pipe, int index, int size)
   1663 {
   1664     int i;
   1665     _th_repl_head_free_block_t *prev_block_ptr;
   1666     _th_repl_head_free_block_t *block_ptr;
   1667     int block_index, block_size, sub_block_size;
   1668 
   1669     for (i = 0; i < _th_repl_head_info[unit][pipe].array_size; i++) {
   1670         block_ptr = REPL_HEAD_FREE_LIST(unit, pipe, i);
   1671         prev_block_ptr = NULL;
   1672         while (NULL != block_ptr) {
   1673             block_index = block_ptr->index;
   1674             block_size = block_ptr->size;
   1675             if ((index >= block_index) &&
   1676                     ((index + size) <= (block_index + block_size))) {
   1677 
   1678                 /* This free block contains the block to be marked as used.
   1679                  * Remove this free block from linked list.
   1680                  */
   1681                 if (block_ptr == REPL_HEAD_FREE_LIST(unit, pipe, i)) {
   1682                     REPL_HEAD_FREE_LIST(unit, pipe, i) = block_ptr->next;
   1683                 } else {
   1684                     /* 
   1685                      * In the following line of code, Coverity thinks the
   1686                      * prev_block_ptr may still be NULL when dereferenced.
   1687                      * This situation will never occur because 
   1688                      * if block_ptr is not pointing to the head of the 
   1689                      * linked list, prev_block_ptr would not be NULL.
   1690                      */
   1691                     /* coverity[var_deref_op : FALSE] */
   1692                     prev_block_ptr->next = block_ptr->next;
   1693                 }
   1694                 sal_free(block_ptr);
   1695 
   1696                 /* This free block contains up to 3 sub-blocks: the sub-block
   1697                  * to be marked as used, and the sub-blocks before and after
   1698                  * it. The sub-blocks before and after the used sub-block
   1699                  * need to be inserted back into the free list array.
   1700                  */
   1701 
   1702                 /* Insert the sub-block before the used sub-block back into
   1703                  * the free list array.
   1704                  */
   1705                 sub_block_size = index - block_index;
   1706                 if (sub_block_size > 0) {
   1707                     BCM_IF_ERROR_RETURN(_bcm_th_repl_head_block_insert(unit,
   1708                                 pipe, block_index, sub_block_size));
   1709                 }
   1710 
   1711                 /* Insert the sub-block after the used sub-block back into
   1712                  * the free list array.
   1713                  */
   1714                 sub_block_size = (block_index + block_size) - (index + size);
   1715                 if (sub_block_size > 0) {
   1716                     BCM_IF_ERROR_RETURN(_bcm_th_repl_head_block_insert(unit,
   1717                                 pipe, index + size, sub_block_size));
   1718                 }
   1719 
   1720                 return BCM_E_NONE;
   1721             }
   1722 
   1723             prev_block_ptr = block_ptr;
   1724             block_ptr = block_ptr->next;
   1725         }
   1726     }
   1727 
   1728     /* The block to be marked used is not found among the free blocks. */
   1729     return BCM_E_NOT_FOUND;
   1730 }
   1731 #endif /* BCM_WARM_BOOT_SUPPORT */
   1732 
   1733 /* --------------------------------------------------------------
   1734  * The following set of routines manage REPL_LIST table resource.
   1735  * --------------------------------------------------------------
   1736  */
   1737 
   1738 /*
   1739  * Function:
   1740  *      _bcm_th_repl_list_entry_info_deinit
   1741  * Purpose:
   1742  *      De-initialize replication list entry info.
   1743  * Parameters:
   1744  *      unit - (IN)SOC unit number. 
   1745  * Returns:
   1746  *      None
   1747  */
   1748 STATIC void 
   1749 _bcm_th_repl_list_entry_info_deinit(int unit)
   1750 {
   1751     int pipe;
   1752 
   1753     if (NULL != _th_repl_list_entry_info[unit]) {
   1754         for (pipe = 0; pipe < NUM_PIPES(unit); pipe++) {
   1755             if (NULL != _th_repl_list_entry_info[unit][pipe].bitmap_entries_used) {
   1756                 sal_free(_th_repl_list_entry_info[unit][pipe].bitmap_entries_used);
   1757                 _th_repl_list_entry_info[unit][pipe].bitmap_entries_used = NULL;
   1758             }
   1759         }
   1760         sal_free(_th_repl_list_entry_info[unit]);
   1761         _th_repl_list_entry_info[unit] = NULL;
   1762     }
   1763 }
   1764 
   1765 /*
   1766  * Function:
   1767  *      _bcm_th_repl_list_entry_info_init
   1768  * Purpose:
   1769  *      Initialize replication list entry info.
   1770  * Parameters:
   1771  *      unit - (IN)SOC unit number. 
   1772  * Returns:
   1773  *      BCM_E_xxx
   1774  */
   1775 STATIC int 
   1776 _bcm_th_repl_list_entry_info_init(int unit)
   1777 {
   1778     int alloc_size;
   1779     int pipe;
   1780     soc_mem_t repl_list_table;
   1781 
   1782     alloc_size = NUM_PIPES(unit) * sizeof(_th_repl_list_entry_info_t);
   1783 
   1784     if (NULL == _th_repl_list_entry_info[unit]) {
   1785         _th_repl_list_entry_info[unit] = sal_alloc(alloc_size,
   1786                 "repl_list_entry_info");
   1787         if (NULL == _th_repl_list_entry_info[unit]) {
   1788             _bcm_th_repl_list_entry_info_deinit(unit);
   1789             return BCM_E_MEMORY;
   1790         }
   1791     }
   1792     sal_memset(_th_repl_list_entry_info[unit], 0, alloc_size);
   1793 
   1794     for (pipe = 0; pipe < NUM_PIPES(unit); pipe++) {
   1795         soc_mem_t repl_head_tbl = REPL_HEAD_TBL(unit);
   1796         if (soc_feature(unit, soc_feature_split_repl_head_table)) {
   1797             repl_head_tbl = REPL_HEAD_TBL_SPLIT(unit, 0);
   1798         }
   1799         if(SOC_IS_TOMAHAWK3(unit)) {
   1800             repl_list_table = MMU_REPL_LIST_TBLm;
   1801         } else {
   1802         repl_list_table = REPL_LIST_TBL_PIPE(unit, pipe);
   1803         }
   1804         _th_repl_list_entry_info[unit][pipe].num_entries = 1 <<
   1805             soc_mem_field_length(unit, repl_head_tbl, HEAD_PTRf);
   1806         alloc_size = SHR_BITALLOCSIZE(_th_repl_list_entry_info[unit][pipe].num_entries);
   1807         if (NULL == _th_repl_list_entry_info[unit][pipe].bitmap_entries_used) {
   1808             _th_repl_list_entry_info[unit][pipe].bitmap_entries_used =
   1809                 sal_alloc(alloc_size, "repl list bitmap_entries_used");
   1810             if (NULL == _th_repl_list_entry_info[unit][pipe].bitmap_entries_used) {
   1811                 _bcm_th_repl_list_entry_info_deinit(unit);
   1812                 return BCM_E_MEMORY;
   1813             }
   1814         }
   1815         sal_memset(_th_repl_list_entry_info[unit][pipe].bitmap_entries_used, 0,
   1816                 alloc_size);
   1817 
   1818         /* Reserve REPL_LIST table entry 0 */
   1819         REPL_LIST_ENTRY_USED_SET(unit, pipe, 0);
   1820 
   1821         /* Clear entry 0 of REPL_LIST table */
   1822         SOC_IF_ERROR_RETURN
   1823             (soc_mem_write(unit, repl_list_table, MEM_BLOCK_ALL,
   1824                            0, soc_mem_entry_null(unit, REPL_LIST_TBL(unit))));
   1825 
   1826     }
   1827 
   1828     return BCM_E_NONE;
   1829 }
   1830 
   1831 /*
   1832  * Function:
   1833  *      _bcm_th_repl_list_entry_free
   1834  * Purpose:
   1835  *      Free a REPL_LIST table entry.
   1836  * Parameters:
   1837  *      unit - (IN) SOC unit number. 
   1838  *      pipe - (IN) Pipeline number. 
   1839  *      entry_index - (IN) Index of the entry to be freed.
   1840  * Returns:
   1841  *      BCM_E_xxx
   1842  */
   1843 STATIC int
   1844 _bcm_th_repl_list_entry_free(int unit, int pipe, int entry_index)
   1845 {
   1846     if (!REPL_LIST_ENTRY_USED_GET(unit, pipe, entry_index)) {
   1847         return BCM_E_INTERNAL;
   1848     }
   1849 
   1850     REPL_LIST_ENTRY_USED_CLR(unit, pipe, entry_index);
   1851     return BCM_E_NONE;
   1852 }
   1853 
   1854 /*
   1855  * Function:
   1856  *      _bcm_th_repl_list_entry_alloc
   1857  * Purpose:
   1858  *      Allocate a free entry from REPL_LIST table.
   1859  * Parameters:
   1860  *      unit - (IN) SOC unit number. 
   1861  *      pipe - (IN) Pipeline number. 
   1862  *      entry_index - (OUT) Index of a free entry.
   1863  * Returns:
   1864  *      BCM_E_xxx
   1865  */
   1866 STATIC int 
   1867 _bcm_th_repl_list_entry_alloc(int unit, int pipe, int *entry_index)
   1868 {
   1869     int i;
   1870 #ifdef BCM_TOMAHAWK3_SUPPORT
   1871     if(SOC_IS_TOMAHAWK3(unit)) {
   1872 #define _TH3_IPMC_MAX_RECYCLE_POOL_SIZE 18
   1873         /* try to reclycle from candidate pool if pool_size > 18
   1874          * in the worst case, 18 replicatoin list will be used
   1875          */
   1876         if(_repl_list_recycle_array[unit]->list_size > _TH3_IPMC_MAX_RECYCLE_POOL_SIZE) {
   1877                 int rv;
   1878                 rv = _bcm_th3_repl_list_recycle(unit, entry_index);
   1879                 if (rv == BCM_E_NONE) {
   1880                     REPL_LIST_ENTRY_USED_SET(unit, pipe, *entry_index);
   1881                     return rv;
   1882                 }
   1883         }
   1884 #undef _TH3_IPMC_MAX_RECYCLE_POOL_SIZE
   1885     }
   1886 #endif
   1887     for (i = 0; i < _th_repl_list_entry_info[unit][pipe].num_entries; i++) {
   1888         if (!REPL_LIST_ENTRY_USED_GET(unit, pipe, i)) {
   1889             *entry_index = i;
   1890             REPL_LIST_ENTRY_USED_SET(unit, pipe, i);
   1891             return BCM_E_NONE;
   1892         }
   1893     }
   1894 
   1895 #ifdef BCM_TOMAHAWK3_SUPPORT
   1896     /* try to do the recylce again before returning BCM_E_RESOURCE */
   1897     if(SOC_IS_TOMAHAWK3(unit) && _repl_list_recycle_array[unit]->list_size != 0) {
   1898         int rv;
   1899         rv = _bcm_th3_repl_list_recycle(unit, entry_index);
   1900         if (BCM_FAILURE(rv)) {
   1901             *entry_index = -1;
   1902             return BCM_E_RESOURCE;
   1903         } else {
   1904             REPL_LIST_ENTRY_USED_SET(unit, pipe, *entry_index);
   1905             return BCM_E_NONE;
   1906         }
   1907     }
   1908 #endif
   1909     *entry_index = -1;
   1910     return BCM_E_RESOURCE;
   1911 }
   1912 
   1913 #ifdef BCM_WARM_BOOT_SUPPORT
   1914 /*
   1915  * Function:
   1916  *      _bcm_th_repl_list_entry_used_set
   1917  * Purpose:
   1918  *      Mark the REPL_LIST table entry as used.
   1919  * Parameters:
   1920  *      unit - (IN) SOC unit number. 
   1921  *      pipe - (IN) Pipeline number. 
   1922  *      entry_index - (IN) Index of the entry to be marked.
   1923  * Returns:
   1924  *      BCM_E_xxx
   1925  */
   1926 STATIC int
   1927 _bcm_th_repl_list_entry_used_set(int unit, int pipe, int entry_index)
   1928 {
   1929     REPL_LIST_ENTRY_USED_SET(unit, pipe, entry_index);
   1930     return BCM_E_NONE;
   1931 }
   1932 
   1933 /*
   1934  * Function:
   1935  *      _bcm_th_repl_list_entry_used_get
   1936  * Purpose:
   1937  *      Get used status of a REPL_LIST table entry.
   1938  * Parameters:
   1939  *      unit - (IN) SOC unit number. 
   1940  *      pipe - (IN) Pipeline number. 
   1941  *      entry_index - (IN) Index of the entry.
   1942  *      used - (OUT) Used status.
   1943  * Returns:
   1944  *      TRUE if used, else FALSE.
   1945  */
   1946 STATIC int
   1947 _bcm_th_repl_list_entry_used_get(int unit, int pipe, int entry_index)
   1948 {
   1949     if (REPL_LIST_ENTRY_USED_GET(unit, pipe, entry_index)) {
   1950         return TRUE;
   1951     }
   1952     return FALSE;
   1953 }
   1954 #endif /* BCM_WARM_BOOT_SUPPORT */
   1955 
   1956 /* --------------------------------------------------------------
   1957  * The following set of routines manage replication lists.
   1958  * --------------------------------------------------------------
   1959  */
   1960 /*
   1961  * Function:
   1962  *      bcm_th_ipmc_repl_detach
   1963  * Purpose:
   1964  *      Deinitialize replication.
   1965  * Parameters:
   1966  *      unit - SOC unit #
   1967  * Returns:
   1968  *      BCM_E_XXX
   1969  */
   1970 int
   1971 bcm_th_ipmc_repl_detach(int unit)
   1972 {
   1973     int pipe, num_ports;
   1974     _bcm_repl_list_info_t *rli_current, *rli_free;
   1975     bcm_port_t port;
   1976 
   1977     _bcm_th_repl_list_entry_info_deinit(unit);
   1978 
   1979     _bcm_th_repl_head_info_deinit(unit);
   1980 #ifdef BCM_TOMAHAWK3_SUPPORT
   1981     _bcm_th3_repl_list_recycle_candidate_deinit(unit);
   1982 #endif
   1983     if (_th_repl_info[unit] != NULL) {
   1984         if (_th_repl_info[unit]->repl_list_info_array != NULL) {
   1985             for (pipe = 0; pipe < NUM_PIPES(unit); pipe++) {
   1986                 rli_current = _th_repl_info[unit]->repl_list_info_array[pipe];
   1987                 while (rli_current != NULL) {
   1988                     rli_free = rli_current;
   1989                     rli_current = rli_current->next;
   1990                     sal_free(rli_free);
   1991                 }
   1992             }
   1993             sal_free(_th_repl_info[unit]->repl_list_info_array);
   1994         }
   1995 
   1996 #ifdef BCM_MAVERICK2_SUPPORT
   1997         if (SOC_IS_MAVERICK2(unit)) {
   1998             /* MV2 is single pipe TD3, but regsfile has same
   1999              port count as TD3 for this memory.Hence dividing by 2*/
   2000             num_ports = (soc_mem_index_count(unit, ING_DEVICE_PORTm) - 1)/2;
   2001         } else
   2002 #endif
   2003             if (SOC_IS_TRIDENT3X(unit)) {
   2004                 num_ports = soc_mem_index_count(unit, ING_DEVICE_PORTm) - 1;
   2005             } else {
   2006                 num_ports = soc_mem_index_count(unit, PORT_TABm) - 1;
   2007             }
   2008         for (port = 0; port < num_ports; port++) {
   2009             if (_th_repl_info[unit]->port_info[port] != NULL) {
   2010                 if (_th_repl_info[unit]->
   2011                         port_info[port]->intf_count != NULL) {
   2012                     sal_free(_th_repl_info[unit]->
   2013                             port_info[port]->intf_count);
   2014                 }
   2015                 sal_free(_th_repl_info[unit]->port_info[port]);
   2016             }
   2017         }
   2018         if (_th_repl_info[unit]->l3_intf_next_hop_ipmc != NULL) {
   2019             sal_free(_th_repl_info[unit]->l3_intf_next_hop_ipmc);
   2020         }
   2021         if (_th_repl_info[unit]->l3_intf_next_hop_trill != NULL) {
   2022             sal_free(_th_repl_info[unit]->l3_intf_next_hop_trill);
   2023         }
   2024         sal_free(_th_repl_info[unit]);
   2025         _th_repl_info[unit] = NULL;
   2026 
   2027         if (soc_property_get(unit, spn_MULTICAST_PER_TRUNK_REPLICATION, 0)) {
   2028             BCM_IF_ERROR_RETURN(bcm_th_aggid_info_detach(unit));
   2029         }
   2030     }
   2031 
   2032     return BCM_E_NONE;
   2033 }
   2034 #ifdef BCM_TOMAHAWK3_SUPPORT
   2035 
   2036 STATIC int
   2037 _bcm_th3_repl_init(int unit)
   2038 {
   2039     bcm_port_t port;
   2040     uint32 regval;
   2041     soc_reg_t reg = MMU_RQE_REPL_PORT_AGG_MAPr;
   2042     _bcm_repl_list_info_t *recycle_head = NULL;
   2043     /* init repl head */
   2044     BCM_IF_ERROR_RETURN(_bcm_th3_repl_head_info_init(unit));
   2045 
   2046     /* init repl list entry*/
   2047     BCM_IF_ERROR_RETURN(_bcm_th_repl_list_entry_info_init(unit));
   2048 
   2049     /* enable per trunk replication mode */
   2050     if (soc_property_get(unit, spn_MULTICAST_PER_TRUNK_REPLICATION, 0)) {
   2051         BCM_MC_PER_TRUNK_REPL_MODE(unit) = TRUE;
   2052         BCM_IF_ERROR_RETURN(bcm_th_aggid_info_init(unit));
   2053     } else {
   2054         BCM_MC_PER_TRUNK_REPL_MODE(unit) = FALSE;
   2055         BCM_IF_ERROR_RETURN(bcm_th_aggid_info_detach(unit));
   2056     }
   2057     /* init repl list recyclye candidate pool with a dummy node*/
   2058     recycle_head = (_bcm_repl_list_info_t *)
   2059                                 sal_alloc(sizeof(_bcm_repl_list_info_t), "recycle head");
   2060 
   2061     if (NULL == recycle_head) {
   2062         return BCM_E_MEMORY;
   2063     }
   2064     sal_memset(recycle_head, 0, sizeof(_bcm_repl_list_info_t));
   2065     recycle_head->list_size = 0;
   2066     _repl_list_recycle_array[unit] = recycle_head;
   2067     /* map device port to agg_id */
   2068     PBMP_ITER(PBMP_ALL(unit), port) {
   2069         regval = 0;
   2070         soc_reg_field_set(unit, reg, &regval, L3MC_PORT_AGG_IDf,
   2071                             BCM_MC_PER_TRUNK_REPL_MODE(unit) ?
   2072                                              TH3_AGG_ID_HW_INVALID : port);
   2073         SOC_IF_ERROR_RETURN(
   2074             soc_reg32_set(unit, reg, port, 0, regval));
   2075 
   2076     }
   2077     if (!SOC_WARM_BOOT(unit)) {
   2078         /* Only clear if not cold boot */
   2079         if (!SOC_HW_RESET(unit) || SAL_BOOT_BCMSIM) {
   2080             /* clear  */
   2081             SOC_IF_ERROR_RETURN
   2082                 (soc_mem_clear(unit, MMU_REPL_MEMBER_ICCm, MEM_BLOCK_ALL, 0));
   2083 
   2084             SOC_IF_ERROR_RETURN
   2085                  (soc_mem_clear(unit, MMU_REPL_GROUP_INFO_TBLm, MEM_BLOCK_ALL, 0));
   2086 
   2087             SOC_IF_ERROR_RETURN
   2088                     (soc_mem_clear(unit, MMU_REPL_HEAD_TBLm, MEM_BLOCK_ALL, 0));
   2089 
   2090             SOC_IF_ERROR_RETURN
   2091                     (soc_mem_clear(unit, MMU_REPL_LIST_TBLm, MEM_BLOCK_ALL, 0));
   2092 
   2093         }
   2094     }
   2095     return BCM_E_NONE;
   2096 }
   2097 
   2098 #endif
   2099 /*
   2100  * Function:
   2101  *      bcm_th_ipmc_repl_init
   2102  * Purpose:
   2103  *      Initialize replication.
   2104  * Parameters:
   2105  *      unit - SOC unit #
   2106  * Returns:
   2107  *      BCM_E_XXX
   2108  */
   2109 int
   2110 bcm_th_ipmc_repl_init(int unit)
   2111 {
   2112     int rv = BCM_E_NONE;
   2113     int alloc_size;
   2114     int i;
   2115     bcm_port_t port;
   2116     int phy_port, mmu_port;
   2117     int port_speed, count_width;
   2118     uint32 regval;
   2119     soc_mem_t ipmc_mem_inst;
   2120     int pipe, slice;
   2121     soc_info_t *si;
   2122     soc_reg_t reg = MMU_DQS_REPL_PORT_AGG_MAPr;
   2123 
   2124     bcm_th_ipmc_repl_detach(unit);
   2125 
   2126     if (NULL == _th_repl_info[unit]) {
   2127        _th_repl_info[unit] = sal_alloc(sizeof(_th_repl_info_t), "repl info");
   2128        if (NULL == _th_repl_info[unit]) {
   2129            bcm_th_ipmc_repl_detach(unit);
   2130            return BCM_E_MEMORY;
   2131        }
   2132     }
   2133     sal_memset(_th_repl_info[unit], 0, sizeof(_th_repl_info_t));
   2134 
   2135     /* There are 4 pipelines in Tomahawk. Each pipeline has its own 
   2136      * multicast replication tables.
   2137      */
   2138     _th_repl_info[unit]->num_pipes = NUM_PIPE(unit);
   2139 
   2140 #ifdef BCM_TOMAHAWK3_SUPPORT
   2141     /* There are 8 pipelines in Tomahawk3, but
   2142      * multicast replication tables are pipeline independent.
   2143      */
   2144     if(SOC_IS_TOMAHAWK3(unit)) {
   2145         _th_repl_info[unit]->num_pipes = 1;
   2146     }
   2147 #endif
   2148     _th_repl_info[unit]->num_repl_groups = soc_mem_index_count(unit, L3_IPMCm);
   2149 
   2150     /* The total number of replication interfaces equals to the total
   2151      * number of next hops. Unlike previous XGS3 devices, each L3 inteface
   2152      * will be associated with a next hop index.
   2153      */
   2154     _th_repl_info[unit]->num_intf = soc_mem_index_count(unit,
   2155             EGR_L3_NEXT_HOPm);
   2156 
   2157     alloc_size = _th_repl_info[unit]->num_pipes *
   2158         sizeof(_bcm_repl_list_info_t *);
   2159     if (NULL == _th_repl_info[unit]->repl_list_info_array) {
   2160         _th_repl_info[unit]->repl_list_info_array = sal_alloc(alloc_size,
   2161                 "array of linked list of replication list info");
   2162         if (NULL == _th_repl_info[unit]->repl_list_info_array) {
   2163             bcm_th_ipmc_repl_detach(unit);
   2164             return BCM_E_MEMORY;
   2165         }
   2166     }
   2167     sal_memset(_th_repl_info[unit]->repl_list_info_array, 0, alloc_size);
   2168 
   2169     PBMP_ITER(PBMP_ALL(unit), port) {
   2170         /* coverity[overrun-local : FALSE] */
   2171         if (NULL == _th_repl_info[unit]->port_info[port]) {
   2172             _th_repl_info[unit]->port_info[port] =
   2173                 sal_alloc(sizeof(_th_repl_port_info_t), "repl port info");
   2174             if (NULL == _th_repl_info[unit]->port_info[port]) {
   2175                 bcm_th_ipmc_repl_detach(unit);
   2176                 return BCM_E_MEMORY;
   2177             }
   2178         }
   2179         sal_memset(_th_repl_info[unit]->port_info[port], 0,
   2180                 sizeof(_th_repl_port_info_t));
   2181 
   2182         alloc_size = sizeof(int) * _th_repl_info[unit]->num_repl_groups;
   2183         if (NULL == _th_repl_info[unit]->port_info[port]->intf_count) {
   2184             _th_repl_info[unit]->port_info[port]->intf_count = 
   2185                 sal_alloc(alloc_size, "repl port intf count");
   2186             if (NULL == _th_repl_info[unit]->port_info[port]->intf_count) {
   2187                 bcm_th_ipmc_repl_detach(unit);
   2188                 return BCM_E_MEMORY;
   2189             }
   2190         }
   2191         sal_memset(_th_repl_info[unit]->port_info[port]->intf_count, 0,
   2192                 alloc_size);
   2193     }
   2194 
   2195     if (NULL == _th_repl_info[unit]->l3_intf_next_hop_ipmc) {
   2196         _th_repl_info[unit]->l3_intf_next_hop_ipmc =
   2197             sal_alloc(sizeof(int) * soc_mem_index_count(unit, EGR_L3_INTFm),
   2198                     "l3_intf_next_hop_ipmc");
   2199         if (NULL == _th_repl_info[unit]->l3_intf_next_hop_ipmc) {
   2200             bcm_th_ipmc_repl_detach(unit);
   2201             return BCM_E_MEMORY;
   2202         }
   2203     }
   2204     for (i = 0; i < soc_mem_index_count(unit, EGR_L3_INTFm); i++) {
   2205         _th_repl_info[unit]->l3_intf_next_hop_ipmc[i] = -1;
   2206     }
   2207 
   2208     if (NULL == _th_repl_info[unit]->l3_intf_next_hop_trill) {
   2209         _th_repl_info[unit]->l3_intf_next_hop_trill =
   2210             sal_alloc(sizeof(int) * soc_mem_index_count(unit, EGR_L3_INTFm),
   2211                     "l3_intf_next_hop_trill");
   2212         if (NULL == _th_repl_info[unit]->l3_intf_next_hop_trill) {
   2213             bcm_th_ipmc_repl_detach(unit);
   2214             return BCM_E_MEMORY;
   2215         }
   2216     }
   2217     for (i = 0; i < soc_mem_index_count(unit, EGR_L3_INTFm); i++) {
   2218         _th_repl_info[unit]->l3_intf_next_hop_trill[i] = -1;
   2219     }
   2220 #ifdef BCM_TOMAHAWK3_SUPPORT
   2221     if(SOC_IS_TOMAHAWK3(unit)) {
   2222         rv = _bcm_th3_repl_init(unit);
   2223         if(BCM_FAILURE(rv)) {
   2224             bcm_th_ipmc_repl_detach(unit);
   2225         }
   2226         return BCM_E_NONE;
   2227     }
   2228 #endif
   2229     rv = _bcm_th_repl_head_info_init(unit);
   2230     if (BCM_FAILURE(rv)) {
   2231         bcm_th_ipmc_repl_detach(unit);
   2232         return rv;
   2233     }
   2234 
   2235     rv = _bcm_th_repl_list_entry_info_init(unit);
   2236     if (BCM_FAILURE(rv)) {
   2237         bcm_th_ipmc_repl_detach(unit);
   2238         return rv;
   2239     }
   2240 
   2241     /* enable per trunk replication mode */
   2242     if (soc_property_get(unit, spn_MULTICAST_PER_TRUNK_REPLICATION, 0)) {
   2243         BCM_MC_PER_TRUNK_REPL_MODE(unit) = TRUE;
   2244         BCM_IF_ERROR_RETURN(bcm_th_aggid_info_init(unit));
   2245     } else {
   2246         BCM_MC_PER_TRUNK_REPL_MODE(unit) = FALSE;
   2247     }
   2248 
   2249     if (!SOC_WARM_BOOT(unit)) {
   2250         si = &SOC_INFO(unit);
   2251         for (slice = 0; slice < NUM_SLICE(unit); slice++) {
   2252             if (!si->sc_epipe_map[slice]) {
   2253                 continue;
   2254             }
   2255             /* Clear replication group initial count table */
   2256             ipmc_mem_inst = REPL_GROUP_INITIAL_COPY_COUNT_TBL_SLICE(unit, slice);
   2257             SOC_IF_ERROR_RETURN
   2258                 (soc_mem_clear(unit, ipmc_mem_inst, MEM_BLOCK_ALL, 0));
   2259 #if defined(BCM_TOMAHAWK2_SUPPORT)
   2260             if (SOC_IS_TOMAHAWK2(unit)) {
   2261                 ipmc_mem_inst =
   2262                     SOC_MEM_UNIQUE_ACC(unit,
   2263                                    MMU_REPL_GROUP_INITIAL_COPY_COUNT0m)[slice];
   2264                 SOC_IF_ERROR_RETURN
   2265                     (soc_mem_clear(unit, ipmc_mem_inst, MEM_BLOCK_ALL, 0));
   2266                 ipmc_mem_inst =
   2267                     SOC_MEM_UNIQUE_ACC(unit,
   2268                                    MMU_REPL_GROUP_INITIAL_COPY_COUNT1m)[slice];
   2269                 SOC_IF_ERROR_RETURN
   2270                     (soc_mem_clear(unit, ipmc_mem_inst, MEM_BLOCK_ALL, 0));
   2271             }
   2272 #endif /* BCM_TOMAHAWK2_SUPPORT */
   2273         }
   2274         /* Only clear if not cold boot */
   2275         if (!SOC_HW_RESET(unit) || SAL_BOOT_BCMSIM) {
   2276             for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) {
   2277                 /* Clear replication group table */
   2278                 ipmc_mem_inst = REPL_GROUP_INFO_TBL_PIPE(unit, pipe);
   2279                 SOC_IF_ERROR_RETURN
   2280                     (soc_mem_clear(unit, ipmc_mem_inst, MEM_BLOCK_ALL, 0));
   2281 
   2282                 /* Clear replication head table */
   2283                 if (soc_feature(unit, soc_feature_split_repl_head_table)) {
   2284                     ipmc_mem_inst = REPL_HEAD_TBL_SPLIT_PIPE(unit, 0, pipe);
   2285                     SOC_IF_ERROR_RETURN
   2286                         (soc_mem_clear(unit, ipmc_mem_inst, MEM_BLOCK_ALL, 0));
   2287                     ipmc_mem_inst = REPL_HEAD_TBL_SPLIT_PIPE(unit, 1, pipe);
   2288                     SOC_IF_ERROR_RETURN
   2289                         (soc_mem_clear(unit, ipmc_mem_inst, MEM_BLOCK_ALL, 0));
   2290                 } else {
   2291                     ipmc_mem_inst = REPL_HEAD_TBL_PIPE(unit, pipe);
   2292                     SOC_IF_ERROR_RETURN
   2293                         (soc_mem_clear(unit, ipmc_mem_inst, MEM_BLOCK_ALL, 0));
   2294                 }
   2295 
   2296                 /* Clear replication list table */
   2297                 ipmc_mem_inst = REPL_LIST_TBL_PIPE(unit, pipe);
   2298                 SOC_IF_ERROR_RETURN
   2299                     (soc_mem_clear(unit, ipmc_mem_inst, MEM_BLOCK_ALL, 0));
   2300             }
   2301         }
   2302 
   2303         /* Initialize PORT_INITIAL_COPY_COUNT_WIDTH registers */
   2304         PBMP_ITER(PBMP_ALL(unit), port) {
   2305             /* coverity[overrun-local : FALSE] */
   2306             phy_port = SOC_INFO(unit).port_l2p_mapping[port];
   2307             /* coverity[overrun-local : FALSE] */
   2308             mmu_port = SOC_INFO(unit).port_p2m_mapping[phy_port];
   2309             /* coverity[illegal_address : FALSE] */
   2310             if (IS_CPU_PORT(unit, port) || IS_LB_PORT(unit, port) ||
   2311                 IS_MANAGEMENT_PORT(unit, port) || IS_FAE_PORT(unit, port)) {
   2312                 /* For CPU, loopback, and management ports,
   2313                  * the copy count width is fixed at 2/3 bits
   2314                  * (encoded value of 0/1).
   2315                  * Pysical ports 129 and 131 are management ports.
   2316                  */
   2317                 count_width = 1;
   2318                 if (phy_port == 129 || phy_port == 131 ||
   2319                     (phy_port == 128 && SOC_IS_TRIDENT3(unit)) || (phy_port == 81 && SOC_IS_MAVERICK2(unit))) {
   2320                     if (soc_mem_field_length(unit,
   2321                         MMU_REPL_GROUP_INITIAL_COPY_COUNTm, ICC_BIT_MPf) <= 2) {
   2322                         count_width = 0;
   2323                     }
   2324                 }
   2325             } else {
   2326                 if (SOC_IS_TOMAHAWK2(unit)) {
   2327                     /* Single-lane ports are allocated 2 bits, while 2 or 4
   2328                      * lane ports are allocated 3 bits. */
   2329                     count_width = (si->port_num_lanes[port] > 1) ? 1 : 0;
   2330                 } else {
   2331                     /* For ports with speed 40G and above the copy count width
   2332                      * is 3 bits (encoded value of 1) for lower speeds its
   2333                      * 2 bits (encoded value of 0).
   2334                      */
   2335                     BCM_IF_ERROR_RETURN
   2336                         (bcm_esw_port_speed_get(unit, port, &port_speed));
   2337                     count_width = (port_speed >= 40000) ? 1 : 0;
   2338                 }
   2339             }
   2340 
   2341             /* If the port_initial_copy_count is not skipped, update the same */
   2342             if (!soc_feature(unit, soc_feature_skip_port_initial_copy_count)) {
   2343                 regval = 0;
   2344                 soc_reg_field_set(unit, PORT_INITIAL_COPY_COUNT_WIDTHr, &regval,
   2345                         BIT_WIDTHf, count_width);
   2346                 SOC_IF_ERROR_RETURN(WRITE_PORT_INITIAL_COPY_COUNT_WIDTHr(unit,
   2347                             port, regval));
   2348             }
   2349 
   2350             /* configure mmu port to repl aggregateId map */
   2351             regval = 0;
   2352 
   2353 #ifdef BCM_TOMAHAWK3_SUPPORT
   2354             reg = (SOC_IS_TOMAHAWK3(unit)) ? MMU_RQE_REPL_PORT_AGG_MAPr :
   2355                   MMU_DQS_REPL_PORT_AGG_MAPr;
   2356 #endif
   2357 
   2358             soc_reg_field_set(unit, reg, &regval,
   2359                       L3MC_PORT_AGG_IDf,
   2360                       BCM_MC_PER_TRUNK_REPL_MODE(unit) ?
   2361                       TH_AGG_ID_HW_INVALID : (mmu_port % mmu_port_stride[unit]));
   2362             SOC_IF_ERROR_RETURN(
   2363                     soc_reg32_set(unit, reg, port, 0, regval));
   2364         }
   2365     }
   2366 
   2367 
   2368     return rv;
   2369 }
   2370 
   2371 
   2372 /* Function:
   2373  *	_bcm_th_port_pipe_get
   2374  * Purpose:
   2375  *      Get pipeline to which the given port belongs.
   2376  * Parameters:
   2377  *	unit - SOC unit number.
   2378  *	port - Port number.
   2379  *      pipe - (OUT) Pipeline number.
   2380  * Returns:
   2381  *	BCM_E_XXX
   2382  */
   2383 STATIC int
   2384 _bcm_th_port_pipe_get(int unit, int port, int *pipe)
   2385 {
   2386     soc_info_t *si = &SOC_INFO(unit);
   2387 
   2388     if (si->port_pipe[port] == -1) {
   2389         return BCM_E_PORT;
   2390     }
   2391 
   2392     *pipe = si->port_pipe[port];
   2393 
   2394     return BCM_E_NONE;
   2395 }
   2396 
   2397 /* Function:
   2398  *	_bcm_th_port_slice_get
   2399  * Purpose:
   2400  *      Get MMU slice to which the given port belongs.
   2401  * Parameters:
   2402  *	unit - SOC unit number.
   2403  *	port - Port number.
   2404  *      slice - (OUT) Slice number.
   2405  * Returns:
   2406  *	BCM_E_XXX
   2407  */
   2408 STATIC int
   2409 _bcm_td3_port_slice_get(int unit, int port, int *slice)
   2410 {
   2411     *slice = 0;
   2412 
   2413     return BCM_E_NONE;
   2414 }
   2415 
   2416 /* Function:
   2417  *	_bcm_th_port_slice_get
   2418  * Purpose:
   2419  *      Get MMU slice to which the given port belongs.
   2420  * Parameters:
   2421  *	unit - SOC unit number.
   2422  *	port - Port number.
   2423  *      slice - (OUT) Slice number.
   2424  * Returns:
   2425  *	BCM_E_XXX
   2426  */
   2427 STATIC int
   2428 _bcm_th_port_slice_get(int unit, int port, int *slice)
   2429 {
   2430     int pipe;
   2431 
   2432     if (SOC_IS_TRIDENT3X(unit)) {
   2433         return _bcm_td3_port_slice_get(unit, port, slice);
   2434     }
   2435     /* Get pipeline number */
   2436     BCM_IF_ERROR_RETURN(_bcm_th_port_pipe_get(unit, port, &pipe));
   2437 
   2438     /* Derive slice number */
   2439     if (pipe <= 1) {
   2440         *slice = 0;
   2441     } else {
   2442         *slice = 1;
   2443     }
   2444 
   2445     return BCM_E_NONE;
   2446 }
   2447 
   2448 /* Function:
   2449  *	_bcm_td3_repl_icc_set
   2450  * Purpose:
   2451  *      Set replication initial copy count.
   2452  * Parameters:
   2453  *	unit       - StrataSwitch PCI device unit number.
   2454  *	repl_group - The replication group number.
   2455  *	port       - Port.
   2456  *	intf_count - Replication list's interface count.
   2457  *  count_width - count_width
   2458  *  copy_count - copy_count
   2459  * Returns:
   2460  *	BCM_E_XXX
   2461  */
   2462 STATIC int
   2463 _bcm_td3_repl_icc_set(int unit, int repl_group, bcm_port_t port,
   2464                       int intf_count, int count_width, int copy_count)
   2465 {
   2466     soc_info_t *si;
   2467     bcm_port_t phy_port;
   2468     mmu_repl_group_initial_copy_count_entry_t initial_copy_count_entry;
   2469     uint32 count_mask, count_shift;
   2470     SHR_BITDCL copy_count_buf[12];
   2471     int slice = 0;    /* Only 1 slice in TD3 */
   2472     soc_mem_t repl_group_icc_table;
   2473 
   2474 #if defined(BCM_HELIX5_SUPPORT)
   2475     int bit = 0;
   2476 #endif
   2477 
   2478     /* TD3TBD:
   2479      * PORT_INITIAL_COPY_COUNT_WIDTHr NEEDS to be updated while
   2480      * Chaging lanes or speed */
   2481 
   2482     /* Update REPL_GROUP_INITIAL_COPY_COUNT table */
   2483     repl_group_icc_table =
   2484         REPL_GROUP_INITIAL_COPY_COUNT_TBL_SLICE(unit, slice);
   2485     SOC_IF_ERROR_RETURN
   2486         (soc_mem_read(unit, repl_group_icc_table, MEM_BLOCK_ANY,
   2487                       repl_group, &initial_copy_count_entry));
   2488     si = &SOC_INFO(unit);
   2489     phy_port = si->port_l2p_mapping[port];
   2490     if (SOC_IS_TRIDENT3(unit)) {
   2491         if (slice == 0) {
   2492             if (phy_port == 128 &&
   2493                     SOC_PORT_BLOCK(unit, phy_port) == SOC_PORT_BLOCK(unit, 129)) {
   2494                 /* Second management port */
   2495                 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit,
   2496                         &initial_copy_count_entry, ICC_BIT_2ND_MPf, copy_count);
   2497             } else if (phy_port == 131) {
   2498                 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit,
   2499                         &initial_copy_count_entry, ICC_BIT_LP_PYf, copy_count);
   2500             } else if (phy_port == 130) {
   2501                 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit,
   2502                         &initial_copy_count_entry, ICC_BIT_LP_PXf, copy_count);
   2503             } else if (phy_port == 129) {
   2504                 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit,
   2505                         &initial_copy_count_entry, ICC_BIT_MPf, copy_count);
   2506             } else if (IS_CPU_PORT(unit, port)) {
   2507                 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit,
   2508                         &initial_copy_count_entry, ICC_BIT_CPUf, copy_count);
   2509             } else if (phy_port <= 128 && phy_port >= 65) {
   2510                 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_get(unit,
   2511                         &initial_copy_count_entry, ICC_BIT_FP_PYf, copy_count_buf);
   2512                 count_mask = (1 << count_width) - 1;
   2513                 count_shift = (phy_port - 65) * 2 % 32;
   2514                 copy_count_buf[(phy_port - 65) * 2 / 32] &= ~(count_mask << count_shift);
   2515                 copy_count_buf[(phy_port - 65) * 2 / 32] |= (copy_count << count_shift);
   2516                 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_set(unit,
   2517                         &initial_copy_count_entry, ICC_BIT_FP_PYf, copy_count_buf);
   2518             } else if (phy_port <= 64 && phy_port >= 1) {
   2519                 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_get(unit,
   2520                         &initial_copy_count_entry, ICC_BIT_FP_PXf, copy_count_buf);
   2521                 count_mask = (1 << count_width) - 1;
   2522                 count_shift = (phy_port - 1) * 2 % 32;
   2523                 copy_count_buf[(phy_port - 1) * 2 / 32] &= ~(count_mask << count_shift);
   2524                 copy_count_buf[(phy_port - 1) * 2 / 32] |= (copy_count << count_shift);
   2525                 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_set(unit,
   2526                         &initial_copy_count_entry, ICC_BIT_FP_PXf, copy_count_buf);
   2527             } else {
   2528                 return BCM_E_PORT;
   2529             }
   2530         }
   2531     }
   2532 
   2533 #if defined(BCM_MAVERICK2_SUPPORT)
   2534     if (SOC_IS_MAVERICK2(unit)) {
   2535         if (slice == 0) {
   2536             if (IS_LB_PORT(unit, port)) {
   2537                 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit,
   2538                         &initial_copy_count_entry, ICC_BIT_LP_PXf, copy_count);
   2539             } else if (IS_MANAGEMENT_PORT(unit, port)) {
   2540                 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit,
   2541                         &initial_copy_count_entry, ICC_BIT_MPf, copy_count);
   2542             } else if (IS_CPU_PORT(unit, port)) {
   2543                 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit,
   2544                         &initial_copy_count_entry, ICC_BIT_CPUf, copy_count);
   2545             } else if (IS_E_PORT(unit, port) || IS_HG_PORT(unit, port)) {
   2546                 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_get(unit,
   2547                         &initial_copy_count_entry, ICC_BIT_FP_PXf, copy_count_buf);
   2548                 count_mask = (1 << count_width) - 1;
   2549                 count_shift = (phy_port - 1) * 2 % 32;
   2550                 copy_count_buf[(phy_port - 1) * 2 / 32] &= ~(count_mask << count_shift);
   2551                 copy_count_buf[(phy_port - 1) * 2 / 32] |= (copy_count << count_shift);
   2552                 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_set(unit,
   2553                         &initial_copy_count_entry, ICC_BIT_FP_PXf, copy_count_buf);
   2554             } else {
   2555                 return BCM_E_PORT;
   2556             }
   2557         }
   2558     }
   2559 #endif
   2560 
   2561 #if defined(BCM_HELIX5_SUPPORT)
   2562     if (SOC_IS_HELIX5(unit)) {
   2563         if (slice == 0) {
   2564             if (IS_LB_PORT(unit, port)) {
   2565                 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit,
   2566                         &initial_copy_count_entry, ICC_BIT_LP_PXf, copy_count);
   2567             } else if (IS_CPU_PORT(unit, port)) {
   2568                 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit,
   2569                         &initial_copy_count_entry, ICC_BIT_CPUf, copy_count);
   2570             } else if (IS_E_PORT(unit, port) || IS_HG_PORT(unit, port)) {
   2571                 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_get(unit,
   2572                         &initial_copy_count_entry, ICC_BIT_FP_PXf, copy_count_buf);
   2573                 count_shift = (phy_port - 1) * 3;
   2574                 for (bit = 0; bit < count_width; bit++) {
   2575                     if (copy_count & (1 << bit)) {
   2576                         SHR_BITSET(copy_count_buf, count_shift + bit);
   2577                     } else {
   2578                         SHR_BITCLR(copy_count_buf, count_shift + bit);
   2579                     }
   2580                 }
   2581 
   2582                 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_set(unit,
   2583                         &initial_copy_count_entry, ICC_BIT_FP_PXf, copy_count_buf);
   2584             } else {
   2585                 return BCM_E_PORT;
   2586             }
   2587         }
   2588     }
   2589 #endif
   2590 
   2591     SOC_IF_ERROR_RETURN
   2592         (soc_mem_write(unit, repl_group_icc_table, MEM_BLOCK_ALL,
   2593                        repl_group, &initial_copy_count_entry));
   2594     return BCM_E_NONE;
   2595 }
   2596 
   2597 /* Function:
   2598  *	_bcm_th_repl_initial_copy_count_set
   2599  * Purpose:
   2600  *      Set replication initial copy count.
   2601  * Parameters:
   2602  *	unit       - StrataSwitch PCI device unit number.
   2603  *	repl_group - The replication group number.
   2604  *	port       - Port.
   2605  *	intf_count - Replication list's interface count.
   2606  * Returns:
   2607  *	BCM_E_XXX
   2608  */
   2609 STATIC int
   2610 _bcm_th_repl_initial_copy_count_set(int unit, int repl_group, bcm_port_t port,
   2611                 int intf_count)
   2612 {
   2613     soc_info_t *si;
   2614     bcm_port_t phy_port;
   2615     uint32 regval;
   2616     int count_width, copy_count;
   2617     mmu_repl_group_initial_copy_count_entry_t initial_copy_count_entry;
   2618     uint32 count_mask, count_shift, count_column;
   2619     uint32 copy_count_buf[4];
   2620     int pipe, slice;
   2621     soc_mem_t repl_group_icc_table;
   2622 #if defined(BCM_TOMAHAWK2_SUPPORT)
   2623     soc_mem_t repl_group_icc_table0 = INVALIDm;
   2624     soc_mem_t repl_group_icc_table1 = INVALIDm;
   2625 #endif /* BCM_TOMAHAWK2_SUPPORT */
   2626 
   2627     /* Get port's copy count width */
   2628     if (!soc_feature(unit, soc_feature_skip_port_initial_copy_count)) {
   2629         SOC_IF_ERROR_RETURN(READ_PORT_INITIAL_COPY_COUNT_WIDTHr(unit,
   2630                     port, &regval));
   2631         count_width = 2 + soc_reg_field_get(unit,
   2632                 PORT_INITIAL_COPY_COUNT_WIDTHr, regval, BIT_WIDTHf);
   2633     } else {
   2634         /* In HX5, the above reg is marked as reserved, since for all
   2635          * front-panel ports the initial-copy-count-width has been setup as 3.
   2636          */
   2637         count_width = 3;
   2638     }
   2639     /* Compute port's initial copy count */
   2640     copy_count = 0;
   2641     switch (count_width) {
   2642         case 2:
   2643             if (intf_count <= 3) {
   2644                 copy_count = intf_count;
   2645             }
   2646             break;
   2647         case 3:
   2648             if (intf_count <= 5) {
   2649                 copy_count = intf_count;
   2650             }
   2651             break;
   2652         default:
   2653             return BCM_E_INTERNAL;
   2654             break;
   2655     }
   2656 
   2657     if (SOC_IS_TRIDENT3X(unit)) {
   2658         return _bcm_td3_repl_icc_set(unit, repl_group, port, intf_count,
   2659                                      count_width, copy_count);
   2660     }
   2661 
   2662     /* Get pipeline number */
   2663     BCM_IF_ERROR_RETURN(_bcm_th_port_pipe_get(unit, port, &pipe));
   2664     /* Update REPL_GROUP_INITIAL_COPY_COUNT table */
   2665     BCM_IF_ERROR_RETURN(_bcm_th_port_slice_get(unit, port, &slice));
   2666 
   2667     repl_group_icc_table =
   2668         SOC_MEM_UNIQUE_ACC(unit, MMU_REPL_GROUP_INITIAL_COPY_COUNTm)[slice];
   2669 #if defined(BCM_TOMAHAWK2_SUPPORT)
   2670     if (SOC_IS_TOMAHAWK2(unit)) {
   2671         repl_group_icc_table0 =
   2672             SOC_MEM_UNIQUE_ACC(unit, MMU_REPL_GROUP_INITIAL_COPY_COUNT0m)[slice];
   2673         repl_group_icc_table1 =
   2674             SOC_MEM_UNIQUE_ACC(unit, MMU_REPL_GROUP_INITIAL_COPY_COUNT1m)[slice];
   2675     }
   2676 #endif /* BCM_TOMAHAWK2_SUPPORT */
   2677     SOC_IF_ERROR_RETURN
   2678         (soc_mem_read(unit, repl_group_icc_table, MEM_BLOCK_ANY,
   2679                       repl_group, &initial_copy_count_entry));
   2680     si = &SOC_INFO(unit);
   2681     phy_port = si->port_l2p_mapping[port];
   2682 
   2683 #   define IS_X_PIPE(_pipe_)               ((_pipe_ & 1) == 0)
   2684 #   define IS_Y_PIPE(_pipe_)               ((_pipe_ & 1) == 1)
   2685 #   define PORT_NUM_PER_PIPE(_u_)          (SOC_IS_TOMAHAWK2(_u_) ? 64 : 32)
   2686 #   define PHY_PORT_ID_PER_PIPE(_u_, _pp_) ((_pp_ - 1) % PORT_NUM_PER_PIPE(_u_))
   2687     
   2688     if (IS_LB_PORT(unit, port) && IS_Y_PIPE(pipe)) {
   2689         soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit,
   2690                 &initial_copy_count_entry, ICC_BIT_LP_PYf, copy_count);
   2691     } else if (IS_LB_PORT(unit, port) && IS_X_PIPE(pipe)) {
   2692         soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit,
   2693                 &initial_copy_count_entry, ICC_BIT_LP_PXf, copy_count);
   2694     } else if (IS_MANAGEMENT_PORT(unit, port)) {
   2695         soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit,
   2696                 &initial_copy_count_entry, ICC_BIT_MPf, copy_count);
   2697     } else if (IS_CPU_PORT(unit, port)) {
   2698         soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit,
   2699                 &initial_copy_count_entry, ICC_BIT_CPUf, copy_count);
   2700     } else if (IS_Y_PIPE(pipe)) {
   2701         soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_get(unit,
   2702                 &initial_copy_count_entry, ICC_BIT_FP_PYf, copy_count_buf);
   2703         count_mask   = (1 << count_width) - 1;
   2704         count_shift  = PHY_PORT_ID_PER_PIPE(unit, phy_port) * 2 % 32;
   2705         count_column = PHY_PORT_ID_PER_PIPE(unit, phy_port) * 2 / 32;
   2706         copy_count_buf[count_column] &= ~(count_mask << count_shift);
   2707         copy_count_buf[count_column] |=  (copy_count << count_shift);
   2708         soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_set(unit,
   2709                 &initial_copy_count_entry, ICC_BIT_FP_PYf, copy_count_buf);
   2710     } else if (IS_X_PIPE(pipe)) {
   2711         soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_get(unit,
   2712                 &initial_copy_count_entry, ICC_BIT_FP_PXf, copy_count_buf);
   2713         count_mask   = (1 << count_width) - 1;
   2714         count_shift  = PHY_PORT_ID_PER_PIPE(unit, phy_port) * 2 % 32;
   2715         count_column = PHY_PORT_ID_PER_PIPE(unit, phy_port) * 2 / 32;
   2716         copy_count_buf[count_column] &= ~(count_mask << count_shift);
   2717         copy_count_buf[count_column] |=  (copy_count << count_shift);
   2718         soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_set(unit,
   2719                 &initial_copy_count_entry, ICC_BIT_FP_PXf, copy_count_buf);
   2720     } else {
   2721         return BCM_E_PORT;
   2722     }
   2723     SOC_IF_ERROR_RETURN
   2724         (soc_mem_write(unit, repl_group_icc_table, MEM_BLOCK_ALL, 
   2725                        repl_group, &initial_copy_count_entry));
   2726 #if defined(BCM_TOMAHAWK2_SUPPORT)
   2727     if (SOC_IS_TOMAHAWK2(unit)) {
   2728         /* coverity[negative_returns : FALSE] */
   2729         SOC_IF_ERROR_RETURN
   2730             (soc_mem_write(unit, repl_group_icc_table0, MEM_BLOCK_ALL, 
   2731                            repl_group, &initial_copy_count_entry));
   2732         /* coverity[negative_returns : FALSE] */
   2733         SOC_IF_ERROR_RETURN
   2734             (soc_mem_write(unit, repl_group_icc_table1, MEM_BLOCK_ALL, 
   2735                            repl_group, &initial_copy_count_entry));
   2736     }
   2737 #endif /* BCM_TOMAHAWK2_SUPPORT */
   2738     return BCM_E_NONE;
   2739 }
   2740 
   2741 STATIC int
   2742 _bcm_td3_repl_head_tbl_write(int unit, int pipe, int index, uint32 *entry)
   2743 {
   2744     soc_mem_t repl_hd_tbl;
   2745     int max_index_offset = 0;
   2746 
   2747     if (SOC_IS_HELIX5(unit)) {
   2748         max_index_offset = 32;
   2749     } else {
   2750         max_index_offset = 64;
   2751     }
   2752 
   2753     if (soc_feature(unit, soc_feature_split_repl_head_table)) {
   2754         repl_hd_tbl = REPL_HEAD_TBL_SPLIT_PIPE(unit, 0, pipe);
   2755         if (index >= max_index_offset * 1024) {
   2756             index -= max_index_offset * 1024;
   2757             repl_hd_tbl = REPL_HEAD_TBL_SPLIT_PIPE(unit, 1, pipe);
   2758         }
   2759         SOC_IF_ERROR_RETURN(soc_mem_write(unit, repl_hd_tbl, MEM_BLOCK_ALL,
   2760                                           index, entry));
   2761     } else {
   2762         repl_hd_tbl = REPL_HEAD_TBL_PIPE(unit, pipe);
   2763         SOC_IF_ERROR_RETURN(soc_mem_write(unit, repl_hd_tbl, MEM_BLOCK_ALL,
   2764                                           index, entry));
   2765     }
   2766 
   2767     return BCM_E_NONE;
   2768 }
   2769 
   2770 STATIC int
   2771 _bcm_td3_repl_head_tbl_read(int unit, int pipe, int index, uint32 *entry, uint32 *head_ptr)
   2772 {
   2773     soc_mem_t repl_hd_tbl;
   2774     int max_index_offset = 0;
   2775 
   2776     if (SOC_IS_HELIX5(unit)) {
   2777         max_index_offset = 32;
   2778     } else {
   2779         max_index_offset = 64;
   2780     }
   2781 
   2782     if (soc_feature(unit, soc_feature_split_repl_head_table)) {
   2783         repl_hd_tbl = REPL_HEAD_TBL_SPLIT_PIPE(unit, 0, pipe);
   2784         if (index >= max_index_offset * 1024) {
   2785             index -= max_index_offset * 1024;
   2786             repl_hd_tbl = REPL_HEAD_TBL_SPLIT_PIPE(unit, 1, pipe);
   2787         }
   2788         SOC_IF_ERROR_RETURN(soc_mem_read(unit, repl_hd_tbl, MEM_BLOCK_ALL,
   2789                                          index, entry));
   2790         if (head_ptr) {
   2791             *head_ptr = soc_mem_field32_get(unit, repl_hd_tbl, entry,
   2792                                              HEAD_PTRf);
   2793         }
   2794     } else {
   2795 
   2796 #if defined(BCM_TOMAHAWK3_SUPPORT)
   2797         if (SOC_IS_TOMAHAWK3(unit)) {
   2798             repl_hd_tbl = MMU_REPL_HEAD_TBLm;
   2799         } else
   2800 #endif
   2801         {
   2802             repl_hd_tbl = REPL_HEAD_TBL_PIPE(unit, pipe);
   2803         }
   2804 
   2805         SOC_IF_ERROR_RETURN(soc_mem_read(unit, repl_hd_tbl, MEM_BLOCK_ALL,
   2806                                          index, entry));
   2807         if (head_ptr) {
   2808             *head_ptr = soc_mem_field32_get(unit, repl_hd_tbl, entry, HEAD_PTRf);
   2809         }
   2810     }
   2811 
   2812     return BCM_E_NONE;
   2813 }
   2814 
   2815 /* Function:
   2816  *	_bcm_th_repl_list_start_ptr_set
   2817  * Purpose:
   2818  *      Set replication list start pointer for given (repl_group, port).
   2819  * Parameters:
   2820  *	unit       - StrataSwitch PCI device unit number.
   2821  *	repl_group - The replication group number.
   2822  *	port       - Port.
   2823  *	start_ptr  - Replication list's start pointer.
   2824  *	intf_count - Replication list's interface count.
   2825  * Returns:
   2826  *	BCM_E_XXX
   2827  */
   2828 STATIC int
   2829 _bcm_th_repl_list_start_ptr_set(int unit, int repl_group, bcm_port_t port,
   2830                 int start_ptr, int intf_count)
   2831 {
   2832     int add_member;
   2833     soc_mem_t repl_group_table;
   2834     soc_mem_t repl_head_table;
   2835     soc_field_t member_bitmap_f, head_index_f; 
   2836     soc_info_t *si;
   2837     bcm_port_t phy_port, mmu_port;
   2838     int member_bitmap_index;
   2839     int pipe;
   2840     mmu_repl_group_info_tbl_entry_t repl_group_entry;
   2841     uint32 fldbuf[SOC_PBMP_WORD_MAX];
   2842     int i;
   2843     soc_pbmp_t old_member_bitmap;
   2844     soc_pbmp_t new_member_bitmap;
   2845     int old_member_count, new_member_count;
   2846     int old_head_index, new_head_index;
   2847     int member_id, member, old_member_id, new_member_id;
   2848     uint32 repl_head_entry[SOC_MAX_MEM_FIELD_WORDS];
   2849     uint32 old_repl_head_entry[SOC_MAX_MEM_FIELD_WORDS];
   2850     int member_bitmap_len;
   2851 
   2852     if (start_ptr > 0) {
   2853         add_member = TRUE;
   2854     } else {
   2855         add_member = FALSE;
   2856     }
   2857 
   2858     member_bitmap_f = PIPE_MEMBER_BMPf;
   2859     head_index_f = PIPE_BASE_PTRf;
   2860 
   2861 
   2862     if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) {
   2863         int aggid = TH_AGG_ID_INVALID;
   2864         BCM_IF_ERROR_RETURN(bcm_th_port_to_aggid(unit, port, &aggid));
   2865         member_bitmap_index = aggid;
   2866     } else {
   2867         /* Get member bitmap index */
   2868         si = &SOC_INFO(unit);
   2869         phy_port = si->port_l2p_mapping[port];
   2870         mmu_port = si->port_p2m_mapping[phy_port];
   2871         member_bitmap_index = mmu_port % mmu_port_stride[unit];
   2872     }
   2873 
   2874     member_bitmap_len = soc_mem_field_length(unit, MMU_REPL_GROUP_INFO_TBLm,
   2875                                              member_bitmap_f);
   2876     if (member_bitmap_index >= member_bitmap_len) {
   2877         return BCM_E_PARAM;
   2878     }
   2879 
   2880     /* Get old member bitmap and old head index */
   2881     BCM_IF_ERROR_RETURN(_bcm_th_port_pipe_get(unit, port, &pipe));
   2882     if (soc_feature(unit, soc_feature_split_repl_head_table)) {
   2883         if (member_bitmap_index < 32) {
   2884             repl_head_table = REPL_HEAD_TBL_SPLIT_PIPE(unit, 0, pipe);
   2885         } else {
   2886             repl_head_table = REPL_HEAD_TBL_SPLIT_PIPE(unit, 1, pipe);
   2887         }
   2888     } else {
   2889         repl_head_table = REPL_HEAD_TBL_PIPE(unit, pipe);
   2890     }
   2891     repl_group_table = REPL_GROUP_INFO_TBL_PIPE(unit, pipe);
   2892 
   2893     SOC_IF_ERROR_RETURN
   2894         (soc_mem_read(unit, repl_group_table, MEM_BLOCK_ANY, 
   2895                       repl_group, &repl_group_entry));
   2896     sal_memset(fldbuf, 0, SOC_PBMP_WORD_MAX * sizeof(uint32));
   2897     soc_mem_field_get(unit, repl_group_table, (uint32 *)&repl_group_entry,
   2898             member_bitmap_f, fldbuf);
   2899     for (i = 0; i < SOC_PBMP_WORD_MAX; i++) {
   2900         SOC_PBMP_WORD_SET(old_member_bitmap, i, fldbuf[i]);
   2901     }
   2902     SOC_PBMP_ASSIGN(new_member_bitmap, old_member_bitmap);
   2903     SOC_PBMP_COUNT(old_member_bitmap, old_member_count);
   2904     old_head_index = soc_mem_field32_get(unit, repl_group_table,
   2905             &repl_group_entry, head_index_f);
   2906 
   2907     if (add_member) {
   2908         /* Update REPL_HEAD table */
   2909         sal_memset(repl_head_entry, 0, sizeof(repl_head_entry));
   2910         soc_mem_field32_set(unit, repl_head_table, repl_head_entry,
   2911                             HEAD_PTRf, start_ptr);
   2912         if (SOC_PBMP_MEMBER(old_member_bitmap, member_bitmap_index)) {
   2913             /* Port is already a member of the group */
   2914             member_id = 0;
   2915             SOC_PBMP_ITER(old_member_bitmap, member) {
   2916                 if (member == member_bitmap_index) {
   2917                     break;
   2918                 }
   2919                 member_id++;
   2920             }
   2921             SOC_IF_ERROR_RETURN
   2922                 (_bcm_td3_repl_head_tbl_write(unit, pipe,
   2923                  (old_head_index + member_id), repl_head_entry));
   2924             new_head_index = old_head_index;
   2925         } else {
   2926             SOC_PBMP_PORT_ADD(new_member_bitmap, member_bitmap_index);
   2927             new_member_count = old_member_count + 1;
   2928             BCM_IF_ERROR_RETURN(_bcm_th_repl_head_block_alloc(unit,
   2929                         pipe, new_member_count, &new_head_index));
   2930             old_member_id = 0;
   2931             new_member_id = 0;
   2932             SOC_PBMP_ITER(new_member_bitmap, member) {
   2933                 if (member == member_bitmap_index) {
   2934                     SOC_IF_ERROR_RETURN
   2935                         (_bcm_td3_repl_head_tbl_write(unit, pipe,
   2936                                        (new_head_index + new_member_id),
   2937                                        repl_head_entry));
   2938                 } else {
   2939                     SOC_IF_ERROR_RETURN
   2940                         (_bcm_td3_repl_head_tbl_read(unit, pipe,
   2941                                       (old_head_index + old_member_id),
   2942                                       old_repl_head_entry, NULL));
   2943                     SOC_IF_ERROR_RETURN
   2944                         (_bcm_td3_repl_head_tbl_write(unit, pipe,
   2945                                        (new_head_index + new_member_id),
   2946                                        old_repl_head_entry));
   2947                     old_member_id++;
   2948                 }
   2949                 new_member_id++;
   2950             }
   2951         }
   2952 
   2953         /* Update REPL_GROUP_INITIAL_COPY_COUNT entry */
   2954         BCM_IF_ERROR_RETURN(_bcm_th_repl_initial_copy_count_set(unit,
   2955                         repl_group, port, intf_count));
   2956 
   2957         /* Update REPL_GROUP entry */
   2958         for (i = 0; i < SOC_PBMP_WORD_MAX; i++) {
   2959             fldbuf[i] = SOC_PBMP_WORD_GET(new_member_bitmap, i);
   2960         }
   2961         soc_mem_field_set(unit, repl_group_table, (uint32 *)&repl_group_entry,
   2962                 member_bitmap_f, fldbuf);
   2963         soc_mem_field32_set(unit, repl_group_table, &repl_group_entry,
   2964                 head_index_f, new_head_index);
   2965         repl_group_table = REPL_GROUP_INFO_TBL_PIPE(unit, pipe);
   2966 
   2967         SOC_IF_ERROR_RETURN
   2968             (soc_mem_write(unit, repl_group_table, MEM_BLOCK_ALL,
   2969                            repl_group, &repl_group_entry));
   2970 
   2971         /* Release old block of REPL_HEAD entries */
   2972         if (old_member_count > 0 && old_head_index != new_head_index) {
   2973             BCM_IF_ERROR_RETURN(_bcm_th_repl_head_block_free(unit,
   2974                         pipe, old_head_index, old_member_count));
   2975         }
   2976 
   2977     } else { /* Remove member from replication group */
   2978 
   2979         if (!SOC_PBMP_MEMBER(old_member_bitmap, member_bitmap_index)) {
   2980             /* Port is not a member. Nothing more to do. */
   2981             return BCM_E_NONE;
   2982         }
   2983 
   2984         /* Update REPL_HEAD table */
   2985         new_member_count = old_member_count - 1;
   2986         if (new_member_count > 0) {
   2987             BCM_IF_ERROR_RETURN(_bcm_th_repl_head_block_alloc(unit,
   2988                         pipe, new_member_count, &new_head_index));
   2989             old_member_id = 0;
   2990             new_member_id = 0;
   2991             SOC_PBMP_ITER(old_member_bitmap, member) {
   2992                 if (member != member_bitmap_index) {
   2993                     SOC_IF_ERROR_RETURN
   2994                         (_bcm_td3_repl_head_tbl_read(unit, pipe,
   2995                                       (old_head_index + old_member_id),
   2996                                       old_repl_head_entry, NULL));
   2997                     SOC_IF_ERROR_RETURN
   2998                         (_bcm_td3_repl_head_tbl_write(unit, pipe,
   2999                                        (new_head_index + new_member_id),
   3000                                        old_repl_head_entry));
   3001                     new_member_id++;
   3002                 }
   3003                 old_member_id++;
   3004             }
   3005         } else {
   3006             new_head_index = 0;
   3007         }
   3008 
   3009         /* Update REPL_GROUP_INITIAL_COPY_COUNT entry. MMU spec
   3010          * recommends setting the initial copy count to 1 for
   3011          * ports that are being removed from a replication group.
   3012          */
   3013         BCM_IF_ERROR_RETURN(_bcm_th_repl_initial_copy_count_set(unit,
   3014                     repl_group, port, 1));
   3015 
   3016         /* Update REPL_GROUP entry */
   3017         SOC_PBMP_PORT_REMOVE(new_member_bitmap, member_bitmap_index);
   3018         for (i = 0; i < SOC_PBMP_WORD_MAX; i++) {
   3019             fldbuf[i] = SOC_PBMP_WORD_GET(new_member_bitmap, i);
   3020         }
   3021         soc_mem_field_set(unit, repl_group_table, (uint32 *)&repl_group_entry,
   3022                 member_bitmap_f, fldbuf);
   3023         soc_mem_field32_set(unit, repl_group_table, &repl_group_entry,
   3024                 head_index_f, new_head_index);
   3025         repl_group_table = REPL_GROUP_INFO_TBL_PIPE(unit, pipe);
   3026 
   3027         SOC_IF_ERROR_RETURN
   3028             (soc_mem_write(unit, repl_group_table, MEM_BLOCK_ALL,
   3029                            repl_group, &repl_group_entry));
   3030 
   3031         /* Release old block of REPL_HEAD entries */
   3032         BCM_IF_ERROR_RETURN(_bcm_th_repl_head_block_free(unit,
   3033                     pipe, old_head_index, old_member_count));
   3034     }
   3035 
   3036     return BCM_E_NONE;
   3037 }
   3038 
   3039 /*
   3040  * Function:
   3041  *	_bcm_th_repl_list_start_ptr_get
   3042  * Purpose:
   3043  *      Get replication list start pointer for given (repl_group, port).
   3044  * Parameters:
   3045  *	unit       - StrataSwitch PCI device unit number.
   3046  *	repl_group - The replication group number.
   3047  *	port       - Port.
   3048  *	start_ptr  - (OUT) Replication list's start pointer to
   3049  *	             REPL_LIST table.
   3050  * Returns:
   3051  *	BCM_E_XXX
   3052  */
   3053 STATIC int
   3054 _bcm_th_repl_list_start_ptr_get(int unit, int repl_group, bcm_port_t port,
   3055         int *start_ptr)
   3056 {
   3057     soc_mem_t repl_group_table;
   3058     soc_field_t member_bitmap_f, head_index_f; 
   3059     soc_info_t *si;
   3060     bcm_port_t phy_port, mmu_port;
   3061     int member_bitmap_index;
   3062     int pipe;
   3063     mmu_repl_group_info_tbl_entry_t repl_group_entry;
   3064     uint32 fldbuf[SOC_PBMP_WORD_MAX];
   3065     int i;
   3066     soc_pbmp_t member_bitmap;
   3067     int member_id, member;
   3068     int head_index;
   3069     uint32 repl_head_entry[SOC_MAX_MEM_FIELD_WORDS];
   3070 
   3071     member_bitmap_f = PIPE_MEMBER_BMPf;
   3072     head_index_f = PIPE_BASE_PTRf;
   3073 
   3074     if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) {
   3075         int aggid = TH_AGG_ID_INVALID;
   3076         BCM_IF_ERROR_RETURN(bcm_th_port_to_aggid(unit, port, &aggid));
   3077         member_bitmap_index = aggid;
   3078     } else {
   3079         /* Get member bitmap index */
   3080         si = &SOC_INFO(unit);
   3081         phy_port = si->port_l2p_mapping[port];
   3082         mmu_port = si->port_p2m_mapping[phy_port];
   3083         member_bitmap_index = mmu_port % mmu_port_stride[unit];
   3084     }
   3085 
   3086     /* Get member bitmap */
   3087     BCM_IF_ERROR_RETURN(_bcm_th_port_pipe_get(unit, port, &pipe));
   3088 
   3089     repl_group_table = REPL_GROUP_INFO_TBL_PIPE(unit, pipe);
   3090 
   3091     SOC_IF_ERROR_RETURN
   3092         (soc_mem_read(unit, repl_group_table, MEM_BLOCK_ANY,
   3093                       repl_group, &repl_group_entry));
   3094     sal_memset(fldbuf, 0, SOC_PBMP_WORD_MAX * sizeof(uint32));
   3095     soc_mem_field_get(unit, repl_group_table, (uint32 *)&repl_group_entry,
   3096             member_bitmap_f, fldbuf);
   3097     for (i = 0; i < SOC_PBMP_WORD_MAX; i++) {
   3098         SOC_PBMP_WORD_SET(member_bitmap, i, fldbuf[i]);
   3099     }
   3100 
   3101     /* Check if port is in member bitmap */
   3102     if (!SOC_PBMP_MEMBER(member_bitmap, member_bitmap_index)) {
   3103         *start_ptr = 0;
   3104         return BCM_E_NONE;
   3105     }
   3106 
   3107     /* Get replication list start pointer */
   3108     member_id = 0;
   3109     SOC_PBMP_ITER(member_bitmap, member) {
   3110         if (member == member_bitmap_index) {
   3111             break;
   3112         }
   3113         member_id++;
   3114     }
   3115     head_index = member_id + soc_mem_field32_get(unit, repl_group_table,
   3116             &repl_group_entry, head_index_f);
   3117     SOC_IF_ERROR_RETURN
   3118         (_bcm_td3_repl_head_tbl_read(unit, pipe,
   3119                       head_index, repl_head_entry, (uint32 *)start_ptr));
   3120 
   3121     return BCM_E_NONE;
   3122 }
   3123 
   3124 /*
   3125  * Function:
   3126  *	_bcm_th_repl_list_free
   3127  * Purpose:
   3128  *	Free the REPL_LIST entries in the HW list starting at start_ptr.
   3129  * Parameters:
   3130  *	unit      - StrataSwitch PCI device unit number.
   3131  *	pipe      - Pipeline number.
   3132  *	start_ptr - Replication list's start pointer to
   3133  *	            REPL_LIST table.
   3134  * Returns:
   3135  *	BCM_E_XXX
   3136  */
   3137 STATIC int
   3138 _bcm_th_repl_list_free(int unit, int pipe, int start_ptr)
   3139 {
   3140     mmu_repl_list_tbl_entry_t repl_list_entry;
   3141     int	prev_repl_entry_ptr, repl_entry_ptr;
   3142     soc_mem_t repl_list_table;
   3143 
   3144     prev_repl_entry_ptr = -1;
   3145     repl_entry_ptr = start_ptr;
   3146     if(SOC_IS_TOMAHAWK3(unit)) {
   3147         repl_list_table = MMU_REPL_LIST_TBLm;
   3148         pipe = 0;
   3149     } else {
   3150     repl_list_table = REPL_LIST_TBL_PIPE(unit, pipe);
   3151     }
   3152     while (repl_entry_ptr != prev_repl_entry_ptr) {
   3153         SOC_IF_ERROR_RETURN
   3154             (soc_mem_read(unit, repl_list_table, MEM_BLOCK_ANY,
   3155                           repl_entry_ptr, &repl_list_entry));
   3156         BCM_IF_ERROR_RETURN
   3157             (_bcm_th_repl_list_entry_free(unit, pipe, repl_entry_ptr)); 
   3158         prev_repl_entry_ptr = repl_entry_ptr;
   3159         repl_entry_ptr = soc_MMU_REPL_LIST_TBLm_field32_get(unit,
   3160                 &repl_list_entry, NEXTPTRf);
   3161     }
   3162 
   3163     return BCM_E_NONE;
   3164 }
   3165 
   3166 /*
   3167  * Function:
   3168  *	_bcm_th_repl_list_write
   3169  * Purpose:
   3170  *	Write the replication list contained in intf_vec into REPL_LIST table.
   3171  *      Return the start_ptr and total interface count.
   3172  * Parameters:
   3173  *	unit       - StrataSwitch PCI device unit number.
   3174  *	pipe       - Pipeline number.
   3175  *	start_ptr  - (OUT) Replication list's start pointer to
   3176  *	             REPL_LIST table.
   3177  *      intf_count - (OUT) Interface count.
   3178  *	intf_vec   - (IN) Vector of interfaces.
   3179  * Returns:
   3180  *	BCM_E_XXX
   3181  */
   3182 STATIC int
   3183 _bcm_th_repl_list_write(int unit, int pipe, int *start_ptr, int *intf_count,
   3184                         SHR_BITDCL *intf_vec)
   3185 {
   3186     int i;
   3187     int remaining_count;
   3188     int prev_repl_entry_ptr, repl_entry_ptr;
   3189     uint32 msb_max, msb;
   3190     uint32 ls_bits[2];
   3191     int rv = BCM_E_NONE;
   3192     int no_more_free_repl_entries;
   3193     mmu_repl_list_tbl_entry_t repl_list_entry;
   3194     soc_mem_t repl_list_table;
   3195     int max_rem_count = 5;
   3196 
   3197     *intf_count = 0;
   3198     for (i = 0; i < _SHR_BITDCLSIZE(REPL_INTF_TOTAL(unit)); i++) {
   3199         *intf_count += _shr_popcount(intf_vec[i]);
   3200     }
   3201 
   3202     if (*intf_count == 0) {
   3203         return BCM_E_NONE;
   3204     }
   3205     repl_list_table = REPL_LIST_TBL_PIPE(unit, pipe);
   3206     remaining_count = *intf_count;
   3207     prev_repl_entry_ptr = -1;
   3208     msb_max = _SHR_BITDCLSIZE(REPL_INTF_TOTAL(unit)) / 2; /* 32 -> 64 */
   3209     for (msb = 0; msb < msb_max; msb++) {
   3210         ls_bits[0] = intf_vec[2 * msb + 0];
   3211         ls_bits[1] = intf_vec[2 * msb + 1];
   3212         if ((ls_bits[0] != 0) || (ls_bits[1] != 0)) {
   3213             rv = _bcm_th_repl_list_entry_alloc(unit, pipe, &repl_entry_ptr);
   3214             if (rv == BCM_E_RESOURCE) {
   3215                 no_more_free_repl_entries = TRUE;
   3216             } else if (BCM_FAILURE(rv)) {
   3217                 return rv;
   3218             } else {
   3219                 no_more_free_repl_entries = FALSE;
   3220             }
   3221             if (prev_repl_entry_ptr == -1) {
   3222                 if (no_more_free_repl_entries) {
   3223                     return BCM_E_RESOURCE;
   3224                 }
   3225                 *start_ptr = repl_entry_ptr;
   3226             } else {
   3227                 if (no_more_free_repl_entries) {
   3228                     /* Terminate replication list */
   3229                     soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry,
   3230                             NEXTPTRf, prev_repl_entry_ptr);
   3231                 } else {
   3232                     soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry,
   3233                             NEXTPTRf, repl_entry_ptr);
   3234                 }
   3235                 SOC_IF_ERROR_RETURN
   3236                     (soc_mem_write(unit, repl_list_table, MEM_BLOCK_ALL, 
   3237                                    prev_repl_entry_ptr, &repl_list_entry));
   3238                 if (no_more_free_repl_entries) {
   3239                     /* Free the list already written */
   3240                     _bcm_th_repl_list_free(unit, pipe, *start_ptr);
   3241                     return BCM_E_RESOURCE;
   3242                 }
   3243             } 
   3244             prev_repl_entry_ptr = repl_entry_ptr;
   3245 
   3246             sal_memset(&repl_list_entry, 0, sizeof(repl_list_entry));
   3247             soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry,
   3248                     MSB_VLANf, msb);
   3249             soc_MMU_REPL_LIST_TBLm_field_set(unit, &repl_list_entry,
   3250                     LSB_VLAN_BMf, ls_bits);
   3251 
   3252             remaining_count -= (_shr_popcount(ls_bits[0]) +
   3253                     _shr_popcount(ls_bits[1]));
   3254             if (remaining_count > max_rem_count) {
   3255                 /* Set the RMNG_REPS field to all zeroes */
   3256                 soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry,
   3257                         RMNG_REPSf, 0);
   3258             } else if (remaining_count > 0) {
   3259                 soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry,
   3260                         RMNG_REPSf, remaining_count);
   3261             } else { /* No more intefaces left to be written */
   3262                 break;
   3263             }
   3264         }
   3265     }
   3266 
   3267     if (prev_repl_entry_ptr > 0) {
   3268         /* Write final entry */
   3269         soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry, NEXTPTRf,
   3270                 prev_repl_entry_ptr);
   3271         SOC_IF_ERROR_RETURN
   3272             (soc_mem_write(unit, repl_list_table, MEM_BLOCK_ALL, 
   3273                            prev_repl_entry_ptr, &repl_list_entry));
   3274     }
   3275 
   3276     return BCM_E_NONE;
   3277 }
   3278 
   3279 /*
   3280  * Function:
   3281  *	_bcm_th_repl_list_compare
   3282  * Purpose:
   3283  *	Compare replication list starting at given pointer to
   3284  *	the interface list contained in intf_vec.
   3285  * Parameters:
   3286  *	unit - StrataSwitch PCI device unit number.
   3287  *	pipe - Pipeline number.
   3288  *	start_ptr - Replication list's start pointer to REPL_LIST table.
   3289  *	intf_vec - Vector of interfaces.
   3290  * Returns:
   3291  *	BCM_E_XXX
   3292  */
   3293 STATIC int
   3294 _bcm_th_repl_list_compare(int unit, int pipe, int start_ptr,
   3295                           SHR_BITDCL *intf_vec)
   3296 {
   3297     soc_mem_t   repl_list_table;
   3298     uint32		msb, hw_msb, msb_max;
   3299     uint32		ls_bits[2], hw_ls_bits[2];
   3300     mmu_repl_list_tbl_entry_t repl_list_entry;
   3301     int	                repl_entry_ptr, prev_repl_entry_ptr;
   3302 
   3303     repl_list_table = REPL_LIST_TBL_PIPE(unit, pipe);
   3304     prev_repl_entry_ptr = -1;
   3305     repl_entry_ptr = start_ptr;
   3306     msb_max = _SHR_BITDCLSIZE(REPL_INTF_TOTAL(unit)) / 2; /* 32 -> 64 */
   3307 
   3308     for (msb = 0; msb < msb_max; msb++) {
   3309         ls_bits[0] = intf_vec[2 * msb + 0];
   3310         ls_bits[1] = intf_vec[2 * msb + 1];
   3311         if ((ls_bits[0] != 0) || (ls_bits[1] != 0)) {
   3312             if (repl_entry_ptr == prev_repl_entry_ptr) { /* HW list end */
   3313                 return BCM_E_NOT_FOUND;
   3314             }
   3315             SOC_IF_ERROR_RETURN
   3316                 (soc_mem_read(unit, repl_list_table, MEM_BLOCK_ANY, 
   3317                               repl_entry_ptr, &repl_list_entry));
   3318             hw_msb = soc_MMU_REPL_LIST_TBLm_field32_get(unit,
   3319                     &repl_list_entry, MSB_VLANf);
   3320             soc_MMU_REPL_LIST_TBLm_field_get(unit, &repl_list_entry,
   3321                     LSB_VLAN_BMf, hw_ls_bits);
   3322             if ((hw_msb != msb) || (ls_bits[0] != hw_ls_bits[0]) ||
   3323                     (ls_bits[1] != hw_ls_bits[1])) {
   3324                 return BCM_E_NOT_FOUND;
   3325             }
   3326             prev_repl_entry_ptr = repl_entry_ptr;
   3327             repl_entry_ptr = soc_MMU_REPL_LIST_TBLm_field32_get(unit,
   3328                     &repl_list_entry, NEXTPTRf);
   3329         }
   3330     }
   3331 
   3332     return BCM_E_NONE;
   3333 }
   3334 
   3335 /*
   3336  * Function:
   3337  *	_bcm_th_repl_intf_vec_construct
   3338  * Purpose:
   3339  *	Construct replication interface vector.
   3340  * Parameters:
   3341  *	unit       - StrataSwitch PCI device unit number.
   3342  *	port       - Port.
   3343  *	if_count   - Number of interfaces in replication list.
   3344  *      if_array   - (IN) List of interface numbers.
   3345  *      is_l3      - (IN) Indicates if interfaces are IPMC interfaces.
   3346  *      check_port - If if_array consists of L3 interfaces, this parameter 
   3347  *                   controls whether to check the given port is a member
   3348  *                   in each L3 interface's VLAN. This check should be  
   3349  *                   disabled when not needed, in order to improve
   3350  *                   performance.
   3351  *      intf_vec   - (OUT) Vector of interfaces.
   3352  * Returns:
   3353  *	BCM_E_XXX
   3354  */
   3355 STATIC int
   3356 _bcm_th_repl_intf_vec_construct(int unit, bcm_port_t port, int if_count,
   3357         bcm_if_t *if_array, int is_l3, int check_port, SHR_BITDCL *intf_vec)
   3358 {
   3359     int if_num;
   3360     bcm_l3_intf_t l3_intf;
   3361     pbmp_t pbmp, ubmp;
   3362     uint32 nh_flags;
   3363     bcm_l3_egress_t nh_info;
   3364     int nh_index;
   3365     egr_l3_next_hop_entry_t egr_nh;
   3366     int mac_oui, mac_non_oui;
   3367     bcm_mac_t rbridge_mac;
   3368     soc_field_t ent_type_fld = ENTRY_TYPEf;
   3369     uint32 ent_type_val = 7;
   3370 
   3371 #if defined(BCM_HGPROXY_COE_SUPPORT)
   3372     bcm_port_t port_in = port;
   3373 #endif
   3374 
   3375 #ifdef BCM_TOMAHAWK3_SUPPORT
   3376     egr_l3_next_hop_2_entry_t egr_nh2;
   3377     if(SOC_IS_TOMAHAWK3(unit)) {
   3378         ent_type_val = 3;
   3379     }
   3380 #endif
   3381 
   3382 
   3383 #if defined(BCM_HGPROXY_COE_SUPPORT)
   3384     if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   3385         BCM_GPORT_IS_SET(port) &&
   3386         _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) {
   3387             BCM_IF_ERROR_RETURN(
   3388                 _bcmi_coe_subport_physical_port_get(unit, port, &port));
   3389     }
   3390 #endif
   3391 
   3392     if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, DATA_TYPEf)) {
   3393         ent_type_fld = DATA_TYPEf;
   3394     }
   3395 
   3396     for (if_num = 0; if_num < if_count; if_num++) {
   3397         if (!BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, if_array[if_num])) {
   3398             /* L3 interface is used */
   3399 
   3400             if (if_array[if_num] > soc_mem_index_max(unit, EGR_L3_INTFm)) {
   3401                 return BCM_E_PARAM;
   3402             }
   3403 
   3404             if (check_port) {
   3405                 bcm_l3_intf_t_init(&l3_intf);
   3406                 l3_intf.l3a_intf_id = if_array[if_num];
   3407                 BCM_IF_ERROR_RETURN(bcm_esw_l3_intf_get(unit, &l3_intf));
   3408                 if (!SOC_IS_TRIDENT3X(unit)) {
   3409                     BCM_IF_ERROR_RETURN(bcm_esw_vlan_port_get(unit,
   3410                                         l3_intf.l3a_vid, &pbmp, &ubmp));
   3411                     if (!BCM_PBMP_MEMBER(pbmp, port)) {
   3412                         return BCM_E_PARAM;
   3413                     }
   3414                 }
   3415             }
   3416 
   3417             /* Get a next hop index if the L3 inteface is not already
   3418              * associated with one.
   3419              */
   3420             if (is_l3) { /* L3 interface is being added to IPMC group */
   3421                 if (REPL_L3_INTF_NEXT_HOP_IPMC(unit, if_array[if_num]) == -1) {
   3422                     bcm_l3_egress_t_init(&nh_info);
   3423                     nh_flags = _BCM_L3_SHR_MATCH_DISABLE |
   3424                         _BCM_L3_SHR_WRITE_DISABLE;
   3425                     BCM_IF_ERROR_RETURN
   3426                         (bcm_xgs3_nh_add(unit, nh_flags, &nh_info, &nh_index));
   3427 
   3428                     sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t));
   3429                     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   3430                             ent_type_fld, ent_type_val);
   3431                     if(soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm,
   3432                                     L3MC__INTF_NUMf)) {
   3433                     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   3434                             L3MC__INTF_NUMf, if_array[if_num]);
   3435                     }
   3436                     if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm,
   3437                                 L3MC__HG_MODIFY_ENABLEf)) {
   3438                         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   3439                                 L3MC__HG_MODIFY_ENABLEf, 0x1);
   3440                     }
   3441 
   3442                     if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm,
   3443                                 L3MC__L2_MC_DA_DISABLEf)) {
   3444                         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   3445                                 L3MC__L2_MC_DA_DISABLEf, 1);
   3446                     }
   3447                     if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm,
   3448                                 L3MC__L2_MC_SA_DISABLEf)) {
   3449                         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   3450                                 L3MC__L2_MC_SA_DISABLEf, 1);
   3451                     }
   3452                     if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm,
   3453                                 L3MC__L2_MC_VLAN_DISABLEf)) {
   3454                         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   3455                                 L3MC__L2_MC_VLAN_DISABLEf, 1);
   3456                     }
   3457 
   3458 #if defined(BCM_HGPROXY_COE_SUPPORT)
   3459                     if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   3460                         BCM_GPORT_IS_SET(port_in) &&
   3461                         _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port_in)) {
   3462                         bcm_module_t mod_out;
   3463                         bcm_port_t port_out;
   3464                         bcm_trunk_t trunk_id;
   3465                         int local_id;
   3466 
   3467                         BCM_IF_ERROR_RETURN(
   3468                             _bcm_esw_gport_resolve(unit, port_in,
   3469                                                    &mod_out, &port_out,
   3470                                                    &trunk_id, &local_id));
   3471                         if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm,
   3472                                                 L3MC__USE_MAC_DA_PROFILEf)) {
   3473                             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   3474                                                 L3MC__USE_MAC_DA_PROFILEf,
   3475                                                 TRUE);
   3476                         }
   3477                         if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm,
   3478                                                 L3MC__HG_MC_DST_PORT_NUMf)) {
   3479                             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   3480                                                 L3MC__HG_MC_DST_PORT_NUMf,
   3481                                                 port_out);
   3482                         }
   3483                         if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm,
   3484                                                 L3MC__HG_MC_DST_MODIDf)) {
   3485                             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   3486                                                 L3MC__HG_MC_DST_MODIDf,
   3487                                                 mod_out);
   3488                         }
   3489                     }
   3490 #endif
   3491                     SOC_IF_ERROR_RETURN(soc_mem_write(unit, EGR_L3_NEXT_HOPm,
   3492                                 MEM_BLOCK_ALL, nh_index, &egr_nh));
   3493 
   3494 #ifdef BCM_TOMAHAWK3_SUPPORT
   3495                     if(SOC_IS_TOMAHAWK3(unit)) {
   3496                         SOC_IF_ERROR_RETURN(
   3497                                 READ_EGR_L3_NEXT_HOP_2m(unit, MEM_BLOCK_ANY,
   3498                                     nh_index, &egr_nh2) );
   3499 
   3500                         soc_mem_field32_set(unit, EGR_L3_NEXT_HOP_2m, &egr_nh2,
   3501                             INTF_NUMf, if_array[if_num]);
   3502 
   3503                         SOC_IF_ERROR_RETURN(soc_mem_write(unit, EGR_L3_NEXT_HOP_2m,
   3504                                     MEM_BLOCK_ALL, nh_index, &egr_nh2));
   3505                     }
   3506 #endif
   3507                     REPL_L3_INTF_NEXT_HOP_IPMC(unit, if_array[if_num]) =
   3508                         nh_index;
   3509                 }
   3510                 SHR_BITSET(intf_vec,
   3511                     REPL_L3_INTF_NEXT_HOP_IPMC(unit, if_array[if_num]));
   3512 
   3513             } else { /* L3 interface is being added to Trill group */
   3514                 if (REPL_L3_INTF_NEXT_HOP_TRILL(unit, if_array[if_num]) == -1) {
   3515                     bcm_l3_egress_t_init(&nh_info);
   3516                     nh_flags = _BCM_L3_SHR_MATCH_DISABLE |
   3517                         _BCM_L3_SHR_WRITE_DISABLE;
   3518                     BCM_IF_ERROR_RETURN
   3519                         (bcm_xgs3_nh_add(unit, nh_flags, &nh_info, &nh_index));
   3520 
   3521                     sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t));
   3522                     if (SOC_IS_TD2_TT2(unit)) {
   3523                         /*
   3524                          * TD2 needs to set the entry_type to 0x7 (L3MC) 
   3525                          * in order to use trill_all_rbridges_macda as the DA 
   3526                          * in TRILL header 
   3527                          */
   3528                         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   3529                                 ent_type_fld, ent_type_val);
   3530                     } else
   3531                     {
   3532                         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   3533                                 ent_type_fld, 0);
   3534                     }
   3535 #ifdef BCM_TOMAHAWK3_SUPPORT
   3536                     if(SOC_IS_TOMAHAWK3(unit)) {
   3537                         SOC_IF_ERROR_RETURN(
   3538                                 READ_EGR_L3_NEXT_HOP_2m(unit, MEM_BLOCK_ANY,
   3539                                     nh_index, &egr_nh2) );
   3540                         soc_mem_field32_set(unit, EGR_L3_NEXT_HOP_2m, &egr_nh2,
   3541                             INTF_NUMf, if_array[if_num]);
   3542 
   3543                         SOC_IF_ERROR_RETURN(soc_mem_write(unit, EGR_L3_NEXT_HOP_2m,
   3544                                     MEM_BLOCK_ALL, nh_index, &egr_nh2));
   3545                     } else
   3546 #endif
   3547                     {
   3548                     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   3549                             L3__INTF_NUMf, if_array[if_num]);
   3550                     }
   3551                     /* Get and Set rbridge mac */
   3552                     BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit,
   3553                             bcmSwitchTrillBroadcastDestMacOui, &mac_oui)); 
   3554                     BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit,
   3555                             bcmSwitchTrillBroadcastDestMacNonOui, &mac_non_oui)); 
   3556                     rbridge_mac[0] = (mac_oui >> 16) & 0xff;
   3557                     rbridge_mac[1] = (mac_oui >> 8) & 0xff;
   3558                     rbridge_mac[2] = mac_oui & 0xff;
   3559                     rbridge_mac[3] = (mac_non_oui >> 16) & 0xff;
   3560                     rbridge_mac[4] = (mac_non_oui >> 8) & 0xff;
   3561                     rbridge_mac[5] = mac_non_oui & 0xff;
   3562                     soc_mem_mac_addr_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   3563                             L3__MAC_ADDRESSf, rbridge_mac);
   3564 
   3565                     SOC_IF_ERROR_RETURN(soc_mem_write(unit, EGR_L3_NEXT_HOPm,
   3566                                 MEM_BLOCK_ALL, nh_index, &egr_nh));
   3567 
   3568                     REPL_L3_INTF_NEXT_HOP_TRILL(unit, if_array[if_num]) =
   3569                         nh_index;
   3570                 }
   3571                 SHR_BITSET(intf_vec,
   3572                     REPL_L3_INTF_NEXT_HOP_TRILL(unit, if_array[if_num]));
   3573             }
   3574         } else {
   3575             /* Next hop is used */
   3576             SHR_BITSET(intf_vec,
   3577                     if_array[if_num] - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit));
   3578         }
   3579     }
   3580 
   3581     return BCM_E_NONE;
   3582 }
   3583 
   3584 /*
   3585  * Function:
   3586  *	_bcm_th_ipmc_cut_through_eligibility_set
   3587  * Purpose:
   3588  *	Check cut-through eligibility for a given replication group.
   3589  * Parameters:
   3590  *	unit       - StrataSwitch PCI device unit number.
   3591  *	repl_group - The replication group number.
   3592  *	port       - Port to assign replication list.
   3593  * Returns:
   3594  *	BCM_E_XXX
   3595  */
   3596 int
   3597 _bcm_th_ipmc_cut_through_eligibility_set(int unit, int repl_group)
   3598 {
   3599     int rv = BCM_E_NONE;
   3600     int i, pipe, member_bitmap_width;
   3601     int member = 0;
   3602     soc_mem_t repl_group_table;
   3603     soc_field_t member_bitmap_f;
   3604     mmu_repl_group_info_tbl_entry_t repl_group_entry;
   3605     soc_pbmp_t old_member_bitmap[4];
   3606     soc_pbmp_t new_member_bitmap[4];
   3607     uint32 fldbuf[SOC_PBMP_WORD_MAX];
   3608     soc_info_t *si;
   3609     soc_pbmp_t l3_pbmp;
   3610     bcm_port_t mmu_port, phy_port, logical_port;
   3611     int cut_through_eligible = TRUE;
   3612     ipmc_entry_t l3_ipmc_entry;
   3613 #if defined(BCM_TRIDENT3_SUPPORT)
   3614     bcm_multicast_t  ipmc_group = 0;
   3615 #endif
   3616 
   3617     member_bitmap_f = PIPE_MEMBER_BMPf;
   3618     member_bitmap_width = soc_mem_field_length(unit, MMU_REPL_GROUP_INFO_TBLm,
   3619                                                member_bitmap_f);
   3620     si = &SOC_INFO(unit);
   3621     SOC_PBMP_CLEAR(l3_pbmp);
   3622 
   3623     for (pipe = 0; pipe < NUM_PIPES(unit); pipe++) {
   3624         SOC_PBMP_CLEAR(old_member_bitmap[pipe]);
   3625         SOC_PBMP_CLEAR(new_member_bitmap[pipe]);
   3626         /* Read pipeline's replication group table */
   3627         repl_group_table = REPL_GROUP_INFO_TBL_PIPE(unit, pipe);
   3628 
   3629         SOC_IF_ERROR_RETURN
   3630             (soc_mem_read(unit, repl_group_table, MEM_BLOCK_ANY,
   3631                           repl_group, &repl_group_entry));
   3632              sal_memset(fldbuf, 0, SOC_PBMP_WORD_MAX * sizeof(uint32));
   3633              soc_mem_field_get(unit, repl_group_table, (uint32 *)&repl_group_entry,
   3634                                member_bitmap_f, fldbuf);
   3635              for (i = 0; i < SOC_PBMP_WORD_MAX; i++) {
   3636                 SOC_PBMP_WORD_SET(old_member_bitmap[pipe], i, fldbuf[i]);
   3637              }
   3638             if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) {
   3639                 int aggid = TH_AGG_ID_INVALID;
   3640                 PBMP_ITER(PBMP_PIPE(unit, pipe), logical_port) {
   3641                     rv = bcm_th_port_to_aggid(unit, logical_port, &aggid);
   3642                     if (rv == BCM_E_NONE) {
   3643                         if (SOC_PBMP_MEMBER(old_member_bitmap[pipe], aggid)) {
   3644                             SOC_PBMP_PORT_ADD(new_member_bitmap[pipe], logical_port);
   3645                         }
   3646                     }
   3647                 }
   3648             } else {
   3649                 for (i = 0; i < member_bitmap_width; i++) {
   3650                     if (SOC_PBMP_MEMBER(old_member_bitmap[pipe], i)) {
   3651                         mmu_port = i + mmu_port_stride[unit] * pipe;
   3652                         phy_port = si->port_m2p_mapping[mmu_port];
   3653                         logical_port = si->port_p2l_mapping[phy_port];
   3654                         SOC_PBMP_PORT_ADD(new_member_bitmap[pipe], logical_port);
   3655                     }
   3656                 }
   3657             }
   3658             SOC_PBMP_OR(l3_pbmp, new_member_bitmap[pipe]);
   3659     }
   3660 #if defined(BCM_TRIDENT3_SUPPORT)
   3661     /* For VXLAN IPMC, cut-through is always disabled.
   3662     *  The IP header for the tunnel needs the entire length of
   3663     *  the IP payload. This implies that the MMU must store the
   3664     *  entire packet, determining its length and then forward it
   3665     *  to the EP.
   3666     */
   3667     (void)_bcm_tr_multicast_ipmc_group_type_get(unit, repl_group, &ipmc_group);
   3668     if (SOC_IS_TRIDENT3X(unit) &&
   3669         (_BCM_MULTICAST_TYPE_VXLAN == _BCM_MULTICAST_TYPE_GET(ipmc_group))){
   3670         cut_through_eligible = FALSE;
   3671     } else
   3672 #endif
   3673     {
   3674     SOC_PBMP_ITER(l3_pbmp, member) {
   3675         /*
   3676          * Packets with a single logical replication per port are
   3677          * eligible for cut-through consideration. If the IPMC group has more
   3678          * than 1 switch copy per egress port, DO_NOT_CUT_THROUGH bit in
   3679          * L3_IPMC table must be set for the ipmc group.
   3680          */
   3681         /* Coverity issue ignored:
   3682          * Maximum port number used in l3_pbmp
   3683          * should never exceed SOC_MAX_NUM_PP_PORTS */
   3684         /* coverity[overrun-local : FALSE] */         
   3685         if (REPL_PORT_GROUP_INTF_COUNT(unit, member, repl_group) > 1) {
   3686             cut_through_eligible = FALSE;
   3687             break;
   3688         }
   3689     }
   3690     }
   3691     
   3692     soc_mem_lock(unit, L3_IPMCm);
   3693     rv = READ_L3_IPMCm(unit, MEM_BLOCK_ANY, repl_group, &l3_ipmc_entry);
   3694     if (BCM_SUCCESS(rv)) {
   3695         if (!cut_through_eligible) {
   3696             soc_L3_IPMCm_field32_set(unit, &l3_ipmc_entry, DO_NOT_CUT_THROUGHf,
   3697                                      !cut_through_eligible);
   3698         } else {
   3699             /* This is needed to set the mode back to cut-through when
   3700              * intf_count <= 1 after bcm_th_ipmc_egress_intf_delete is called.
   3701              */
   3702             soc_L3_IPMCm_field32_set(unit, &l3_ipmc_entry, DO_NOT_CUT_THROUGHf,
   3703                                      !cut_through_eligible);
   3704         }
   3705         rv = WRITE_L3_IPMCm(unit, MEM_BLOCK_ALL, repl_group, &l3_ipmc_entry);
   3706     }
   3707     soc_mem_unlock(unit, L3_IPMCm);
   3708  
   3709     return rv;
   3710 
   3711 }
   3712 
   3713 /*
   3714  * Function:
   3715  *	bcm_th_ipmc_egress_intf_set
   3716  * Purpose:
   3717  *	Assign set of egress interfaces to port's replication list for chosen
   3718  *	replication group.
   3719  * Parameters:
   3720  *	unit       - StrataSwitch PCI device unit number.
   3721  *	repl_group - The replication group number.
   3722  *	port       - Port to assign replication list.
   3723  *	if_count   - Number of interfaces in replication list.
   3724  *      if_array   - (IN) List of interface numbers.
   3725  *      is_l3      - (IN) Indicates if multicast group is of type IPMC.
   3726  *      check_port - (IN) If if_array consists of L3 interfaces, this parameter 
   3727  *                        controls whether to check the given port is a member
   3728  *                        in each L3 interface's VLAN. This check should be  
   3729  *                        disabled when not needed, in order to improve
   3730  *                        performance.
   3731  * Returns:
   3732  *	BCM_E_XXX
   3733  */
   3734 int
   3735 bcm_th_ipmc_egress_intf_set(int unit, int repl_group, bcm_port_t port,
   3736                             int if_count, bcm_if_t *if_array, int is_l3,
   3737                             int check_port)
   3738 {
   3739     int rv = BCM_E_NONE;
   3740     int pipe;
   3741     int set_repl_list;
   3742     int prev_start_ptr, list_start_ptr=0;
   3743     int alloc_size;
   3744     SHR_BITDCL *intf_vec = NULL;
   3745     int repl_hash;
   3746     _bcm_repl_list_info_t *rli_current, *rli_prev;
   3747     int intf_count;
   3748     int new_repl_list = FALSE;
   3749     bcm_port_t port_in = port;
   3750 
   3751     REPL_INIT(unit);
   3752     REPL_GROUP_ID(unit, repl_group);
   3753 #if defined(BCM_HGPROXY_COE_SUPPORT)
   3754     if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   3755         BCM_GPORT_IS_SET(port) &&
   3756         _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) {
   3757             BCM_IF_ERROR_RETURN(
   3758                 _bcmi_coe_subport_physical_port_get(unit, port, &port));
   3759     }
   3760 #endif
   3761 
   3762 
   3763     if (!IS_CPU_PORT(unit, port)) {
   3764         REPL_PORT_CHECK(unit, port);
   3765     }
   3766     BCM_IF_ERROR_RETURN(_bcm_th_port_pipe_get(unit, port, &pipe));
   3767 
   3768 #ifdef BCM_TOMAHAWK3_SUPPORT
   3769     if (SOC_IS_TOMAHAWK3(unit)) {
   3770         if (if_count > TH3_IPMC_MAX_INTF_COUNT) {
   3771             return BCM_E_PARAM;
   3772         }
   3773     }
   3774 #endif
   3775     if (if_count > REPL_INTF_TOTAL(unit)) {
   3776         return BCM_E_PARAM;
   3777     } else if (if_count > 0) {
   3778         set_repl_list = TRUE;
   3779     } else {
   3780         set_repl_list = FALSE;
   3781     }
   3782 
   3783     if (REPL_PORT_GROUP_INFO(unit, port) == NULL) {
   3784         return BCM_E_PORT;
   3785     }
   3786 
   3787     if ((if_count == 0) &&
   3788         (REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group) == 0)) {
   3789         return BCM_E_NONE;
   3790     }
   3791 
   3792     REPL_LOCK(unit);
   3793 #ifdef BCM_TOMAHAWK3_SUPPORT
   3794     if(SOC_IS_TOMAHAWK3(unit)) {
   3795         rv = bcm_th3_repl_list_start_ptr_get(unit, repl_group, port,
   3796             &prev_start_ptr);
   3797         pipe = 0;
   3798     } else
   3799 #endif
   3800     {
   3801     /* Get current replication list start pointer of (repl_group, port) */
   3802     rv = _bcm_th_repl_list_start_ptr_get(unit, repl_group, port,
   3803             &prev_start_ptr);
   3804     }
   3805     if (BCM_FAILURE(rv)) {
   3806         goto intf_set_done;
   3807     }
   3808 
   3809     if (set_repl_list) { 
   3810         /* Set new replication list for given (repl_group, port) */
   3811 
   3812         /* Interface validation and vector construction */
   3813         alloc_size = SHR_BITALLOCSIZE(REPL_INTF_TOTAL(unit));
   3814         intf_vec = sal_alloc(alloc_size, "Repl interface vector");
   3815         if (intf_vec == NULL) {
   3816             rv = BCM_E_MEMORY;
   3817             goto intf_set_done;
   3818         }
   3819         sal_memset(intf_vec, 0, alloc_size);
   3820         rv = _bcm_th_repl_intf_vec_construct(unit, port_in, if_count, if_array,
   3821                 is_l3, check_port, intf_vec);
   3822         if (BCM_FAILURE(rv)) {
   3823             goto intf_set_done;
   3824         }
   3825 
   3826         /* Search for matching replication list */
   3827         repl_hash = _shr_crc32b(0, (uint8 *)intf_vec, REPL_INTF_TOTAL(unit));
   3828         for (rli_current = REPL_LIST_INFO(unit, pipe); rli_current != NULL;
   3829                 rli_current = rli_current->next) {
   3830             if (repl_hash == rli_current->hash) {
   3831 #ifdef BCM_TOMAHAWK3_SUPPORT
   3832                 if(SOC_IS_TOMAHAWK3(unit)) {
   3833                     rv = _bcm_th3_repl_list_compare(unit, pipe,
   3834                                         rli_current->index, intf_vec);
   3835 
   3836                 } else
   3837 #endif
   3838                 {
   3839                 rv = _bcm_th_repl_list_compare(unit, pipe, rli_current->index,
   3840                         intf_vec);
   3841                 }
   3842                 if (rv == BCM_E_NOT_FOUND) {
   3843                     continue; /* Not a match */
   3844                 } else if (BCM_FAILURE(rv)) {
   3845                     goto intf_set_done; 
   3846                 } else {
   3847                     break; /* Match */
   3848                 }
   3849             }
   3850         }
   3851 
   3852         if (rli_current != NULL) {
   3853             /* Found a match */
   3854             if (prev_start_ptr == rli_current->index) {
   3855                 /* (repl_group, port) already points to this list, so done */
   3856                 rv = BCM_E_NONE;
   3857                 goto intf_set_done;
   3858             } else {
   3859                 list_start_ptr = rli_current->index;
   3860                 intf_count = rli_current->list_size;
   3861             }
   3862         } else {
   3863             /* Not a match, make a new chain */
   3864 #ifdef BCM_TOMAHAWK3_SUPPORT
   3865             if(SOC_IS_TOMAHAWK3(unit)) {
   3866                 rv = _bcm_th3_repl_list_write(unit, pipe, &list_start_ptr,
   3867                     &intf_count, intf_vec);
   3868             } else
   3869 #endif
   3870             {
   3871             rv = _bcm_th_repl_list_write(unit, pipe, &list_start_ptr,
   3872                     &intf_count, intf_vec);
   3873             }
   3874             if (BCM_FAILURE(rv)) {
   3875                 goto intf_set_done;
   3876             }
   3877 
   3878             if (intf_count > 0) {
   3879                 /* Update data structures */
   3880                 alloc_size = sizeof(_bcm_repl_list_info_t);
   3881                 rli_current = sal_alloc(alloc_size, "IPMC repl list info");
   3882                 if (rli_current == NULL) {
   3883                     /* Release list */
   3884                     _bcm_th_repl_list_free(unit, pipe, list_start_ptr);
   3885                     rv = BCM_E_MEMORY;
   3886                     goto intf_set_done;
   3887                 }
   3888                 sal_memset(rli_current, 0, alloc_size);
   3889                 rli_current->index = list_start_ptr;
   3890                 rli_current->hash = repl_hash;
   3891                 rli_current->list_size = intf_count;
   3892                 rli_current->next = REPL_LIST_INFO(unit, pipe);
   3893                 REPL_LIST_INFO(unit, pipe) = rli_current;
   3894                 new_repl_list = TRUE;
   3895             } else {
   3896                 rv = BCM_E_INTERNAL;
   3897                 goto intf_set_done;
   3898             }
   3899         }
   3900 
   3901         /* Update replication list start pointer */
   3902 #ifdef BCM_TOMAHAWK3_SUPPORT
   3903         if  (SOC_IS_TOMAHAWK3(unit)) {
   3904             rv = bcm_th3_repl_list_start_ptr_set(unit, repl_group, port,
   3905                 list_start_ptr, intf_count);
   3906 
   3907         } else
   3908 
   3909 #endif
   3910         {
   3911         rv = _bcm_th_repl_list_start_ptr_set(unit, repl_group, port,
   3912                 list_start_ptr, intf_count);
   3913         }
   3914         if (BCM_FAILURE(rv)) {
   3915             if (new_repl_list) {
   3916                 _bcm_th_repl_list_free(unit, pipe, list_start_ptr);
   3917                 REPL_LIST_INFO(unit, pipe) = rli_current->next;
   3918                 sal_free(rli_current);
   3919             }
   3920             goto intf_set_done;
   3921         }
   3922         (rli_current->refcount)++;
   3923         REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group) = intf_count;
   3924 
   3925     } else { 
   3926         /* Delete replication list for given (repl_group, port) */
   3927 
   3928         if (prev_start_ptr != 0) {
   3929 #ifdef BCM_TOMAHAWK3_SUPPORT
   3930             if (SOC_IS_TOMAHAWK3(unit)) {
   3931                 rv = bcm_th3_repl_list_start_ptr_set(unit, repl_group,
   3932                                                                  port, 0, 0);
   3933 
   3934             } else
   3935 #endif
   3936             {
   3937                 rv = _bcm_th_repl_list_start_ptr_set(unit, repl_group,
   3938                                                                 port, 0, 0);
   3939             }
   3940             if (BCM_FAILURE(rv)) {
   3941                 goto intf_set_done;
   3942             }
   3943         }
   3944         REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group) = 0;
   3945     }
   3946 
   3947     /* Delete old replication list */
   3948     if (prev_start_ptr != 0) {
   3949         rli_prev = NULL;
   3950         for (rli_current = REPL_LIST_INFO(unit, pipe); rli_current != NULL;
   3951                 rli_current = rli_current->next) {
   3952             if (prev_start_ptr == rli_current->index) {
   3953                 (rli_current->refcount)--;
   3954                 if (rli_current->refcount == 0) {
   3955                     /* Free these linked list entries */
   3956                     if (rli_prev == NULL) {
   3957                         REPL_LIST_INFO(unit, pipe) = rli_current->next;
   3958                     } else {
   3959                         rli_prev->next = rli_current->next;
   3960                     }
   3961 #ifdef BCM_TOMAHAWK3_SUPPORT
   3962                     /* the repl list is first put into a recycle candidate pool */
   3963                     if(SOC_IS_TOMAHAWK3(unit)) {
   3964 
   3965                         rli_current->next = _repl_list_recycle_array[unit]->next;
   3966                         _repl_list_recycle_array[unit]->next = rli_current;
   3967                         (_repl_list_recycle_array[unit]->list_size)++;
   3968 
   3969                     } else
   3970 #endif
   3971                     {
   3972                         _bcm_th_repl_list_free(unit, pipe, prev_start_ptr);
   3973                     sal_free(rli_current);
   3974                 }
   3975                 }
   3976                 break;
   3977             }
   3978             rli_prev = rli_current;
   3979         }
   3980     }
   3981 #ifdef BCM_TOMAHAWK3_SUPPORT
   3982     if(SOC_IS_TOMAHAWK3(unit)) {
   3983         goto intf_set_done;
   3984     }
   3985 #endif
   3986     /*
   3987      * Packets with a single logical replication per port are 
   3988      * eligible for cut-through consideration. If the IPMC group has more
   3989      * than 1 switch copy per egress port, DO_NOT_CUT_THROUGH bit in 
   3990      * L3_IPMC table must be set for the ipmc group.
   3991      */     
   3992     rv = _bcm_th_ipmc_cut_through_eligibility_set(unit, repl_group);
   3993 
   3994 intf_set_done:
   3995 
   3996     REPL_UNLOCK(unit);
   3997 
   3998     if (intf_vec != NULL) {
   3999         sal_free(intf_vec);
   4000     }
   4001 
   4002     return rv;
   4003 }
   4004 
   4005 /*
   4006  * Function:
   4007  *	bcm_th_ipmc_egress_intf_get
   4008  * Purpose:
   4009  *	Retrieve set of egress interfaces to port's replication list for chosen
   4010  *	replication group.
   4011  * Parameters:
   4012  *	unit       - StrataSwitch PCI device unit number.
   4013  *	repl_group - The replication group number.
   4014  *	port       - Port from which to get replication list.
   4015  *	if_max     - Maximum number of interfaces in replication list.
   4016  *      if_array   - (OUT) List of interface numbers.
   4017  *	if_count   - (OUT) Number of interfaces in replication list.
   4018  * Returns:
   4019  *	BCM_E_XXX
   4020  * Notes:
   4021  *      If the input parameter if_max = 0, return in the output parameter
   4022  *      if_count the total number of interfaces in the specified multicast 
   4023  *      group's replication list.
   4024  */
   4025 int
   4026 bcm_th_ipmc_egress_intf_get(int unit, int repl_group, bcm_port_t port,
   4027                             int if_max, bcm_if_t *if_array, int *if_count)
   4028 {
   4029     int rv = BCM_E_NONE;
   4030     int pipe;
   4031     int prev_repl_entry_ptr, repl_entry_ptr;
   4032     int intf_count;
   4033     int l3_intf, intf_base;
   4034     int ls_pos;
   4035     uint32 ls_bits[2];
   4036     mmu_repl_list_tbl_entry_t repl_list_entry;
   4037     int next_hop_index;
   4038     int entry_type;
   4039     egr_l3_next_hop_entry_t egr_nh;
   4040 #ifdef BCM_TOMAHAWK3_SUPPORT
   4041     egr_l3_next_hop_2_entry_t egr_nh2;
   4042 #endif
   4043     soc_mem_t repl_list_table;
   4044     soc_field_t ent_type_fld = ENTRY_TYPEf;
   4045     if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, DATA_TYPEf)) {
   4046         ent_type_fld = DATA_TYPEf;
   4047     }
   4048 
   4049     REPL_INIT(unit);
   4050     REPL_GROUP_ID(unit, repl_group);
   4051     if (!IS_CPU_PORT(unit, port)) {
   4052         REPL_PORT_CHECK(unit, port);
   4053     }
   4054     BCM_IF_ERROR_RETURN(_bcm_th_port_pipe_get(unit, port, &pipe));
   4055 
   4056     if (if_max < 0) {
   4057         return BCM_E_PARAM;
   4058     } else if (if_max > 0 && NULL == if_array) {
   4059         return BCM_E_PARAM;
   4060     }
   4061 
   4062     if (NULL == if_count) {
   4063         return BCM_E_PARAM;
   4064     }
   4065 
   4066     if(SOC_IS_TOMAHAWK3(unit)) {
   4067         repl_list_table = MMU_REPL_LIST_TBLm;
   4068     } else {
   4069     repl_list_table = REPL_LIST_TBL_PIPE(unit, pipe);
   4070     }
   4071 
   4072     REPL_LOCK(unit);
   4073     if (REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group) == 0) {
   4074         *if_count = 0;
   4075         REPL_UNLOCK(unit);
   4076         return BCM_E_NONE;
   4077     }
   4078 
   4079 #ifdef BCM_TOMAHAWK3_SUPPORT
   4080     if(SOC_IS_TOMAHAWK3(unit)) {
   4081         rv = bcm_th3_repl_list_start_ptr_get(unit, repl_group, port,
   4082                                                         &repl_entry_ptr);
   4083     } else
   4084 #endif
   4085     {
   4086     rv = _bcm_th_repl_list_start_ptr_get(unit, repl_group, port,
   4087             &repl_entry_ptr);
   4088     }
   4089     if (BCM_FAILURE(rv)) {
   4090         goto intf_get_done;
   4091     }
   4092 
   4093     prev_repl_entry_ptr = -1;
   4094     intf_count = 0;
   4095     while (repl_entry_ptr != prev_repl_entry_ptr) {
   4096         rv = soc_mem_read(unit, repl_list_table, MEM_BLOCK_ANY, 
   4097                           repl_entry_ptr, &repl_list_entry);
   4098 
   4099         if (BCM_FAILURE(rv)) {
   4100             goto intf_get_done;
   4101         }
   4102 #ifdef BCM_TOMAHAWK3_SUPPORT
   4103         if(SOC_IS_TOMAHAWK3(unit)) {
   4104             uint32 nh_mode;
   4105 
   4106             nh_mode = soc_MMU_REPL_LIST_TBLm_field32_get(unit, &repl_list_entry,
   4107                             MODEf);
   4108             if(nh_mode) {
   4109                 /* sparse mode */
   4110                 int i;
   4111                 for(i = 0; i < 4; i++) {
   4112                     rv = _bcm_th3_sparse_mode_egress_intf_get(unit,
   4113                             repl_entry_ptr, i, if_array, &intf_count);
   4114                     if(BCM_FAILURE(rv)) {
   4115                         goto intf_get_done;
   4116                     }
   4117                     if (intf_count == if_max) {
   4118                         *if_count = intf_count;
   4119                         goto intf_get_done;
   4120                     }
   4121 
   4122                 }
   4123                 prev_repl_entry_ptr = repl_entry_ptr;
   4124                 repl_entry_ptr = soc_MMU_REPL_LIST_TBLm_field32_get(unit,
   4125                         &repl_list_entry, NEXTPTRf);
   4126                 if (intf_count >= REPL_PORT_GROUP_INTF_COUNT(unit,
   4127                                                     port, repl_group)) {
   4128                     break;
   4129                 }
   4130 
   4131                 continue;
   4132             }
   4133         }
   4134 #endif
   4135         /* Each MSB represents 64 entries in LSB bitmap */
   4136         intf_base = soc_MMU_REPL_LIST_TBLm_field32_get(unit, &repl_list_entry,
   4137                 MSB_VLANf) * 64;
   4138         soc_MMU_REPL_LIST_TBLm_field_get(unit, &repl_list_entry,
   4139                 LSB_VLAN_BMf, ls_bits);
   4140 
   4141         for (ls_pos = 0; ls_pos < 64; ls_pos++) {
   4142             if (ls_bits[ls_pos / 32] & (1 << (ls_pos % 32))) {
   4143                 if (if_max == 0) {
   4144                     intf_count++;
   4145                 } else {
   4146                     next_hop_index = intf_base + ls_pos;
   4147                     if_array[intf_count] = next_hop_index +
   4148                         BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   4149 
   4150                     /* Check if next hop index corresponds to
   4151                      * an IPMC or Trill interface.
   4152                      */
   4153                     rv = READ_EGR_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY,
   4154                             next_hop_index, &egr_nh);
   4155                     if (BCM_FAILURE(rv)) {
   4156                         goto intf_get_done;
   4157                     }
   4158 #ifdef BCM_TOMAHAWK3_SUPPORT
   4159                     if (SOC_IS_TOMAHAWK3(unit)) {
   4160                         rv = READ_EGR_L3_NEXT_HOP_2m(unit, MEM_BLOCK_ANY,
   4161                                 next_hop_index, &egr_nh2);
   4162                         if (BCM_FAILURE(rv)) {
   4163                             goto intf_get_done;
   4164                         }
   4165                     }
   4166 #endif
   4167                     entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit,
   4168                             &egr_nh, ent_type_fld);
   4169                     if (entry_type == 0) {
   4170 #ifdef BCM_TOMAHAWK3_SUPPORT
   4171                         if (SOC_IS_TOMAHAWK3(unit)) {
   4172                             l3_intf = soc_EGR_L3_NEXT_HOP_2m_field32_get(unit,
   4173                                 &egr_nh2, INTF_NUMf);
   4174 
   4175                         } else
   4176 #endif
   4177                         {
   4178                         l3_intf = soc_EGR_L3_NEXT_HOPm_field32_get(unit,
   4179                                 &egr_nh, L3__INTF_NUMf);
   4180                         }
   4181                         if (REPL_L3_INTF_NEXT_HOP_TRILL(unit, l3_intf) ==
   4182                                 next_hop_index) {
   4183                             if_array[intf_count] = l3_intf;
   4184                         } 
   4185                     } else if (entry_type == 7) {
   4186 #ifdef BCM_TOMAHAWK3_SUPPORT
   4187                         if (SOC_IS_TOMAHAWK3(unit)) {
   4188                             l3_intf = soc_EGR_L3_NEXT_HOP_2m_field32_get(unit,
   4189                                     &egr_nh2, INTF_NUMf);
   4190 
   4191                         } else
   4192 #endif
   4193                         {
   4194                         l3_intf = soc_EGR_L3_NEXT_HOPm_field32_get(unit,
   4195                                 &egr_nh, L3MC__INTF_NUMf);
   4196                         }
   4197                         if (REPL_L3_INTF_NEXT_HOP_IPMC(unit, l3_intf) ==
   4198                                 next_hop_index) {
   4199                             if_array[intf_count] = l3_intf;
   4200                         }
   4201                     }
   4202 #ifdef BCM_TOMAHAWK3_SUPPORT
   4203                     else if ((entry_type == 3) &&
   4204                              (SOC_IS_TOMAHAWK3(unit))) {
   4205                         l3_intf = soc_EGR_L3_NEXT_HOP_2m_field32_get(unit,
   4206                                     &egr_nh2, INTF_NUMf);
   4207                         if (REPL_L3_INTF_NEXT_HOP_IPMC(unit, l3_intf) ==
   4208                                 next_hop_index) {
   4209                             if_array[intf_count] = l3_intf;
   4210                         } 
   4211 
   4212                     }
   4213 #endif
   4214 
   4215                     intf_count++;
   4216                     if (intf_count == if_max) {
   4217                         *if_count = intf_count;
   4218                         goto intf_get_done;
   4219                     }
   4220                 }
   4221             }
   4222         }
   4223         prev_repl_entry_ptr = repl_entry_ptr;
   4224         repl_entry_ptr = soc_MMU_REPL_LIST_TBLm_field32_get(unit,
   4225                 &repl_list_entry, NEXTPTRf);
   4226         if (intf_count >= REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group)) {
   4227             break;
   4228         }
   4229     }
   4230 
   4231     *if_count = intf_count;
   4232 
   4233 intf_get_done:
   4234     REPL_UNLOCK(unit);
   4235     return rv;
   4236 }
   4237 
   4238 /*
   4239  * Function:
   4240  *      bcm_th_ipmc_egress_intf_add
   4241  * Purpose:
   4242  *      Add L3 interface to selected ports' replication list for chosen
   4243  *      IPMC group.
   4244  * Parameters:
   4245  *      unit     - StrataSwitch PCI device unit number.
   4246  *      ipmc_id  - IPMC group number.
   4247  *      port     - port to add.
   4248  *      l3_intf  - L3 interface to replicate.
   4249  * Returns:
   4250  *      BCM_E_XXX
   4251  */
   4252 int
   4253 bcm_th_ipmc_egress_intf_add(int unit, int ipmc_id, bcm_port_t port,
   4254                             bcm_l3_intf_t *l3_intf)
   4255 {
   4256     bcm_if_t *if_array = NULL;
   4257     int  intf_num, intf_max, alloc_size, rv = BCM_E_NONE;
   4258     pbmp_t pbmp, ubmp;
   4259 #ifdef BCM_TOMAHAWK3_SUPPORT
   4260     bcm_pbmp_t l2_pbmp, l3_pbmp;
   4261     bcm_port_t port_idx;
   4262     int th3_if_count = 0;
   4263 #endif
   4264 
   4265     REPL_INIT(unit);
   4266     REPL_GROUP_ID(unit, ipmc_id);
   4267     REPL_PORT_CHECK(unit, port);
   4268 
   4269     /* Check if port belongs to this VLAN */
   4270     if (!SOC_IS_TRIDENT3X(unit)) {
   4271         BCM_IF_ERROR_RETURN
   4272             (bcm_esw_vlan_port_get(unit, l3_intf->l3a_vid, &pbmp, &ubmp));
   4273         if (!SOC_PBMP_MEMBER(pbmp, port)) {
   4274             return BCM_E_PARAM;
   4275         }
   4276     }
   4277 
   4278     intf_max = REPL_INTF_TOTAL(unit);
   4279 #ifdef BCM_TOMAHAWK3_SUPPORT
   4280     if (SOC_IS_TOMAHAWK3(unit)) {
   4281         intf_max = TH3_IPMC_MAX_INTF_COUNT;
   4282         /* Retrieve the number of replications for this MC group across all
   4283          * ports */
   4284         rv = _bcm_esw_multicast_ipmc_read(unit, ipmc_id, &l2_pbmp, &l3_pbmp);
   4285         /* Add any L2 copies for the MC group */
   4286         BCM_PBMP_COUNT(l2_pbmp, th3_if_count);
   4287         /* Iterate among all L3 ports to get the sum of interface counts */
   4288         alloc_size = intf_max * sizeof(bcm_if_t);
   4289         if_array = sal_alloc(alloc_size, "IPMC repl interface array");
   4290         if (if_array == NULL) {
   4291             return BCM_E_MEMORY;
   4292         }
   4293 
   4294         REPL_LOCK(unit);
   4295         BCM_PBMP_ITER(l3_pbmp, port_idx) {
   4296             if (port_idx == 158) {
   4297                 /* Skip checke for spare port used in B0 WAR*/
   4298                 continue;
   4299             }
   4300             rv = bcm_th_ipmc_egress_intf_get(unit, ipmc_id, port_idx, intf_max,
   4301                                      if_array, &intf_num);
   4302             if (!BCM_SUCCESS(rv)) {
   4303                 REPL_UNLOCK(unit);
   4304                 sal_free(if_array);
   4305                 return rv;
   4306             }
   4307             th3_if_count += intf_num;
   4308         }
   4309         REPL_UNLOCK(unit);
   4310         sal_free(if_array);
   4311         if (th3_if_count >= intf_max) {
   4312             return BCM_E_EXISTS;
   4313         }
   4314     }
   4315 #endif
   4316 
   4317     alloc_size = intf_max * sizeof(bcm_if_t);
   4318     if_array = sal_alloc(alloc_size, "IPMC repl interface array");
   4319     if (if_array == NULL) {
   4320         return BCM_E_MEMORY;
   4321     }
   4322 
   4323     REPL_LOCK(unit);
   4324     rv = bcm_th_ipmc_egress_intf_get(unit, ipmc_id, port, intf_max,
   4325                                      if_array, &intf_num);
   4326     if (BCM_SUCCESS(rv)) {
   4327         if (intf_num < intf_max) {
   4328             if_array[intf_num++] = l3_intf->l3a_intf_id;
   4329             rv = bcm_th_ipmc_egress_intf_set(unit, ipmc_id, port,
   4330                                              intf_num, if_array, TRUE, FALSE);
   4331         } else {
   4332             rv = BCM_E_EXISTS;
   4333         }
   4334     }
   4335 
   4336     REPL_UNLOCK(unit);
   4337     sal_free(if_array);
   4338     return rv;
   4339 }
   4340 
   4341 /*
   4342  * Function:
   4343  *      bcm_th_ipmc_egress_intf_delete
   4344  * Purpose:
   4345  *      Remove L3 interface from selected ports' replication list for chosen
   4346  *      IPMC group.
   4347  * Parameters:
   4348  *      unit     - StrataSwitch PCI device unit number.
   4349  *      ipmc_id  - IPMC group number.
   4350  *      port     - port to remove.
   4351  *      l3_intf  - L3 interface to delete from replication.
   4352  * Returns:
   4353  *      BCM_E_XXX
   4354  */
   4355 int
   4356 bcm_th_ipmc_egress_intf_delete(int unit, int ipmc_id, bcm_port_t port,
   4357                                bcm_l3_intf_t *l3_intf)
   4358 {
   4359     bcm_if_t *if_array = NULL;
   4360     int alloc_size, intf_max, if_count, if_cur, match, rv = BCM_E_NONE;
   4361 
   4362     REPL_INIT(unit);
   4363     REPL_GROUP_ID(unit, ipmc_id);
   4364     REPL_PORT_CHECK(unit, port);
   4365 
   4366     if (!REPL_PORT_GROUP_INTF_COUNT(unit, port, ipmc_id)) {
   4367         return BCM_E_NOT_FOUND;
   4368     }
   4369 
   4370     intf_max = REPL_INTF_TOTAL(unit);
   4371 #ifdef BCM_TOMAHAWK3_SUPPORT
   4372     if (SOC_IS_TOMAHAWK3(unit)) {
   4373         intf_max = TH3_IPMC_MAX_INTF_COUNT;
   4374     }
   4375 #endif
   4376     alloc_size = intf_max * sizeof(bcm_if_t);
   4377     if_array = sal_alloc(alloc_size, "IPMC repl interface array");
   4378     if (if_array == NULL) {
   4379         return BCM_E_MEMORY;
   4380     }
   4381 
   4382     REPL_LOCK(unit);
   4383     rv = bcm_th_ipmc_egress_intf_get(unit, ipmc_id, port, intf_max,
   4384                                      if_array, &if_count);
   4385     if (BCM_SUCCESS(rv)) {
   4386         match = FALSE;
   4387         for (if_cur = 0; if_cur < if_count; if_cur++) {
   4388             if (match) {
   4389                 if_array[if_cur - 1] = if_array[if_cur];
   4390             } else {
   4391                 if (if_array[if_cur] == l3_intf->l3a_intf_id) {
   4392                     match = TRUE;
   4393                 }
   4394             }
   4395         }
   4396         if (match) {
   4397             if_count--;
   4398             rv = bcm_th_ipmc_egress_intf_set(unit, ipmc_id, port,
   4399                                              if_count, if_array, TRUE, FALSE);
   4400         } else {
   4401             rv = BCM_E_NOT_FOUND;
   4402         }
   4403     }
   4404 
   4405     REPL_UNLOCK(unit);
   4406     sal_free(if_array);
   4407     return rv;
   4408 }
   4409 
   4410 /*
   4411  * Function:
   4412  *      _bcm_th_ipmc_repl_get
   4413  * Purpose:
   4414  *      Return set of VLANs selected for port's replication list for chosen
   4415  *      IPMC group.
   4416  * Parameters:
   4417  *      unit     - StrataSwitch PCI device unit number.
   4418  *      ipmc_id  - IPMC group number.
   4419  *      port     - port to list.
   4420  *      vlan_vec - (OUT) vector of replicated VLANs common to selected ports.
   4421  * Returns:
   4422  *      BCM_E_XXX
   4423  */
   4424 int
   4425 bcm_th_ipmc_repl_get(int unit, int ipmc_id, bcm_port_t port,
   4426                         bcm_vlan_vector_t vlan_vec)
   4427 {
   4428     int rv = BCM_E_NONE;
   4429     int pipe;
   4430     uint32 ls_bits[2];
   4431     int prev_repl_entry_ptr, repl_entry_ptr;
   4432     int intf_base;
   4433     int ls_pos;
   4434     mmu_repl_list_tbl_entry_t repl_list_entry;
   4435     int next_hop_index;
   4436     int entry_type;
   4437     bcm_l3_intf_t l3_intf;
   4438     bcm_l3_egress_t egress_object;
   4439     bcm_if_t egr_if;
   4440     int vlan_count;
   4441     egr_l3_next_hop_entry_t egr_nh;
   4442     soc_mem_t repl_list_table;
   4443     soc_field_t ent_type_fld = ENTRY_TYPEf;
   4444     if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, DATA_TYPEf)) {
   4445         ent_type_fld = DATA_TYPEf;
   4446     }
   4447 
   4448     REPL_INIT(unit);
   4449     REPL_GROUP_ID(unit, ipmc_id);
   4450     REPL_PORT_CHECK(unit, port);
   4451     BCM_IF_ERROR_RETURN(_bcm_th_port_pipe_get(unit, port, &pipe));
   4452 
   4453     BCM_VLAN_VEC_ZERO(vlan_vec);
   4454 
   4455     repl_list_table = REPL_LIST_TBL_PIPE(unit, pipe);
   4456     REPL_LOCK(unit);
   4457     if (REPL_PORT_GROUP_INTF_COUNT(unit, port, ipmc_id) == 0) {
   4458         REPL_UNLOCK(unit);
   4459         return BCM_E_NONE;
   4460     }
   4461 
   4462     rv = _bcm_th_repl_list_start_ptr_get(unit, ipmc_id, port,
   4463             &repl_entry_ptr);
   4464     if (BCM_FAILURE(rv)) {
   4465         goto vlan_get_done;
   4466     }
   4467 
   4468     prev_repl_entry_ptr = -1;
   4469     vlan_count = 0;
   4470     while (repl_entry_ptr != prev_repl_entry_ptr) {
   4471         rv = soc_mem_read(unit, repl_list_table, MEM_BLOCK_ANY, 
   4472                           repl_entry_ptr, &repl_list_entry);
   4473         if (BCM_FAILURE(rv)) {
   4474             goto vlan_get_done;
   4475         }
   4476         /* Each MSB represents 64 entries in LSB bitmap */
   4477         intf_base = soc_MMU_REPL_LIST_TBLm_field32_get(unit, &repl_list_entry,
   4478                 MSB_VLANf) * 64;
   4479         soc_MMU_REPL_LIST_TBLm_field_get(unit, &repl_list_entry,
   4480                 LSB_VLAN_BMf, ls_bits);
   4481         for (ls_pos = 0; ls_pos < 64; ls_pos++) {
   4482             if (ls_bits[ls_pos / 32] & (1 << (ls_pos % 32))) {
   4483                 next_hop_index = intf_base + ls_pos;
   4484                 rv = READ_EGR_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY,
   4485                         next_hop_index, &egr_nh);
   4486                 if (BCM_FAILURE(rv)) {
   4487                     goto vlan_get_done;
   4488                 }
   4489                 entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit,
   4490                         &egr_nh, ent_type_fld);
   4491                 bcm_l3_intf_t_init(&l3_intf);
   4492                 if (entry_type == 7) {
   4493                     l3_intf.l3a_intf_id = soc_EGR_L3_NEXT_HOPm_field32_get(unit,
   4494                             &egr_nh, L3MC__INTF_NUMf);
   4495                 } else {
   4496                     egr_if = next_hop_index + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   4497                     rv = bcm_esw_l3_egress_get(unit, egr_if, &egress_object);
   4498                     if (BCM_FAILURE(rv)) {
   4499                         goto vlan_get_done;
   4500                     }
   4501                     l3_intf.l3a_intf_id = egress_object.intf;
   4502                 }
   4503                 rv = bcm_esw_l3_intf_get(unit, &l3_intf);
   4504                 if (BCM_FAILURE(rv)) {
   4505                     goto vlan_get_done;
   4506                 }
   4507                 BCM_VLAN_VEC_SET(vlan_vec, l3_intf.l3a_vid);
   4508                 vlan_count++;
   4509             }
   4510         }
   4511         prev_repl_entry_ptr = repl_entry_ptr;
   4512         repl_entry_ptr = soc_MMU_REPL_LIST_TBLm_field32_get(unit,
   4513                 &repl_list_entry, NEXTPTRf);
   4514         if (vlan_count >= REPL_PORT_GROUP_INTF_COUNT(unit, port, ipmc_id)) {
   4515             break;
   4516         }
   4517     }
   4518 
   4519 vlan_get_done:
   4520     REPL_UNLOCK(unit);
   4521     return rv;
   4522 }
   4523 
   4524 /*
   4525  * Function:
   4526  *      _bcm_th_ipmc_repl_add
   4527  * Purpose:
   4528  *      Add VLAN to selected ports' replication list for chosen
   4529  *      IPMC group.
   4530  *Parameters:
   4531  *      unit     - StrataSwitch PCI device unit number.
   4532  *      ipmc_id  - IPMC group number.
   4533  *      port     - port to add.
   4534  *      vlan     - VLAN to replicate.
   4535  * Returns:
   4536  *      BCM_E_XXX
   4537  */
   4538 int
   4539 bcm_th_ipmc_repl_add(int unit, int ipmc_id, bcm_port_t port,
   4540                      bcm_vlan_t vlan)
   4541 {
   4542     int alloc_size, intf_max, if_count, rv = BCM_E_NONE;
   4543     bcm_if_t *if_array = NULL;
   4544     pbmp_t pbmp, ubmp;
   4545     bcm_l3_intf_t l3_intf;
   4546 
   4547     REPL_INIT(unit);
   4548     REPL_GROUP_ID(unit, ipmc_id);
   4549     REPL_PORT_CHECK(unit, port);
   4550 
   4551     /* Check if port belongs to this VLAN */
   4552     BCM_IF_ERROR_RETURN
   4553         (bcm_esw_vlan_port_get(unit, vlan, &pbmp, &ubmp));
   4554     if (!SOC_PBMP_MEMBER(pbmp, port)) {
   4555         return BCM_E_PARAM;
   4556     }
   4557 
   4558     bcm_l3_intf_t_init(&l3_intf);
   4559     l3_intf.l3a_vid = vlan;
   4560     if (bcm_esw_l3_intf_find_vlan(unit, &l3_intf) < 0) {
   4561         return BCM_E_PARAM;
   4562     }
   4563 
   4564     REPL_LOCK(unit);
   4565 
   4566     intf_max = 1 + REPL_PORT_GROUP_INTF_COUNT(unit, port, ipmc_id);
   4567     alloc_size = intf_max * sizeof(bcm_if_t);
   4568     if_array = sal_alloc(alloc_size, "IPMC repl interface array");
   4569     if (if_array == NULL) {
   4570         REPL_UNLOCK(unit);
   4571         return BCM_E_MEMORY;
   4572     }
   4573 
   4574     rv = bcm_th_ipmc_egress_intf_get(unit, ipmc_id, port, intf_max,
   4575                                      if_array, &if_count);
   4576     if (BCM_SUCCESS(rv)) {
   4577         if (if_count < intf_max) {
   4578             if_array[if_count++] = l3_intf.l3a_intf_id;
   4579             rv = bcm_th_ipmc_egress_intf_set(unit, ipmc_id, port,
   4580                                              if_count, if_array, TRUE, FALSE);
   4581         } else {
   4582             rv = BCM_E_EXISTS;
   4583         }
   4584     }
   4585 
   4586     REPL_UNLOCK(unit);
   4587     sal_free(if_array);
   4588     return rv;
   4589 }
   4590 
   4591 /*
   4592  * Function:
   4593  *      _bcm_th_ipmc_repl_delete
   4594  * Purpose:
   4595  *      Remove VLAN from selected ports' replication list for chosen
   4596  *      IPMC group.
   4597  * Parameters:
   4598  *      unit     - StrataSwitch PCI device unit number.
   4599  *      ipmc_id  - IPMC group number.
   4600  *      port     - port to remove.
   4601  *      vlan     - VLAN to delete from replication.
   4602  * Returns:
   4603  *      BCM_E_XXX
   4604  */
   4605 
   4606 int
   4607 bcm_th_ipmc_repl_delete(int unit, int ipmc_id, bcm_port_t port,
   4608                         bcm_vlan_t vlan)
   4609 {
   4610     int alloc_size, intf_max, if_count, if_cur, match, rv = BCM_E_NONE;
   4611     bcm_if_t *if_array = NULL;
   4612     bcm_l3_intf_t l3_intf;
   4613 
   4614     REPL_INIT(unit);
   4615     REPL_GROUP_ID(unit, ipmc_id);
   4616     REPL_PORT_CHECK(unit, port);
   4617 
   4618     if (!REPL_PORT_GROUP_INTF_COUNT(unit, port, ipmc_id)) {
   4619         return BCM_E_NOT_FOUND;
   4620     }
   4621 
   4622     bcm_l3_intf_t_init(&l3_intf);
   4623     l3_intf.l3a_vid = vlan;
   4624     if (bcm_esw_l3_intf_find_vlan(unit, &l3_intf) < 0) {
   4625         return BCM_E_PARAM;
   4626     }
   4627 
   4628     REPL_LOCK(unit);
   4629     intf_max = REPL_PORT_GROUP_INTF_COUNT(unit, port, ipmc_id);
   4630     alloc_size = intf_max * sizeof(bcm_if_t);
   4631     if_array = sal_alloc(alloc_size, "IPMC repl interface array");
   4632     if (if_array == NULL) {
   4633         REPL_UNLOCK(unit);
   4634         return BCM_E_MEMORY;
   4635     }
   4636 
   4637     rv = bcm_th_ipmc_egress_intf_get(unit, ipmc_id, port, intf_max,
   4638                                      if_array, &if_count);
   4639     if (BCM_SUCCESS(rv)) {
   4640         match = FALSE;
   4641         for (if_cur = 0; if_cur < if_count; if_cur++) {
   4642             if (match) {
   4643                 if_array[if_cur - 1] = if_array[if_cur];
   4644             } else {
   4645                 if (if_array[if_cur] == l3_intf.l3a_intf_id) {
   4646                     match = TRUE;
   4647                 }
   4648             }
   4649         }
   4650         if (match) {
   4651             if_count--;
   4652             rv = bcm_th_ipmc_egress_intf_set(unit, ipmc_id, port,
   4653                                              if_count, if_array, TRUE, FALSE);
   4654         } else {
   4655             rv = BCM_E_NOT_FOUND;
   4656         }
   4657     }
   4658     REPL_UNLOCK(unit);
   4659     sal_free(if_array);
   4660     return rv;
   4661 }
   4662 
   4663 /*
   4664  * Function:
   4665  *      bcm_th_ipmc_repl_delete_all
   4666  * Purpose:
   4667  *      Remove all VLANs from selected ports' replication list for chosen
   4668  *      IPMC group.
   4669  * Parameters:
   4670  *      unit     - StrataSwitch PCI device unit number.
   4671  *      ipmc_id  - The MC index number.
   4672  *      port     - port from which to remove VLANs.
   4673  * Returns:
   4674  *      BCM_E_XXX
   4675  */
   4676 int
   4677 bcm_th_ipmc_repl_delete_all(int unit, int ipmc_id, bcm_port_t port)
   4678 {
   4679     REPL_INIT(unit);
   4680     REPL_GROUP_ID(unit, ipmc_id);
   4681     REPL_PORT_CHECK(unit, port);
   4682 
   4683     if (!REPL_PORT_GROUP_INTF_COUNT(unit, port, ipmc_id)) {
   4684         /* Nothing to do */
   4685         return BCM_E_NONE;
   4686     }
   4687 
   4688     return bcm_th_ipmc_egress_intf_set(unit, ipmc_id, port, 0, NULL,
   4689                                         TRUE, FALSE);
   4690 }
   4691 
   4692 /*
   4693  * Function:
   4694  *      bcm_th_ipmc_repl_set
   4695  * Purpose:
   4696  *      Assign set of VLANs provided to port's replication list for chosen
   4697  *      IPMC group.
   4698  * Parameters:
   4699  *      unit     - StrataSwitch PCI device unit number.
   4700  *      ipmc_id  - The index number.
   4701  *      port     - port to list.
   4702  *      vlan_vec - (IN) vector of replicated VLANs common to selected ports.
   4703  * Returns:
   4704  *      BCM_E_XXX
   4705  */
   4706 int
   4707 bcm_th_ipmc_repl_set(int unit, int ipmc_id, bcm_port_t port,
   4708                      bcm_vlan_vector_t vlan_vec)
   4709 {
   4710     int rv = BCM_E_NONE;
   4711     bcm_if_t *if_array = NULL;
   4712     bcm_l3_intf_t l3_intf;
   4713     pbmp_t pbmp, ubmp;
   4714     int  intf_num, intf_max, alloc_size, vid;
   4715 
   4716     REPL_INIT(unit);
   4717     REPL_GROUP_ID(unit, ipmc_id);
   4718     REPL_PORT_CHECK(unit, port);
   4719 
   4720     intf_max = BCM_VLAN_MAX - BCM_VLAN_MIN + 1;
   4721     alloc_size = intf_max * sizeof(bcm_if_t);
   4722     if_array = sal_alloc(alloc_size, "IPMC repl interface array");
   4723     if (if_array == NULL) {
   4724         return BCM_E_MEMORY;
   4725     }
   4726 
   4727     sal_memset(if_array, 0, alloc_size);
   4728     intf_num = 0;
   4729     for (vid = BCM_VLAN_MIN; vid < BCM_VLAN_MAX; vid++) {
   4730         if (BCM_VLAN_VEC_GET(vlan_vec, vid)) {
   4731             rv = bcm_esw_vlan_port_get(unit, vid, &pbmp, &ubmp);
   4732             if (BCM_FAILURE(rv)) {
   4733                 sal_free(if_array);
   4734                 return rv;
   4735             }
   4736             if (!BCM_PBMP_MEMBER(pbmp, port)) {
   4737                 sal_free(if_array);
   4738                 return BCM_E_PARAM;
   4739             }
   4740             bcm_l3_intf_t_init(&l3_intf);
   4741             l3_intf.l3a_vid = vid;
   4742             if ((rv = bcm_esw_l3_intf_find_vlan(unit, &l3_intf)) < 0) {
   4743                 sal_free(if_array);
   4744                 return rv;
   4745             }
   4746             if_array[intf_num++] = l3_intf.l3a_intf_id;
   4747         }
   4748     }
   4749 
   4750     rv = bcm_th_ipmc_egress_intf_set(unit, ipmc_id, port,
   4751                                      intf_num, if_array, TRUE, FALSE);
   4752 
   4753     sal_free(if_array);
   4754     return rv;
   4755 }
   4756 
   4757 /*
   4758  * Function:
   4759  *      _bcm_th_ipmc_egress_intf_add
   4760  * Purpose:
   4761  *      Add encap ID to selected ports' replication list for chosen
   4762  *      IPMC group.
   4763  * Parameters:
   4764  *      unit     - StrataSwitch PCI device unit number.
   4765  *      ipmc_id  - IPMC group number.
   4766  *      port     - port to add.
   4767  *      encap_id - Encap ID.
   4768  *      is_l3    - Indicates if multicast group type is IPMC.
   4769  * Returns:
   4770  *      BCM_E_XXX
   4771  */
   4772 int
   4773 _bcm_th_ipmc_egress_intf_add(int unit, int ipmc_id, bcm_port_t port,
   4774                             int encap_id, int is_l3)
   4775 {
   4776     bcm_if_t *if_array = NULL;
   4777     int  intf_num, intf_max, alloc_size, rv = BCM_E_NONE;
   4778     pbmp_t pbmp, ubmp;
   4779     bcm_l3_intf_t l3_intf;
   4780     bcm_port_t port_in = port;
   4781 
   4782 #ifdef BCM_TOMAHAWK3_SUPPORT
   4783     bcm_pbmp_t l2_pbmp, l3_pbmp;
   4784     bcm_port_t port_idx;
   4785     int th3_if_count = 0;
   4786 #endif
   4787 
   4788     REPL_INIT(unit);
   4789     REPL_GROUP_ID(unit, ipmc_id);
   4790 
   4791 #if defined(BCM_HGPROXY_COE_SUPPORT)
   4792     if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   4793         BCM_GPORT_IS_SET(port) &&
   4794         _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) {
   4795             BCM_IF_ERROR_RETURN(
   4796                 _bcmi_coe_subport_physical_port_get(unit, port, &port));
   4797     }
   4798 #endif
   4799 
   4800     if (!IS_CPU_PORT(unit, port)) {
   4801         REPL_PORT_CHECK(unit, port);
   4802     }
   4803 
   4804     if ((BCM_MC_PER_TRUNK_REPL_MODE(unit)) &&
   4805          encap_id == BCM_ENCAP_TRUNK_MEMBER) {
   4806          /* For TH_MC_PER_TRUNK_REPL mode, indentical replication list is set
   4807           * for all the members of a trunk.
   4808           */
   4809          return BCM_E_NONE;
   4810     }
   4811 
   4812     intf_max = REPL_INTF_TOTAL(unit);
   4813 #ifdef BCM_TOMAHAWK3_SUPPORT
   4814     if (SOC_IS_TOMAHAWK3(unit)) {
   4815         intf_max = TH3_IPMC_MAX_INTF_COUNT;
   4816         /* Retrieve the number of replications for this MC group across all
   4817          * ports */
   4818         rv = _bcm_esw_multicast_ipmc_read(unit, ipmc_id, &l2_pbmp, &l3_pbmp);
   4819         /* Add any L2 copies for the MC group */
   4820         BCM_PBMP_COUNT(l2_pbmp, th3_if_count);
   4821         /* Iterate among all L3 ports to get the sum of interface counts */
   4822         alloc_size = intf_max * sizeof(bcm_if_t);
   4823         if_array = sal_alloc(alloc_size, "IPMC repl interface array");
   4824         if (if_array == NULL) {
   4825             return BCM_E_MEMORY;
   4826         }
   4827 
   4828         REPL_LOCK(unit);
   4829         BCM_PBMP_ITER(l3_pbmp, port_idx) {
   4830             if (port_idx == 158) {
   4831                 /* Skip checke for spare port used in B0 WAR*/
   4832                 continue;
   4833             }
   4834             rv = bcm_th_ipmc_egress_intf_get(unit, ipmc_id, port_idx, intf_max,
   4835                                      if_array, &intf_num);
   4836             if (!BCM_SUCCESS(rv)) {
   4837                 goto intf_add_done;
   4838             }
   4839             th3_if_count += intf_num;
   4840         }
   4841         REPL_UNLOCK(unit);
   4842         sal_free(if_array);
   4843         if (th3_if_count >= intf_max) {
   4844             return BCM_E_EXISTS;
   4845         }
   4846     }
   4847 #endif
   4848     alloc_size = intf_max * sizeof(bcm_if_t);
   4849     if_array = sal_alloc(alloc_size, "IPMC repl interface array");
   4850     if (if_array == NULL) {
   4851         return BCM_E_MEMORY;
   4852     }
   4853 
   4854     REPL_LOCK(unit);
   4855     rv = bcm_th_ipmc_egress_intf_get(unit, ipmc_id, port, intf_max,
   4856                                      if_array, &intf_num);
   4857     if (BCM_SUCCESS(rv)) {
   4858         if (intf_num < intf_max) {
   4859             if_array[intf_num++] = encap_id;
   4860 
   4861             /* For IPMC and Trill, check port is a member of the L3 interface's 
   4862              * VLAN. Performing this check here is more efficient than doing 
   4863              * it in bcm_th_ipmc_egress_intf_set.
   4864              */ 
   4865             if (!BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, encap_id)) {
   4866                 /* L3 interface is used */
   4867 
   4868                 if (encap_id > soc_mem_index_max(unit, EGR_L3_INTFm)) {
   4869                     rv = BCM_E_PARAM;
   4870                     goto intf_add_done;
   4871                 }
   4872 
   4873                 bcm_l3_intf_t_init(&l3_intf);
   4874                 l3_intf.l3a_intf_id = encap_id;
   4875                 rv = bcm_esw_l3_intf_get(unit, &l3_intf);
   4876                 if (BCM_FAILURE(rv)) {
   4877                     goto intf_add_done;
   4878                 }
   4879 
   4880                 if (!SOC_IS_TRIDENT3X(unit)) {
   4881                     rv = bcm_esw_vlan_port_get(unit, l3_intf.l3a_vid,
   4882                             &pbmp, &ubmp);
   4883                     if (BCM_FAILURE(rv)) {
   4884                         goto intf_add_done;
   4885                     }
   4886                     if (!BCM_PBMP_MEMBER(pbmp, port)) {
   4887                         rv = BCM_E_PARAM;
   4888                         goto intf_add_done;
   4889                     }
   4890                 }
   4891             }
   4892 
   4893             rv = bcm_th_ipmc_egress_intf_set(unit, ipmc_id, port_in,
   4894                                              intf_num, if_array, is_l3, FALSE);
   4895         } else {
   4896             rv = BCM_E_EXISTS;
   4897         }
   4898     }
   4899 
   4900 intf_add_done:
   4901 
   4902     REPL_UNLOCK(unit);
   4903     sal_free(if_array);
   4904     return rv;
   4905 }
   4906 
   4907 /*
   4908  * Function:
   4909  *      _bcm_th_ipmc_egress_intf_delete
   4910  * Purpose:
   4911  *      Remove encap ID from selected ports' replication list for chosen
   4912  *      IPMC group.
   4913  * Parameters:
   4914  *      unit     - StrataSwitch PCI device unit number.
   4915  *      ipmc_id  - IPMC group number.
   4916  *      port     - port to remove.
   4917  *      if_max   - Maximal interface.
   4918  *      encap_id - Encap ID to delete from replication.
   4919  *      is_l3    - Indicates if multicast group type is IPMC.
   4920  * Returns:
   4921  *      BCM_E_XXX
   4922  */
   4923 int
   4924 _bcm_th_ipmc_egress_intf_delete(int unit, int ipmc_id, bcm_port_t port,
   4925                                int if_max, int encap_id, int is_l3)
   4926 {
   4927     bcm_if_t *if_array = NULL;
   4928     int alloc_size, if_count, if_cur, match, rv = BCM_E_NONE;
   4929 
   4930     REPL_INIT(unit);
   4931     REPL_GROUP_ID(unit, ipmc_id);
   4932     if (!IS_CPU_PORT(unit, port)) {
   4933         REPL_PORT_CHECK(unit, port);
   4934     }
   4935 
   4936     if ((BCM_MC_PER_TRUNK_REPL_MODE(unit)) &&
   4937          encap_id == BCM_ENCAP_TRUNK_MEMBER) {
   4938          /* For MC_PER_TRUNK_REPL mode, indentical replication list is set
   4939           * for all the members of a trunk.
   4940           */
   4941          return BCM_E_NONE;
   4942     }
   4943 
   4944     if (!REPL_PORT_GROUP_INTF_COUNT(unit, port, ipmc_id)) {
   4945         return BCM_E_NOT_FOUND;
   4946     }
   4947 
   4948     if ((if_max <= 0) || ((uint32)if_max > REPL_INTF_TOTAL(unit))) {
   4949         return BCM_E_PARAM;
   4950     }
   4951 #ifdef BCM_TOMAHAWK3_SUPPORT
   4952     if (SOC_IS_TOMAHAWK3(unit)) {
   4953         if((uint32)if_max > TH3_IPMC_MAX_INTF_COUNT) {
   4954             return BCM_E_PARAM;
   4955         }
   4956     }
   4957 #endif
   4958 
   4959     alloc_size = if_max * sizeof(bcm_if_t);
   4960     if_array = sal_alloc(alloc_size, "IPMC repl interface array");
   4961     if (if_array == NULL) {
   4962         return BCM_E_MEMORY;
   4963     }
   4964 
   4965     REPL_LOCK(unit);
   4966     rv = bcm_th_ipmc_egress_intf_get(unit, ipmc_id, port, if_max,
   4967                                      if_array, &if_count);
   4968     if (BCM_SUCCESS(rv)) {
   4969         match = FALSE;
   4970         for (if_cur = 0; if_cur < if_count; if_cur++) {
   4971             if (match) {
   4972                 if_array[if_cur - 1] = if_array[if_cur];
   4973             } else {
   4974                 if (if_array[if_cur] == encap_id) {
   4975                     match = TRUE;
   4976                 }
   4977             }
   4978         }
   4979         if (match) {
   4980             if_count--;
   4981             rv = bcm_th_ipmc_egress_intf_set(unit, ipmc_id, port,
   4982                                              if_count, if_array, is_l3, FALSE);
   4983         } else {
   4984             rv = BCM_E_NOT_FOUND;
   4985         }
   4986     }
   4987 
   4988     REPL_UNLOCK(unit);
   4989     sal_free(if_array);
   4990     return rv;
   4991 }
   4992 
   4993 /*
   4994  * Function:
   4995  *      bcm_th_ipmc_trill_mac_update
   4996  * Purpose:
   4997  *      Update the Trill MAC address in next hop entries that are
   4998  *      in Trill multicast replication list. 
   4999  * Parameters:
   5000  *      unit      - (IN) SOC unit #
   5001  *      mac_field - (IN) MAC address
   5002  *      flag      - (IN) 0 = Set the lower 24 bits of MAC address,
   5003  *                       1 = Set the higher 24 bits of MAC address.
   5004  * Returns:
   5005  *      BCM_E_XXX
   5006  */
   5007 int
   5008 bcm_th_ipmc_trill_mac_update(int unit, uint32 mac_field, uint8 flag)
   5009 {
   5010     int intf, nh_index;
   5011     egr_l3_next_hop_entry_t egr_nh;
   5012     uint32 entry_type;
   5013     bcm_mac_t mac;
   5014     soc_field_t ent_type_fld = ENTRY_TYPEf;
   5015     if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, DATA_TYPEf)) {
   5016         ent_type_fld = DATA_TYPEf;
   5017     }
   5018 
   5019     for (intf = 0; intf < soc_mem_index_count(unit, EGR_L3_INTFm); intf++) {
   5020         nh_index = REPL_L3_INTF_NEXT_HOP_TRILL(unit, intf);
   5021         if (nh_index >= 0) {
   5022             SOC_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm,
   5023                         MEM_BLOCK_ANY, nh_index, &egr_nh));
   5024             entry_type = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
   5025                     &egr_nh, ent_type_fld);
   5026             if (entry_type == 0) { /* normal entry type */
   5027                 soc_mem_mac_addr_get(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   5028                         L3__MAC_ADDRESSf, mac);
   5029                 if (!flag) {
   5030                     /* Set the low-order bytes */
   5031                     mac[3] = (uint8) (mac_field >> 16 & 0xff);
   5032                     mac[4] = (uint8) (mac_field >> 8 & 0xff);
   5033                     mac[5] = (uint8) (mac_field & 0xff);
   5034                 } else {
   5035                     /* Set the High-order bytes */
   5036                     mac[0] = (uint8) (mac_field >> 16 & 0xff);
   5037                     mac[1] = (uint8) (mac_field >> 8 & 0xff);
   5038                     mac[2] = (uint8) (mac_field & 0xff);
   5039                 }
   5040                 soc_mem_mac_addr_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   5041                         L3__MAC_ADDRESSf, mac);
   5042             }
   5043         }
   5044     }
   5045 
   5046     return BCM_E_NONE;
   5047 }
   5048 
   5049 /*
   5050  * Function:
   5051  *      bcm_th_ipmc_l3_intf_next_hop_free
   5052  * Purpose:
   5053  *      Free the next hop index associated with the given L3 interface.
   5054  * Parameters:
   5055  *      unit - (IN) SOC unit #
   5056  *      intf - (IN) L3 interface ID
   5057  * Returns:
   5058  *      BCM_E_XXX
   5059  */
   5060 int
   5061 bcm_th_ipmc_l3_intf_next_hop_free(int unit, int intf)
   5062 {
   5063     int nh_index;
   5064 
   5065     if (_th_repl_info[unit] == NULL) {
   5066         /* IPMC replication is not initialized. There is no next hop
   5067          * index to free.
   5068          */
   5069         return BCM_E_NONE;
   5070     }
   5071 
   5072     nh_index = REPL_L3_INTF_NEXT_HOP_IPMC(unit, intf);
   5073     if (nh_index >= 0) {
   5074 #ifdef BCM_TOMAHAWK3_SUPPORT
   5075         if (SOC_IS_TOMAHAWK3(unit)) {
   5076             SOC_IF_ERROR_RETURN
   5077                 (WRITE_EGR_L3_NEXT_HOP_2m(unit, MEM_BLOCK_ALL, nh_index,
   5078                                           soc_mem_entry_null(unit,
   5079                                           EGR_L3_NEXT_HOP_2m)));
   5080         }
   5081 #endif
   5082         SOC_IF_ERROR_RETURN
   5083             (WRITE_EGR_L3_NEXT_HOPm(unit, MEM_BLOCK_ALL, nh_index,
   5084                                     soc_mem_entry_null(unit, EGR_L3_NEXT_HOPm)));
   5085         BCM_IF_ERROR_RETURN
   5086             (bcm_xgs3_nh_del(unit, _BCM_L3_SHR_WRITE_DISABLE, nh_index));
   5087         REPL_L3_INTF_NEXT_HOP_IPMC(unit, intf) = -1;
   5088     }
   5089 
   5090     nh_index = REPL_L3_INTF_NEXT_HOP_TRILL(unit, intf);
   5091     if (nh_index >= 0) {
   5092 #ifdef BCM_TOMAHAWK3_SUPPORT
   5093         if (SOC_IS_TOMAHAWK3(unit)) {
   5094             SOC_IF_ERROR_RETURN
   5095                 (WRITE_EGR_L3_NEXT_HOP_2m(unit, MEM_BLOCK_ALL, nh_index,
   5096                                           soc_mem_entry_null(unit,
   5097                                           EGR_L3_NEXT_HOP_2m)));
   5098         }
   5099 
   5100 #endif
   5101         SOC_IF_ERROR_RETURN
   5102             (WRITE_EGR_L3_NEXT_HOPm(unit, MEM_BLOCK_ALL, nh_index,
   5103                                     soc_mem_entry_null(unit, EGR_L3_NEXT_HOPm)));
   5104         BCM_IF_ERROR_RETURN
   5105             (bcm_xgs3_nh_del(unit, _BCM_L3_SHR_WRITE_DISABLE, nh_index));
   5106         REPL_L3_INTF_NEXT_HOP_TRILL(unit, intf) = -1;
   5107     }
   5108 
   5109     return BCM_E_NONE;
   5110 }
   5111 
   5112 #ifdef BCM_WARM_BOOT_SUPPORT
   5113 STATIC int
   5114 bcm_th_set_port_intf_cnt(int unit, int pipe,int aggid,
   5115                          int repl_group, int intf_cnt)
   5116 {
   5117     int port_iter, aggid_iter, pipe_iter=0;
   5118     uint32 regval;
   5119     bcm_pbmp_t            pbmp_all;
   5120 
   5121     BCM_PBMP_CLEAR(pbmp_all);
   5122     BCM_PBMP_ASSIGN(pbmp_all, PBMP_ALL(unit));
   5123 
   5124     PBMP_ITER(pbmp_all, port_iter) {
   5125 
   5126         if (SOC_IS_TOMAHAWK3(unit)) {
   5127             BCM_IF_ERROR_RETURN(
   5128                 READ_MMU_RQE_REPL_PORT_AGG_MAPr(unit, port_iter, &regval));
   5129             aggid_iter = soc_reg_field_get(unit, MMU_RQE_REPL_PORT_AGG_MAPr, regval,
   5130                                        L3MC_PORT_AGG_IDf);
   5131         } else {
   5132             BCM_IF_ERROR_RETURN(
   5133                 READ_MMU_DQS_REPL_PORT_AGG_MAPr(unit, port_iter, &regval));
   5134             aggid_iter = soc_reg_field_get(unit, MMU_DQS_REPL_PORT_AGG_MAPr, regval,
   5135                                        L3MC_PORT_AGG_IDf);
   5136 
   5137             /* coverity[overrun-local:FALSE] */
   5138             pipe_iter = SOC_INFO(unit).port_pipe[port_iter];
   5139         }
   5140 
   5141         if ((aggid_iter == aggid) && (pipe_iter == pipe)) {
   5142             /* coverity[overrun-local:FALSE] */
   5143             REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group) = intf_cnt;
   5144         }
   5145     }
   5146 
   5147     return BCM_E_NONE;
   5148 }
   5149 
   5150 STATIC int
   5151 bcm_th_add_port_intf_cnt(int unit, int pipe, int aggid,
   5152                          int repl_group, int intf_cnt)
   5153 {
   5154     int port_iter, aggid_iter, pipe_iter=0;
   5155     uint32 regval;
   5156     bcm_pbmp_t            pbmp_all;
   5157 
   5158     BCM_PBMP_CLEAR(pbmp_all);
   5159     BCM_PBMP_ASSIGN(pbmp_all, PBMP_ALL(unit));
   5160 
   5161     PBMP_ITER(pbmp_all, port_iter) {
   5162         if (SOC_IS_TOMAHAWK3(unit)) {
   5163             BCM_IF_ERROR_RETURN(
   5164                 READ_MMU_RQE_REPL_PORT_AGG_MAPr(unit, port_iter, &regval));
   5165             aggid_iter = soc_reg_field_get(unit, MMU_RQE_REPL_PORT_AGG_MAPr, regval,
   5166                                        L3MC_PORT_AGG_IDf);
   5167         } else {
   5168             BCM_IF_ERROR_RETURN(
   5169                 READ_MMU_DQS_REPL_PORT_AGG_MAPr(unit, port_iter, &regval));
   5170             aggid_iter = soc_reg_field_get(unit, MMU_DQS_REPL_PORT_AGG_MAPr, regval,
   5171                                        L3MC_PORT_AGG_IDf);
   5172             /* coverity[overrun-local:FALSE] */
   5173             pipe_iter = SOC_INFO(unit).port_pipe[port_iter];
   5174         }
   5175 
   5176         if ((aggid_iter == aggid) && (pipe_iter == pipe)) {
   5177             /* coverity[overrun-local:FALSE] */
   5178             REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group) += intf_cnt;
   5179         }
   5180     }
   5181 
   5182     return BCM_E_NONE;
   5183 }
   5184 
   5185 /*
   5186  * Function:
   5187  *      _bcm_th_ipmc_repl_reload
   5188  * Purpose:
   5189  *      Re-Initialize replication software to state consistent with
   5190  *      hardware.
   5191  * Parameters:
   5192  *      unit - SOC unit #
   5193  * Returns:
   5194  *      BCM_E_XXX
   5195  */
   5196 int
   5197 _bcm_th_ipmc_repl_reload(int unit)
   5198 {
   5199     int rv = BCM_E_NONE;
   5200     soc_mem_t repl_group_table;
   5201     soc_field_t base_idx_f;
   5202     soc_field_t member_bitmap_f;
   5203     int alloc_size;
   5204     int intf_vec_alloc_size;
   5205     uint8 *repl_group_buf = NULL;
   5206     SHR_BITDCL *intf_vec = NULL;
   5207     int pipe;
   5208     int index_min, index_max;
   5209     int i, j;
   5210     uint32 *repl_group_entry;
   5211     int head_index;
   5212     uint32 fldbuf[SOC_PBMP_WORD_MAX];
   5213     soc_pbmp_t member_bitmap;
   5214     int member_count;
   5215     int member_id, member;
   5216     soc_info_t *si;
   5217     bcm_port_t mmu_port, phy_port, port = -1;
   5218     uint32 repl_head_entry[SOC_MAX_MEM_FIELD_WORDS];
   5219     int start_ptr;
   5220     _bcm_repl_list_info_t *rli_current;
   5221     int prev_repl_entry_ptr, repl_entry_ptr;
   5222     mmu_repl_list_tbl_entry_t repl_list_entry;
   5223     int msb;
   5224     uint32 ls_bits[2];
   5225     uint8 *egr_nh_buf = NULL;
   5226     egr_l3_next_hop_entry_t *egr_nh_entry;
   5227 #ifdef BCM_TOMAHAWK3_SUPPORT
   5228     uint8 *egr_nh2_buf = NULL;
   5229     egr_l3_next_hop_2_entry_t *egr_nh2_entry = NULL;
   5230 #endif
   5231     int entry_type;
   5232     int l3_intf;
   5233     uint8 flags;
   5234     soc_mem_t repl_list_table;
   5235     int aggid = -1, intf_cnt = 0;
   5236 
   5237     soc_field_t ent_type_fld = ENTRY_TYPEf;
   5238     if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, DATA_TYPEf)) {
   5239         ent_type_fld = DATA_TYPEf;
   5240     }
   5241 
   5242     /* Initialize internal data structures */
   5243     BCM_IF_ERROR_RETURN(bcm_th_ipmc_repl_init(unit));
   5244 
   5245     /* Recover internal state by traversing replication lists
   5246      * in each pipeline.
   5247      */
   5248 #ifdef BCM_TOMAHAWK3_SUPPORT
   5249     if(SOC_IS_TOMAHAWK3(unit)) {
   5250         base_idx_f = BASE_PTRf;
   5251         member_bitmap_f = MEMBER_BMPf;
   5252     } else
   5253 #endif
   5254     {
   5255     base_idx_f = PIPE_BASE_PTRf;
   5256     member_bitmap_f = PIPE_MEMBER_BMPf;
   5257     }
   5258 
   5259     alloc_size = 4 * SOC_MEM_WORDS(unit, MMU_REPL_GROUP_INFO_TBLm) *
   5260         _th_repl_info[unit]->num_repl_groups;
   5261     repl_group_buf = soc_cm_salloc(unit, alloc_size, "repl group buf");
   5262     if (NULL == repl_group_buf) {
   5263         rv = BCM_E_MEMORY;
   5264         goto cleanup;
   5265     }
   5266 
   5267     intf_vec_alloc_size = SHR_BITALLOCSIZE(REPL_INTF_TOTAL(unit));
   5268     intf_vec = sal_alloc(intf_vec_alloc_size, "Repl interface vector");
   5269     if (intf_vec == NULL) {
   5270         rv = BCM_E_MEMORY;
   5271         goto cleanup;
   5272     }
   5273     sal_memset(intf_vec, 0, intf_vec_alloc_size);
   5274 
   5275     for (pipe = 0; pipe < NUM_PIPES(unit); pipe++) {
   5276         /* Read pipeline's replication group table */
   5277         if(SOC_IS_TOMAHAWK3(unit)) {
   5278             repl_list_table = MMU_REPL_LIST_TBLm;
   5279             repl_group_table = MMU_REPL_GROUP_INFO_TBLm;
   5280         } else {
   5281         repl_list_table = REPL_LIST_TBL_PIPE(unit, pipe);
   5282         repl_group_table = REPL_GROUP_INFO_TBL_PIPE(unit, pipe);
   5283         }
   5284 
   5285         index_min = 0;
   5286         index_max = _th_repl_info[unit]->num_repl_groups - 1;
   5287         rv = soc_mem_read_range(unit, repl_group_table, MEM_BLOCK_ANY,
   5288                                 index_min, index_max, repl_group_buf);
   5289         if (SOC_FAILURE(rv)) {
   5290             goto cleanup;
   5291         }
   5292 
   5293         for (i = index_min; i <= index_max; i++) {
   5294             repl_group_entry = soc_mem_table_idx_to_pointer(unit,
   5295                     repl_group_table, uint32 *, repl_group_buf, i);
   5296 
   5297             /* Get the head index */
   5298             head_index = soc_mem_field32_get(unit, repl_group_table,
   5299                     repl_group_entry, base_idx_f);
   5300             if (0 == head_index) {
   5301                 continue; /* with next replication group */
   5302             }
   5303 
   5304             /* Get the member bitmap */
   5305             sal_memset(fldbuf, 0, SOC_PBMP_WORD_MAX * sizeof(uint32));
   5306             soc_mem_field_get(unit, repl_group_table, repl_group_entry,
   5307                     member_bitmap_f, fldbuf);
   5308             for (j = 0; j < SOC_PBMP_WORD_MAX; j++) {
   5309                 SOC_PBMP_WORD_SET(member_bitmap, j, fldbuf[j]);
   5310             }
   5311             SOC_PBMP_COUNT(member_bitmap, member_count);
   5312             if (0 == member_count) {
   5313                 continue; /* with next replication group */
   5314             }
   5315 
   5316             member_id = 0;
   5317             SOC_PBMP_ITER(member_bitmap, member) {
   5318                 if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) {
   5319                     aggid = member;
   5320                 } else {
   5321                     if (SOC_IS_TOMAHAWK3(unit)) {
   5322                         port = member;
   5323                     } else {
   5324                         /* Convert member to mmu port, then to physical port, and
   5325                          * finally to logical port */
   5326                         mmu_port = pipe * mmu_port_stride[unit] + member;
   5327                         si = &SOC_INFO(unit);
   5328                         phy_port = si->port_m2p_mapping[mmu_port];
   5329                         port = si->port_p2l_mapping[phy_port];
   5330                     }
   5331                 }
   5332 
   5333                 /* Get replication list start pointer */
   5334                 rv = _bcm_td3_repl_head_tbl_read(unit, pipe,
   5335                                   (head_index + member_id), repl_head_entry,
   5336                                   (uint32 *)&start_ptr);
   5337                 if (SOC_FAILURE(rv)) {
   5338                     goto cleanup;
   5339                 }
   5340                 member_id++;
   5341                 if (0 == start_ptr) {
   5342                     continue; /* with next member */
   5343                 }
   5344 
   5345                 if (_bcm_th_repl_list_entry_used_get(unit, pipe, start_ptr)) {
   5346                     /* Already traversed this replication list */
   5347                     for (rli_current = REPL_LIST_INFO(unit, pipe);
   5348                             rli_current != NULL;
   5349                             rli_current = rli_current->next) {
   5350                         if (rli_current->index == start_ptr) {
   5351                             (rli_current->refcount)++;
   5352                             if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) {
   5353                                 intf_cnt = rli_current->list_size;
   5354                                 bcm_th_set_port_intf_cnt(unit, pipe, aggid,
   5355                                                          i, intf_cnt);
   5356                             } else {
   5357                                 REPL_PORT_GROUP_INTF_COUNT(unit, port, i) =
   5358                                     rli_current->list_size;
   5359                             }
   5360                             break;
   5361                         }
   5362                     }
   5363                     if (rli_current == NULL) {
   5364                         /* Unexpected */
   5365                         rv = BCM_E_INTERNAL;
   5366                         goto cleanup;
   5367                     } else {
   5368                         continue; /* with next member */
   5369                     }
   5370                 }
   5371 
   5372                 /* Traverse the replication list table */
   5373                 sal_memset(intf_vec, 0, intf_vec_alloc_size);
   5374                 prev_repl_entry_ptr = -1;
   5375                 repl_entry_ptr = start_ptr;
   5376                 if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) {
   5377                     intf_cnt = 0;
   5378                 }
   5379                 while (repl_entry_ptr != prev_repl_entry_ptr) {
   5380                     rv = soc_mem_read(unit, repl_list_table, MEM_BLOCK_ANY, 
   5381                                       repl_entry_ptr, &repl_list_entry);
   5382                     if (BCM_FAILURE(rv)) {
   5383                         goto cleanup;
   5384                     }
   5385                     msb = soc_MMU_REPL_LIST_TBLm_field32_get(unit,
   5386                             &repl_list_entry, MSB_VLANf);
   5387                     soc_MMU_REPL_LIST_TBLm_field_get(unit, &repl_list_entry,
   5388                             LSB_VLAN_BMf, ls_bits);
   5389                     intf_vec[2 * msb + 0] = ls_bits[0];
   5390                     intf_vec[2 * msb + 1] = ls_bits[1];
   5391                     if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) {
   5392                         intf_cnt += (_shr_popcount(ls_bits[0]) +
   5393                                      _shr_popcount(ls_bits[1]));
   5394                     } else {
   5395                         REPL_PORT_GROUP_INTF_COUNT(unit, port, i) +=
   5396                             _shr_popcount(ls_bits[0]) + _shr_popcount(ls_bits[1]);
   5397                     }
   5398                     rv = _bcm_th_repl_list_entry_used_set(unit, pipe,
   5399                             repl_entry_ptr);
   5400                     if (BCM_FAILURE(rv)) {
   5401                         goto cleanup;
   5402                     }
   5403                     prev_repl_entry_ptr = repl_entry_ptr;
   5404                     repl_entry_ptr = soc_MMU_REPL_LIST_TBLm_field32_get(unit,
   5405                             &repl_list_entry, NEXTPTRf);
   5406                 }
   5407                 if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) {
   5408                     bcm_th_add_port_intf_cnt(unit, pipe, aggid, i, intf_cnt);
   5409                 }
   5410 
   5411                 /* Insert a new replication list into linked list */
   5412                 rli_current = sal_alloc(sizeof(_bcm_repl_list_info_t),
   5413                         "repl list info");
   5414                 if (rli_current == NULL) {
   5415                     rv = BCM_E_MEMORY;
   5416                     goto cleanup;
   5417                 }
   5418                 sal_memset(rli_current, 0, sizeof(_bcm_repl_list_info_t));
   5419                 rli_current->index = start_ptr;
   5420                 rli_current->hash = _shr_crc32b(0, (uint8 *)intf_vec,
   5421                         REPL_INTF_TOTAL(unit));
   5422                 if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) {
   5423                     rli_current->list_size = intf_cnt;
   5424                 } else {
   5425                     rli_current->list_size = REPL_PORT_GROUP_INTF_COUNT(unit, port, i);
   5426                 }
   5427                 (rli_current->refcount)++;
   5428                 rli_current->next = REPL_LIST_INFO(unit, pipe);
   5429                 REPL_LIST_INFO(unit, pipe) = rli_current;
   5430             }
   5431 
   5432             /* Update REPL_HEAD table usage */
   5433             rv = _bcm_th_repl_head_block_used_set(unit, pipe, head_index,
   5434                     member_count);
   5435             if (BCM_FAILURE(rv)) {
   5436                 goto cleanup;
   5437             }
   5438         }
   5439     }
   5440     soc_cm_sfree(unit, repl_group_buf);
   5441     repl_group_buf = NULL;
   5442     sal_free(intf_vec);
   5443     intf_vec = NULL;
   5444 
   5445     /* Recover array of next hop indices for L3 interfaces */
   5446     egr_nh_buf = soc_cm_salloc(unit,
   5447             SOC_MEM_TABLE_BYTES(unit, EGR_L3_NEXT_HOPm), "egr nh buf");
   5448     if (NULL == egr_nh_buf) {
   5449         rv = BCM_E_MEMORY;
   5450         goto cleanup;
   5451     }
   5452     index_min = soc_mem_index_min(unit, EGR_L3_NEXT_HOPm);
   5453     index_max = soc_mem_index_max(unit, EGR_L3_NEXT_HOPm);
   5454     rv = soc_mem_read_range(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   5455             index_min, index_max, egr_nh_buf);
   5456     if (SOC_FAILURE(rv)) {
   5457         goto cleanup;
   5458     }
   5459 
   5460 #ifdef BCM_TOMAHAWK3_SUPPORT
   5461     if (SOC_IS_TOMAHAWK3(unit)) {
   5462         /* Recover array of next hop indices for L3 interfaces */
   5463         egr_nh2_buf = soc_cm_salloc(unit,
   5464                                     SOC_MEM_TABLE_BYTES(unit, EGR_L3_NEXT_HOP_2m),
   5465                                     "egr nh_2 buf");
   5466         if (NULL == egr_nh2_buf) {
   5467             rv = BCM_E_MEMORY;
   5468             goto cleanup;
   5469         }
   5470         index_min = soc_mem_index_min(unit, EGR_L3_NEXT_HOP_2m);
   5471         index_max = soc_mem_index_max(unit, EGR_L3_NEXT_HOP_2m);
   5472         rv = soc_mem_read_range(unit, EGR_L3_NEXT_HOP_2m, MEM_BLOCK_ANY,
   5473                                 index_min, index_max, egr_nh2_buf);
   5474         if (SOC_FAILURE(rv)) {
   5475             goto cleanup;
   5476         }
   5477     }
   5478 #endif
   5479 
   5480     for (i = index_min; i <= index_max; i++) {
   5481         egr_nh_entry = soc_mem_table_idx_to_pointer
   5482             (unit, EGR_L3_NEXT_HOPm, egr_l3_next_hop_entry_t *,
   5483              egr_nh_buf, i);
   5484 #ifdef BCM_TOMAHAWK3_SUPPORT
   5485         if (SOC_IS_TOMAHAWK3(unit)) {
   5486             egr_nh2_entry = soc_mem_table_idx_to_pointer
   5487                 (unit, EGR_L3_NEXT_HOP_2m, egr_l3_next_hop_2_entry_t *,
   5488                  egr_nh2_buf, i);
   5489         }
   5490 #endif
   5491         entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   5492                 ent_type_fld);
   5493         if (entry_type == 0) {
   5494 #ifdef BCM_TOMAHAWK3_SUPPORT
   5495             if (SOC_IS_TOMAHAWK3(unit)) {
   5496                 l3_intf = soc_EGR_L3_NEXT_HOP_2m_field32_get(unit, egr_nh2_entry,
   5497                     INTF_NUMf);
   5498             } else
   5499 #endif
   5500             {
   5501                 l3_intf = soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   5502                     L3__INTF_NUMf);
   5503             }
   5504             REPL_L3_INTF_NEXT_HOP_TRILL(unit, l3_intf) = i;
   5505         } else if (entry_type == 7) {
   5506 #ifdef BCM_TOMAHAWK3_SUPPORT
   5507             if (SOC_IS_TOMAHAWK3(unit)) {
   5508                 l3_intf = soc_EGR_L3_NEXT_HOP_2m_field32_get(unit, egr_nh2_entry,
   5509                     INTF_NUMf);
   5510             } else
   5511 #endif
   5512             {
   5513                 l3_intf = soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   5514                     L3MC__INTF_NUMf);
   5515             }
   5516             REPL_L3_INTF_NEXT_HOP_IPMC(unit, l3_intf) = i;
   5517         } else {
   5518             continue;
   5519         }
   5520     }
   5521     soc_cm_sfree(unit, egr_nh_buf);
   5522     egr_nh_buf = NULL;
   5523 #ifdef BCM_TOMAHAWK3_SUPPORT
   5524     if (SOC_IS_TOMAHAWK3(unit)) {
   5525         soc_cm_sfree(unit, egr_nh2_buf);
   5526         egr_nh2_buf = NULL;
   5527     }
   5528 #endif
   5529 
   5530     /* Recover REPL list mode from HW cache */
   5531     rv = _bcm_esw_ipmc_repl_wb_flags_get(unit,
   5532                                          _BCM_IPMC_WB_REPL_LIST, &flags);
   5533     if (flags) {
   5534         SOC_IPMCREPLSHR_SET(unit, 1);
   5535     }
   5536 
   5537 cleanup:
   5538     if (repl_group_buf) {
   5539         soc_cm_sfree(unit, repl_group_buf);
   5540     }
   5541     if (intf_vec) {
   5542         sal_free(intf_vec);
   5543     }
   5544 
   5545     if (egr_nh_buf) {
   5546         soc_cm_sfree(unit, egr_nh_buf);
   5547     }
   5548 
   5549 #ifdef BCM_TOMAHAWK3_SUPPORT
   5550     if (SOC_IS_TOMAHAWK3(unit)) {
   5551         if (egr_nh2_buf) {
   5552             soc_cm_sfree(unit, egr_nh2_buf);
   5553         }
   5554     }
   5555 #endif
   5556 
   5557     if (BCM_FAILURE(rv)) {
   5558         bcm_th_ipmc_repl_detach(unit);
   5559     }
   5560 
   5561     return rv;
   5562 }
   5563 #endif /* BCM_WARM_BOOT_SUPPORT */
   5564 
   5565 #ifndef BCM_SW_STATE_DUMP_DISABLE
   5566 /*
   5567  * Function:
   5568  *     _bcm_th_ipmc_repl_sw_dump
   5569  * Purpose:
   5570  *     Displays IPMC replication information maintained by software.
   5571  * Parameters:
   5572  *     unit - Device unit number
   5573  * Returns:
   5574  *     None
   5575  */
   5576 void
   5577 _bcm_th_ipmc_repl_sw_dump(int unit)
   5578 {
   5579     _th_repl_info_t *repl_info;
   5580     int pipe;
   5581     bcm_port_t port;
   5582     _th_repl_port_info_t *port_info;
   5583     int i, j;
   5584     _bcm_repl_list_info_t *rli_start, *rli_current;
   5585     SHR_BITDCL *bitmap;
   5586     _th_repl_head_free_block_t *free_block;
   5587 
   5588     LOG_CLI((BSL_META_U(unit,
   5589                         "  IPMC REPL Info -\n")));
   5590     repl_info = _th_repl_info[unit];
   5591     if (repl_info != NULL) {
   5592         LOG_CLI((BSL_META_U(unit,
   5593                             "    Number of Pipelines : %d\n"),
   5594                  repl_info->num_pipes));
   5595         LOG_CLI((BSL_META_U(unit,
   5596                             "    Replication Group Size : %d\n"),
   5597                  repl_info->num_repl_groups));
   5598         LOG_CLI((BSL_META_U(unit,
   5599                             "    Replication Intf Size  : %d\n"),
   5600                  repl_info->num_intf));
   5601 
   5602         LOG_CLI((BSL_META_U(unit,
   5603                             "    Port Info    -\n")));
   5604         LOG_CLI((BSL_META_U(unit,
   5605                             "    port (index:intf-count) :\n")));
   5606         for (port = 0; port < SOC_MAX_NUM_PORTS; port++) {
   5607             port_info = repl_info->port_info[port];
   5608             LOG_CLI((BSL_META_U(unit,
   5609                                 "    %3d -"), port));
   5610             if (port_info == NULL) {
   5611                 LOG_CLI((BSL_META_U(unit,
   5612                                     " null\n")));
   5613                 continue;
   5614             }
   5615             for (i = 0, j = 0; i < repl_info->num_repl_groups; i++) {
   5616                 /* If zero, skip print */
   5617                 if (port_info->intf_count[i] == 0) {
   5618                     continue;
   5619                 }
   5620                 if ((j > 0) && !(j % 4)) {
   5621                     LOG_CLI((BSL_META_U(unit,
   5622                                         "\n         ")));
   5623                 }
   5624                 LOG_CLI((BSL_META_U(unit,
   5625                                     " %5d:%-5d"), i, port_info->intf_count[i]));
   5626                 j++;
   5627             }
   5628             LOG_CLI((BSL_META_U(unit,
   5629                                 "\n")));
   5630         }
   5631 
   5632         for (pipe = 0; pipe < NUM_PIPES(unit); pipe++) {
   5633             rli_start = REPL_LIST_INFO(unit, pipe);
   5634             LOG_CLI((BSL_META_U(unit,
   5635                                 "    Pipeline %d List Info -\n"), pipe));
   5636             for (rli_current = rli_start; rli_current != NULL;
   5637                     rli_current = rli_current->next) {
   5638                 LOG_CLI((BSL_META_U(unit,
   5639                                     "    Hash:  0x%08x\n"), rli_current->hash));
   5640                 LOG_CLI((BSL_META_U(unit,
   5641                                     "    Index: %5d\n"), rli_current->index));
   5642                 LOG_CLI((BSL_META_U(unit,
   5643                                     "    Size:  %5d\n"), rli_current->list_size));
   5644                 LOG_CLI((BSL_META_U(unit,
   5645                                     "    Refs:  %5d\n"), rli_current->refcount));
   5646             }
   5647         }
   5648 
   5649         LOG_CLI((BSL_META_U(unit,
   5650                             "    L3 Interface Next Hop IPMC Info -\n")));
   5651         for (i = 0; i < soc_mem_index_count(unit, EGR_L3_INTFm); i++) {
   5652            if (repl_info->l3_intf_next_hop_ipmc[i] == -1) {
   5653               continue;
   5654            }
   5655           LOG_CLI((BSL_META_U(unit,
   5656                               "      L3 Interface %4d: Next Hop Index %5d\n"), i,
   5657                    repl_info->l3_intf_next_hop_ipmc[i]));
   5658         }
   5659 
   5660         LOG_CLI((BSL_META_U(unit,
   5661                             "    L3 Interface Next Hop Trill Info -\n")));
   5662         for (i = 0; i < soc_mem_index_count(unit, EGR_L3_INTFm); i++) {
   5663            if (repl_info->l3_intf_next_hop_trill[i] == -1) {
   5664               continue;
   5665            }
   5666           LOG_CLI((BSL_META_U(unit,
   5667                               "      L3 Interface %4d: Next Hop Index %5d\n"), i,
   5668                    repl_info->l3_intf_next_hop_trill[i]));
   5669         }
   5670     }
   5671 
   5672     if (_th_repl_list_entry_info[unit] != NULL) {
   5673         for (pipe = 0; pipe < NUM_PIPES(unit); pipe++) {
   5674             LOG_CLI((BSL_META_U(unit,
   5675                                 "    Pipeline %d Replication List Table Size : %d\n"),
   5676                      pipe, _th_repl_list_entry_info[unit][pipe].num_entries));
   5677             LOG_CLI((BSL_META_U(unit,
   5678                                 "    Pipeline %d Replication List Table Usage Bitmap (index:value-hex) :"),
   5679                      pipe));
   5680             if (NULL !=
   5681                     _th_repl_list_entry_info[unit][pipe].bitmap_entries_used) {
   5682                 bitmap = _th_repl_list_entry_info[unit][pipe].bitmap_entries_used;
   5683                 for (i = 0, j = 0;
   5684                         i < _SHR_BITDCLSIZE(_th_repl_list_entry_info[unit][pipe].num_entries);
   5685                         i++) {
   5686                     /* If zero, skip print */
   5687                     if (bitmap[i] == 0) {
   5688                         continue;
   5689                     }
   5690                     if (!(j % 4)) {
   5691                         LOG_CLI((BSL_META_U(unit,
   5692                                             "\n    ")));
   5693                     }
   5694                     LOG_CLI((BSL_META_U(unit,
   5695                                         "  %5d:%8.8x"), i, bitmap[i]));
   5696                     j++;
   5697                 }
   5698             }
   5699             LOG_CLI((BSL_META_U(unit,
   5700                                 "\n")));
   5701         }
   5702     }
   5703 
   5704     if (_th_repl_head_info[unit] != NULL) {
   5705         for (pipe = 0; pipe < NUM_PIPES(unit); pipe++) {
   5706             LOG_CLI((BSL_META_U(unit,
   5707                                 "    Pipeline %d Replication Head Table Size : %d\n"),
   5708                      pipe, 1 << soc_mem_field_length(unit,
   5709                      MMU_REPL_GROUP_INFO_TBLm, PIPE_BASE_PTRf)));
   5710             LOG_CLI((BSL_META_U(unit,
   5711                                 "    Pipeline %d Replication Head Free List Array:\n"),
   5712                      pipe));
   5713             if (_th_repl_head_info[unit][pipe].free_list_array != NULL) {
   5714                 for (i = 0; i < _th_repl_head_info[unit][pipe].array_size; i++) {
   5715                     LOG_CLI((BSL_META_U(unit,
   5716                                         "      Free List %2d:"), i));
   5717                     free_block = REPL_HEAD_FREE_LIST(unit, pipe, i);
   5718                     j = 0;
   5719                     while (NULL != free_block) {
   5720                         if (j > 0 && !(j % 4)) {
   5721                             LOG_CLI((BSL_META_U(unit,
   5722                                                 "\n                   ")));
   5723                         }
   5724                         LOG_CLI((BSL_META_U(unit,
   5725                                             "  %7d:%-7d"), free_block->index,
   5726                                  free_block->size));
   5727                         free_block = free_block->next;
   5728                         j++;
   5729                     }
   5730                     LOG_CLI((BSL_META_U(unit,
   5731                                         "\n")));
   5732                 }
   5733             }
   5734         }
   5735     }
   5736 
   5737     return;
   5738 }
   5739 #endif /* BCM_SW_STATE_DUMP_DISABLE */
   5740 
   5741 /*
   5742   * Function:
   5743   *      _th_ipmc_glp_get
   5744   * Purpose:
   5745   *      Fill information in bcm_ipmc_addr_t struct.
   5746   */
   5747     
   5748 bcm_error_t
   5749 _th_ipmc_glp_get(int unit, bcm_ipmc_addr_t *ipmc, _bcm_l3_cfg_t *l3cfg)
   5750 {
   5751 
   5752     int no_src_check = FALSE;
   5753     int is_trunk = 0;
   5754     _bcm_l3_cfg_t l3cfg_local;
   5755     int rv = BCM_E_NONE;
   5756     
   5757     l3cfg_local = *l3cfg;  
   5758     if (l3cfg_local.l3c_tunnel) {
   5759         is_trunk = 1;
   5760         if ((((l3cfg_local.l3c_port_tgid & TH_IPMC_NO_SRC_CHECK_PORT) == 
   5761             TH_IPMC_NO_SRC_CHECK_PORT)) &&
   5762             (l3cfg_local.l3c_modid == SOC_MODID_MAX(unit))) {
   5763             no_src_check = TRUE;
   5764             is_trunk = 0;
   5765         }
   5766     }
   5767 
   5768 #ifdef BCM_TRIDENT3_SUPPORT
   5769     if (SOC_IS_TRIDENT3X(unit)) {
   5770         if ((((l3cfg_local.l3c_port_tgid & TH_IPMC_NO_SRC_CHECK_PORT) ==
   5771             TH_IPMC_NO_SRC_CHECK_PORT)) &&
   5772             (l3cfg_local.l3c_modid == SOC_MODID_MAX(unit))) {
   5773             no_src_check = TRUE;
   5774             is_trunk = 0;
   5775         }
   5776     }
   5777 #endif /* BCM_TRIDENT3_SUPPORT */
   5778 
   5779     if (no_src_check) {
   5780         ipmc->ts = 0;
   5781         ipmc->mod_id = -1;
   5782         ipmc->port_tgid = -1;
   5783         ipmc->flags |= BCM_IPMC_SOURCE_PORT_NOCHECK;
   5784     } else if (is_trunk) {
   5785         ipmc->ts = 1;
   5786         ipmc->mod_id = 0;
   5787         ipmc->port_tgid = l3cfg_local.l3c_port_tgid;
   5788     } else {
   5789         bcm_module_t    mod_in, mod_out;
   5790         bcm_port_t      port_in, port_out;
   5791 
   5792         mod_in = l3cfg_local.l3c_modid;
   5793         port_in = l3cfg_local.l3c_port_tgid;
   5794         BCM_IF_ERROR_RETURN
   5795             (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
   5796                                      mod_in, port_in,
   5797                                      &mod_out, &port_out));
   5798         /* Check parameters, since above is an application callback */
   5799         if (!SOC_MODID_ADDRESSABLE(unit, mod_out)) {
   5800             return BCM_E_BADID;
   5801         }
   5802         if (!SOC_PORT_ADDRESSABLE(unit, port_out)) {
   5803             return BCM_E_PORT;
   5804         }        
   5805         ipmc->ts = 0;
   5806         ipmc->mod_id = mod_out;
   5807         ipmc->port_tgid = port_out;
   5808     }    
   5809 
   5810     return rv;
   5811 }
   5812 
   5813 /*
   5814  * Function:
   5815  *      _th_ipmc_info_get
   5816  * Purpose:
   5817  *      Fill information in bcm_ipmc_addr_t struct.
   5818  */
   5819 
   5820 bcm_error_t
   5821 _th_ipmc_info_get(int unit, int ipmc_index, bcm_ipmc_addr_t *ipmc, 
   5822                   ipmc_entry_t *entry, _bcm_esw_ipmc_l3entry_t *use_ipmc_l3entry)
   5823 {
   5824 
   5825     ipmc->v = soc_L3_IPMCm_field32_get(unit, entry, VALIDf);
   5826 
   5827     if (ipmc->v) {
   5828         _bcm_l3_cfg_t l3cfg;
   5829         _bcm_esw_ipmc_l3entry_t *ipmc_l3entry;
   5830 
   5831         if (use_ipmc_l3entry != NULL) {
   5832             /* use the passed in l3 info */
   5833             ipmc_l3entry = use_ipmc_l3entry;
   5834         } else {
   5835             /* Note: this simply picks up the first l3 info */
   5836             ipmc_l3entry = IPMC_GROUP_INFO(unit, ipmc_index)->l3entry_list;
   5837             if (NULL == ipmc_l3entry) {
   5838                 /* No entries in Multicast host table */
   5839                 return BCM_E_EMPTY;
   5840             }
   5841         }
   5842         sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   5843         l3cfg.l3c_flags = BCM_L3_IPMC;
   5844         l3cfg.l3c_vrf = ipmc_l3entry->l3info.vrf;
   5845         l3cfg.l3c_vid = ipmc_l3entry->l3info.vid;
   5846         l3cfg.l3c_ing_intf = ipmc_l3entry->l3info.ing_intf;
   5847 
   5848         if (ipmc_l3entry->ip6) {
   5849             ipmc->flags |= BCM_IPMC_IP6;
   5850         } else {
   5851             ipmc->flags &= ~BCM_IPMC_IP6;
   5852         }
   5853         if (ipmc->flags & BCM_IPMC_HIT_CLEAR) {
   5854             l3cfg.l3c_flags |= BCM_L3_HIT_CLEAR;
   5855         }
   5856         
   5857         /* need to get current l3 info from h/w like hit bits */
   5858         if (ipmc->flags & BCM_IPMC_IP6) {
   5859             sal_memcpy(ipmc->s_ip6_addr, &ipmc_l3entry->l3info.sip6, BCM_IP6_ADDRLEN);
   5860             sal_memcpy(ipmc->mc_ip6_addr, &ipmc_l3entry->l3info.ip6, BCM_IP6_ADDRLEN);
   5861             sal_memcpy(l3cfg.l3c_sip6, &ipmc_l3entry->l3info.sip6, BCM_IP6_ADDRLEN);
   5862             sal_memcpy(l3cfg.l3c_ip6, &ipmc_l3entry->l3info.ip6, BCM_IP6_ADDRLEN);
   5863             l3cfg.l3c_flags |= BCM_L3_IP6;
   5864             BCM_IF_ERROR_RETURN(mbcm_driver[unit]->mbcm_l3_ip6_get(unit, &l3cfg));
   5865         } else {
   5866             ipmc->s_ip_addr = ipmc_l3entry->l3info.src_ip_addr;
   5867             ipmc->mc_ip_addr = ipmc_l3entry->l3info.ipmc_group;
   5868             l3cfg.l3c_src_ip_addr = ipmc_l3entry->l3info.src_ip_addr;
   5869             l3cfg.l3c_ipmc_group = ipmc_l3entry->l3info.ipmc_group;
   5870             BCM_IF_ERROR_RETURN(mbcm_driver[unit]->mbcm_l3_ip4_get(unit, &l3cfg));
   5871         }
   5872         
   5873         if (l3cfg.l3c_flags & BCM_L3_HIT) {
   5874             ipmc->flags |= BCM_IPMC_HIT;
   5875         }
   5876 
   5877         if (l3cfg.l3c_flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) {
   5878             ipmc->flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK;
   5879             ipmc->l3a_intf = l3cfg.l3c_intf;
   5880             if (l3cfg.l3c_flags & BCM_IPMC_RPF_FAIL_DROP) {
   5881                 ipmc->flags |= BCM_IPMC_RPF_FAIL_DROP;
   5882             }
   5883             if (l3cfg.l3c_flags & BCM_IPMC_RPF_FAIL_TOCPU) {
   5884                 ipmc->flags |= BCM_IPMC_RPF_FAIL_TOCPU;
   5885             }
   5886         }
   5887 
   5888         if (ipmc_l3entry->l3info.flags & BCM_L3_RPE) {
   5889             ipmc->cos = ipmc_l3entry->l3info.prio;
   5890             ipmc->flags |= BCM_IPMC_SETPRI;
   5891         } else {
   5892             ipmc->cos = -1;
   5893             ipmc->flags &= ~BCM_IPMC_SETPRI;
   5894         }
   5895         ipmc->group = ipmc_index;
   5896         ipmc->group_l2 = ipmc_l3entry->l3info.ipmc_ptr_l2;
   5897         ipmc->lookup_class = ipmc_l3entry->l3info.lookup_class;
   5898         ipmc->vrf = ipmc_l3entry->l3info.vrf;
   5899         ipmc->vid = ipmc_l3entry->l3info.vid;
   5900         ipmc->ing_intf = ipmc_l3entry->l3info.ing_intf;
   5901         ipmc->rp_id = ipmc_l3entry->l3info.rp_id;
   5902         BCM_IF_ERROR_RETURN
   5903             (_th_ipmc_glp_get(unit, ipmc, &l3cfg));
   5904  
   5905     }
   5906     
   5907     return BCM_E_NONE;
   5908 }
   5909 
   5910 /*
   5911   * Function:
   5912   *      _th_ipmc_glp_set
   5913   * Purpose:
   5914   *      Fill information in bcm_ipmc_addr_t struct.
   5915   */
   5916     
   5917 bcm_error_t
   5918 _th_ipmc_glp_set(int unit, bcm_ipmc_addr_t *ipmc, _bcm_l3_cfg_t *l3cfg)
   5919 {
   5920 
   5921     int  mod, port_tgid, is_trunk, no_src_check = FALSE;
   5922     int rv = BCM_E_NONE;
   5923 
   5924     if ((ipmc->flags & BCM_IPMC_SOURCE_PORT_NOCHECK) ||
   5925         (ipmc->port_tgid < 0)) {                        /* no source port */
   5926         no_src_check = TRUE;
   5927         is_trunk = 0;
   5928         mod = SOC_MODID_MAX(unit);
   5929         port_tgid = TH_IPMC_NO_SRC_CHECK_PORT;
   5930     } else if (ipmc->ts) {                              /* trunk source port */
   5931         is_trunk = 1;
   5932         mod = 0;
   5933         port_tgid = ipmc->port_tgid;
   5934     } else {                                            /* source port */
   5935         bcm_module_t    mod_in, mod_out;
   5936         bcm_port_t      port_in, port_out;
   5937 
   5938         mod_in = ipmc->mod_id;
   5939         port_in = ipmc->port_tgid;
   5940         BCM_IF_ERROR_RETURN
   5941             (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET,
   5942                                     mod_in, port_in,
   5943                                     &mod_out, &port_out));
   5944         /* Check parameters, since above is an application callback */
   5945         if (!SOC_MODID_ADDRESSABLE(unit, mod_out)) {
   5946             return BCM_E_BADID;
   5947         }
   5948         if (!SOC_PORT_ADDRESSABLE(unit, port_out)) {
   5949             return BCM_E_PORT;
   5950         }
   5951         is_trunk = 0;
   5952         mod = mod_out;
   5953         port_tgid = port_out;
   5954     }
   5955 
   5956     if (is_trunk) {
   5957         l3cfg->l3c_tunnel = 1;
   5958         l3cfg->l3c_modid = 0;
   5959         l3cfg->l3c_port_tgid = port_tgid;
   5960     } else {
   5961         l3cfg->l3c_modid = mod;
   5962         if (no_src_check) {
   5963             l3cfg->l3c_tunnel = 1;
   5964             if (SOC_IS_TRIDENT3X(unit)) {
   5965                 l3cfg->l3c_tunnel = 0;
   5966             }
   5967         } else {
   5968             l3cfg->l3c_tunnel = 0;
   5969         }
   5970             l3cfg->l3c_port_tgid = port_tgid;            
   5971     }
   5972 
   5973     return rv;
   5974 }
   5975 
   5976 
   5977 /*
   5978  * Function:
   5979  *      _bcm_th_ipmc_l3_intf_next_hop_get
   5980  * Purpose:
   5981  *      Get the next hop index that was silently allocated to the L3 interface.
   5982  * Parameters:
   5983  *      unit - (IN) SOC unit #
   5984  *      intf - (IN) L3 interface ID
   5985  *      nh_index - (OUT) Next hop index
   5986  * Returns:
   5987  *      BCM_E_XXX
   5988  */
   5989 int
   5990 _bcm_th_ipmc_l3_intf_next_hop_get(int unit, int intf, int *nh_index)
   5991 {
   5992     *nh_index = REPL_L3_INTF_NEXT_HOP_IPMC(unit, intf);
   5993 
   5994     if (*nh_index == REPL_NH_INDEX_UNALLOCATED ||
   5995         *nh_index == REPL_NH_INDEX_L3_EGRESS_ALLOCATED) {
   5996         return BCM_E_NOT_FOUND;
   5997     }
   5998 
   5999     return BCM_E_NONE;
   6000 }
   6001 
   6002 /*
   6003  * Function:
   6004  *      _bcm_th_ipmc_l3_intf_next_hop_l3_egress_clear
   6005  * Purpose:
   6006  *      Inform the IPMC module that a next hop index has been deleted
   6007  *      for the given L3 interface by the bcm_l3_egress_destroy API.
   6008  * Parameters:
   6009  *      unit - SOC device unit number
   6010  *      nh_idx - next hop index
   6011  * Returns:
   6012  *      BCM_E_NONE              Success
   6013  *      BCM_E_XXX               ERROR
   6014  */
   6015 int _bcm_th_ipmc_l3_intf_next_hop_l3_egress_clear(int unit, int nh_idx)
   6016 {
   6017     soc_mem_t mem;                        /* Table location memory. */
   6018     egr_l3_next_hop_entry_t  egr_entry;   /* Egress next hop entry. */
   6019     int ent_type, intf_num;
   6020 
   6021     mem = EGR_L3_NEXT_HOPm;
   6022     sal_memset(&egr_entry, 0, sizeof(egr_l3_next_hop_entry_t));
   6023 
   6024     SOC_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, EGR_L3_NEXT_HOPm,
   6025                                           nh_idx, &egr_entry));
   6026 
   6027     if (soc_feature(unit, soc_feature_mem_access_data_type)) {
   6028         ent_type = soc_mem_field32_get(unit, mem, &egr_entry, DATA_TYPEf);
   6029     } else {
   6030         ent_type = soc_mem_field32_get(unit, mem, &egr_entry, ENTRY_TYPEf);
   6031     }
   6032 
   6033     /* chk if the entry is L3MC */
   6034     if (ent_type == 7) {
   6035         intf_num = soc_mem_field32_get
   6036             (unit, mem, &egr_entry, L3MC__INTF_NUMf);
   6037         if (REPL_L3_INTF_NEXT_HOP_IPMC(unit, intf_num)  ==
   6038                          REPL_NH_INDEX_L3_EGRESS_ALLOCATED) {
   6039             REPL_L3_INTF_NEXT_HOP_IPMC(unit, intf_num) =
   6040                 REPL_NH_INDEX_UNALLOCATED;
   6041         }
   6042     }
   6043 
   6044     return BCM_E_NONE;
   6045 }
   6046 
   6047 
   6048 /*
   6049  * Function:
   6050  *      _bcm_th_ipmc_l3_intf_next_hop_l3_egress_set
   6051  * Purpose:
   6052  *      Inform the IPMC module that a next hop index has been allocated
   6053  *      for the given L3 interface by the bcm_l3_egress_create API.
   6054  * Parameters:
   6055  *      unit - (IN) SOC unit #
   6056  *      intf - (IN) L3 interface ID
   6057  * Returns:
   6058  *      BCM_E_XXX
   6059  */
   6060 int
   6061 _bcm_th_ipmc_l3_intf_next_hop_l3_egress_set(int unit, int intf)
   6062 {
   6063     int nh_index;
   6064 
   6065     nh_index = REPL_L3_INTF_NEXT_HOP_IPMC(unit, intf);
   6066 
   6067     if (nh_index == REPL_NH_INDEX_UNALLOCATED) {
   6068         REPL_L3_INTF_NEXT_HOP_IPMC(unit, intf) =
   6069             REPL_NH_INDEX_L3_EGRESS_ALLOCATED;
   6070     } else if (nh_index == REPL_NH_INDEX_L3_EGRESS_ALLOCATED) {
   6071         /* Do nothing. Users are allowed to create multiple L3
   6072          * egress objects based on the same L3 interface.
   6073          */
   6074     } else {
   6075         /* IPMC module had already silently allocated a next hop index
   6076          * for this L3 interface.
   6077          */
   6078         return BCM_E_CONFIG;
   6079     }
   6080         
   6081     return BCM_E_NONE;
   6082 }
   6083 
   6084 STATIC int
   6085 _bcm_th_ipmc_egress_intf_set_for_trunk_first_member(
   6086     int unit, int repl_group, bcm_port_t port,
   6087     int if_count, bcm_if_t *if_array, int is_l3,
   6088     int check_port, bcm_trunk_t tgid)
   6089 {
   6090     int old_intf_count, new_intf_count;
   6091     int aggid;
   6092 
   6093     old_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group);
   6094     if ((old_intf_count == 0) && (if_count > 0)) {
   6095         BCM_IF_ERROR_RETURN(bcm_th_port_aggid_add(unit, port, tgid, &aggid));
   6096     }
   6097 
   6098     BCM_IF_ERROR_RETURN(
   6099         _bcm_esw_ipmc_egress_intf_set(
   6100             unit, repl_group, port, if_count, if_array, is_l3, check_port));
   6101 
   6102     new_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group);
   6103     if ((old_intf_count > 0) && (new_intf_count == 0)) {
   6104         BCM_IF_ERROR_RETURN(bcm_th_port_aggid_del(unit, port));
   6105     }
   6106 
   6107     return BCM_E_NONE;
   6108 }
   6109 
   6110 
   6111 STATIC int
   6112 _bcm_th_ipmc_egress_intf_set_for_same_pipe_member(
   6113     int unit, int repl_group, bcm_port_t port,
   6114     bcm_port_t first_port, bcm_trunk_t tgid)
   6115 {
   6116     int aggid;
   6117     int old_intf_count, new_intf_count;
   6118 
   6119     old_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group);
   6120     new_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, first_port, repl_group);
   6121     if (old_intf_count == new_intf_count) {
   6122         return BCM_E_NONE;
   6123     }
   6124 
   6125     BCM_IF_ERROR_RETURN(
   6126         _bcm_th_repl_initial_copy_count_set(unit, repl_group,
   6127                                              port, new_intf_count));
   6128 
   6129     if ((old_intf_count == 0) && (new_intf_count > 0)) {
   6130         BCM_IF_ERROR_RETURN(bcm_th_port_aggid_add(unit, port, tgid, &aggid));
   6131     } else if ((old_intf_count > 0) && (new_intf_count == 0)) {
   6132         BCM_IF_ERROR_RETURN(bcm_th_port_aggid_del(unit, port));
   6133     }
   6134 
   6135     REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group) = new_intf_count;
   6136 
   6137     return BCM_E_NONE;
   6138 }
   6139 
   6140 STATIC int
   6141 _bcm_th_ipmc_egress_intf_add_in_per_trunk_mode(int unit, int repl_group,
   6142     bcm_port_t port, int encap_id, int is_l3)
   6143 {
   6144     int aggid;
   6145 
   6146     if (REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group) == 0) {
   6147         BCM_IF_ERROR_RETURN(
   6148             bcm_th_port_aggid_add(unit, port, BCM_TRUNK_INVALID, &aggid));
   6149     }
   6150 
   6151     BCM_IF_ERROR_RETURN(
   6152         _bcm_th_ipmc_egress_intf_add(
   6153             unit, repl_group, port, encap_id, is_l3));
   6154 
   6155     return BCM_E_NONE;
   6156 }
   6157 
   6158 STATIC int
   6159 _bcm_th_ipmc_egress_intf_del_in_per_trunk_mode(int unit, int repl_group,
   6160     bcm_port_t port, int if_max, int encap_id, int is_l3)
   6161 {
   6162 
   6163     int old_intf_count, new_intf_count;
   6164 
   6165     old_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group);
   6166     BCM_IF_ERROR_RETURN(
   6167         _bcm_th_ipmc_egress_intf_delete(
   6168             unit, repl_group, port, if_max, encap_id, is_l3));
   6169     new_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group);
   6170     if (new_intf_count == 0 && old_intf_count > 0) {
   6171         BCM_IF_ERROR_RETURN(bcm_th_port_aggid_del(unit, port));
   6172     }
   6173 
   6174     return BCM_E_NONE;
   6175 }
   6176 
   6177 
   6178 STATIC int
   6179 _bcm_th_ipmc_egress_intf_add_for_trunk(int unit, int repl_group,
   6180     bcm_trunk_t tgid, int encap_id, int is_l3)
   6181 {
   6182 #if defined(BCM_ESW_SUPPORT) && (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS)
   6183     bcm_port_t      trunk_local_member_ports[SOC_MAX_NUM_PP_PORTS] = {0};
   6184     int             max_num_ports = SOC_MAX_NUM_PP_PORTS;
   6185 #else
   6186     bcm_port_t      trunk_local_member_ports[SOC_MAX_NUM_PORTS] = {0};
   6187     int             max_num_ports = SOC_MAX_NUM_PORTS;
   6188 #endif
   6189 
   6190     int idx;
   6191     int member_count, port_iter;
   6192     bcm_port_t trunk_pipe_first_port_array[BCM_PIPES_MAX];
   6193     int aggid, pipe;
   6194 
   6195     BCM_IF_ERROR_RETURN(
   6196         _bcm_esw_trunk_local_members_get(unit, tgid, max_num_ports,
   6197                                          trunk_local_member_ports,
   6198                                          &member_count));
   6199 
   6200     for (idx = 0; idx < BCM_PIPES_MAX; idx++) {
   6201         trunk_pipe_first_port_array[idx] = -1;
   6202     }
   6203     for (idx = 0; idx < member_count; idx++) {
   6204         port_iter = trunk_local_member_ports[idx];
   6205         pipe      = SOC_INFO(unit).port_pipe[port_iter];
   6206         if (trunk_pipe_first_port_array[pipe] == -1) {
   6207             if (REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group) == 0) {
   6208                 BCM_IF_ERROR_RETURN(
   6209                     bcm_th_port_aggid_add(unit, port_iter, tgid, &aggid));
   6210             }
   6211             BCM_IF_ERROR_RETURN(
   6212                 _bcm_th_ipmc_egress_intf_add(
   6213                     unit, repl_group, port_iter, encap_id, is_l3));
   6214             trunk_pipe_first_port_array[pipe] = port_iter;
   6215         } else {
   6216             BCM_IF_ERROR_RETURN(
   6217                 _bcm_th_ipmc_egress_intf_set_for_same_pipe_member(
   6218                     unit, repl_group, port_iter,
   6219                     trunk_pipe_first_port_array[pipe], tgid));
   6220         }
   6221     }
   6222 
   6223     return BCM_E_NONE;
   6224 }
   6225 
   6226 STATIC int
   6227 _bcm_th_ipmc_egress_intf_del_for_trunk(int unit, int repl_group,
   6228     bcm_trunk_t tgid, int if_max, int encap_id, int is_l3)
   6229 {
   6230 #if defined(BCM_ESW_SUPPORT) && (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS)
   6231     bcm_port_t      trunk_local_member_ports[SOC_MAX_NUM_PP_PORTS] = {0};
   6232     int             max_num_ports = SOC_MAX_NUM_PP_PORTS;
   6233 #else
   6234     bcm_port_t      trunk_local_member_ports[SOC_MAX_NUM_PORTS] = {0};
   6235     int             max_num_ports = SOC_MAX_NUM_PORTS;
   6236 #endif
   6237 
   6238     int idx;
   6239     int member_count, port_iter;
   6240     bcm_port_t trunk_pipe_first_port_array[BCM_PIPES_MAX];
   6241     int pipe;
   6242     int old_intf_count, new_intf_count;
   6243 
   6244     BCM_IF_ERROR_RETURN(
   6245         _bcm_esw_trunk_local_members_get(unit, tgid, max_num_ports,
   6246                                          trunk_local_member_ports,
   6247                                          &member_count));
   6248 
   6249     for (idx = 0; idx < BCM_PIPES_MAX; idx++) {
   6250         trunk_pipe_first_port_array[idx] = -1;
   6251     }
   6252 
   6253     for (idx = 0; idx < member_count; idx++) {
   6254         port_iter = trunk_local_member_ports[idx];
   6255         pipe      = SOC_INFO(unit).port_pipe[port_iter];
   6256         if (trunk_pipe_first_port_array[pipe] == -1) {
   6257             old_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group);
   6258             BCM_IF_ERROR_RETURN(
   6259                 _bcm_th_ipmc_egress_intf_delete(
   6260                      unit, repl_group, trunk_local_member_ports[idx],
   6261                      if_max, encap_id, is_l3));
   6262             new_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group);
   6263             if (new_intf_count == 0 && old_intf_count > 0) {
   6264                 BCM_IF_ERROR_RETURN(
   6265                     bcm_th_port_aggid_del(unit, port_iter));
   6266             }
   6267             trunk_pipe_first_port_array[pipe] = port_iter;
   6268         } else {
   6269             BCM_IF_ERROR_RETURN(
   6270                 _bcm_th_ipmc_egress_intf_set_for_same_pipe_member(
   6271                     unit, repl_group, port_iter,
   6272                     trunk_pipe_first_port_array[pipe], tgid));
   6273         }
   6274     }
   6275 
   6276     return BCM_E_NONE;
   6277 }
   6278 
   6279 STATIC int
   6280 _bcm_th_ipmc_egress_intf_add_trunk_member(int unit, int repl_group,
   6281                                            bcm_port_t port)
   6282 {
   6283 #if defined(BCM_ESW_SUPPORT) && (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS)
   6284     bcm_port_t      trunk_local_member_ports[SOC_MAX_NUM_PP_PORTS] = {0};
   6285     int             max_num_ports = SOC_MAX_NUM_PP_PORTS;
   6286 #else
   6287     bcm_port_t      trunk_local_member_ports[SOC_MAX_NUM_PORTS] = {0};
   6288     int             max_num_ports = SOC_MAX_NUM_PORTS;
   6289 #endif
   6290 
   6291     int local_modid;
   6292     int trunk_local_ports;
   6293     int intf_count, if_count, old_intf_count;
   6294     int same_pipe_port = -1, diff_pipe_port = -1;
   6295     int i, rv;
   6296     bcm_port_t port_iter;
   6297     bcm_if_t *if_array = NULL;
   6298     bcm_trunk_t tgid;
   6299     int aggid;
   6300 
   6301     /* Member port belongs to an existing trunk, it needs to share
   6302      * identical replication list as other members of this trunk in
   6303      * same pipe.
   6304      */
   6305     BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get (unit, &local_modid));
   6306     BCM_IF_ERROR_RETURN(
   6307         bcm_esw_trunk_find(unit, local_modid, port, &tgid));
   6308     BCM_IF_ERROR_RETURN(
   6309         _bcm_esw_trunk_local_members_get(unit, tgid, max_num_ports,
   6310                                          trunk_local_member_ports,
   6311                                          &trunk_local_ports));
   6312 
   6313     for (i = 0; i < trunk_local_ports; i++) {
   6314         port_iter = trunk_local_member_ports[i];
   6315         if (port != port_iter) {
   6316             intf_count =
   6317                 REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group);
   6318             if (intf_count > 0) {
   6319                 if (SOC_INFO(unit).port_pipe[port] ==
   6320                     SOC_INFO(unit).port_pipe[port_iter]) {
   6321                     same_pipe_port = port_iter;
   6322                     break;
   6323                 } else {
   6324                     if (diff_pipe_port == -1) {
   6325                         diff_pipe_port = port_iter;
   6326                     }
   6327                 }
   6328             }
   6329         }
   6330     }
   6331 
   6332 #ifdef BCM_TOMAHAWK3_SUPPORT
   6333     if (SOC_IS_TOMAHAWK3(unit)) {
   6334         if(same_pipe_port == -1 && diff_pipe_port == -1) {
   6335             return BCM_E_PARAM;
   6336         }
   6337         if (same_pipe_port != -1) {
   6338             BCM_IF_ERROR_RETURN(
   6339                 _bcm_th3_ipmc_egress_intf_set_for_same_trunk_member(
   6340                         unit, repl_group, port, same_pipe_port, tgid));
   6341         } else {
   6342              BCM_IF_ERROR_RETURN(
   6343                 _bcm_th3_ipmc_egress_intf_set_for_same_trunk_member(
   6344                     unit, repl_group, port, diff_pipe_port, tgid));
   6345 
   6346         }
   6347         return BCM_E_NONE;
   6348     }
   6349 #endif
   6350 
   6351     /* or return BCM_E_PARAM jinghuan */
   6352     if (same_pipe_port == -1 && diff_pipe_port == -1) {
   6353         return BCM_E_NONE;
   6354     }
   6355 
   6356     if (same_pipe_port != -1) {
   6357         BCM_IF_ERROR_RETURN(
   6358             _bcm_th_ipmc_egress_intf_set_for_same_pipe_member(
   6359                 unit, repl_group, port, same_pipe_port, tgid));
   6360     } else {
   6361         intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, diff_pipe_port,
   6362                                                 repl_group);
   6363         if_array = sal_alloc(sizeof(bcm_if_t) * intf_count,
   6364                              "if_array pointers");
   6365         if (if_array == NULL) {
   6366             return BCM_E_MEMORY;
   6367         }
   6368 
   6369         rv = bcm_th_ipmc_egress_intf_get(unit, repl_group, diff_pipe_port,
   6370                                           intf_count, if_array, &if_count);
   6371         if (BCM_FAILURE(rv)) {
   6372             sal_free(if_array);
   6373             return rv;
   6374         }
   6375 
   6376         old_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group);
   6377         if ((old_intf_count == 0) && (intf_count > 0)) {
   6378             rv = bcm_th_port_aggid_add(unit, port, tgid, &aggid);
   6379             if (BCM_FAILURE(rv)) {
   6380                 sal_free(if_array);
   6381                 return rv;
   6382             }
   6383         }
   6384         rv = _bcm_esw_ipmc_egress_intf_set(unit, repl_group, port,
   6385                                            if_count, if_array, TRUE, FALSE);
   6386         if (BCM_FAILURE(rv)) {
   6387             sal_free(if_array);
   6388             return rv;
   6389         }
   6390         sal_free(if_array);
   6391     }
   6392 
   6393     return BCM_E_NONE;
   6394 }
   6395 
   6396 STATIC int
   6397 _bcm_th_ipmc_egress_intf_del_trunk_member(int unit, int repl_group,
   6398                                            bcm_port_t port)
   6399 {
   6400     int is_last_member;
   6401     int old_intf_count;
   6402 
   6403     BCM_IF_ERROR_RETURN(
   6404         bcm_th_port_last_member_check(unit, port, &is_last_member));
   6405 
   6406     old_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group);
   6407     if (is_last_member) {
   6408         BCM_IF_ERROR_RETURN(
   6409             bcm_th_ipmc_egress_intf_set(
   6410                 unit, repl_group, port, 0, NULL, TRUE, FALSE));
   6411     } else {
   6412 #ifdef BCM_TOMAHAWK3_SUPPORT
   6413         if (SOC_IS_TOMAHAWK3(unit)) {
   6414             REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group) = 0;
   6415         } else
   6416 #endif
   6417         {
   6418         BCM_IF_ERROR_RETURN(
   6419             _bcm_th_repl_initial_copy_count_set(
   6420                 unit, repl_group, port, 0));
   6421         REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group) = 0;
   6422     }
   6423     }
   6424 
   6425     if (old_intf_count > 0) {
   6426         BCM_IF_ERROR_RETURN(bcm_th_port_aggid_del(unit, port));
   6427     }
   6428 
   6429     return BCM_E_NONE;
   6430 }
   6431 
   6432 /*
   6433  * Function:
   6434  *      bcm_th_ipmc_egress_intf_set_for_trunk_first_member
   6435  * Purpose:
   6436  *      Assign set of egress interfaces to the first port of a trunk.
   6437  *      or to the only one non-trunk port.
   6438  * Parameters:
   6439  *  unit       - (IN) StrataSwitch PCI device unit number.
   6440  *  repl_group - (IN) The replication group number.
   6441  *  port       - (IN) Port to assign replication list.
   6442  *  if_count   - (IN) Number of interfaces in replication list.
   6443  *  if_array   - (IN) List of interface numbers.
   6444  *  if_updated - (IN) interfaces info to be updated including
   6445  *                    interfaces which is new to the group and port
   6446  *                    and interfaces to be deleted.
   6447  *  is_l3      - (IN) Indicates if multicast group is of type IPMC.
   6448  *  check_port - (IN) If if_array consists of L3 interfaces, this parameter
   6449  *                    controls whether to check the given port is a member
   6450  *                    in each L3 interface's VLAN. This check should be
   6451  *                    disabled when not needed, in order to improve
   6452  *                    performance.
   6453  *  tgid       - (IN) trunk id or BCM_TRUNK_INVALID for non-trunk port.
   6454  *
   6455  * Returns:
   6456  *      BCM_E_XXX
   6457  */
   6458 int
   6459 bcm_th_ipmc_egress_intf_set_for_trunk_first_member(
   6460     int unit, int repl_group, bcm_port_t port,
   6461     int if_count, bcm_if_t *if_array, int is_l3,
   6462     int check_port, bcm_trunk_t tgid)
   6463 {
   6464     int rv = BCM_E_NONE;
   6465 
   6466     IPMC_LOCK(unit);
   6467     rv = _bcm_th_ipmc_egress_intf_set_for_trunk_first_member(
   6468              unit, repl_group, port, if_count, if_array,
   6469              is_l3, check_port, tgid);
   6470     IPMC_UNLOCK(unit);
   6471 
   6472     return rv;
   6473 }
   6474 
   6475 /*
   6476  * Function:
   6477  *      bcm_th_ipmc_egress_intf_set_for_same_pipe_member
   6478  * Purpose:
   6479  *      Align egress intf of same pipe port with the first port of trunk.
   6480  * Parameters:
   6481  *  unit       - (IN) StrataSwitch PCI device unit number.
   6482  *  repl_group - (IN) The replication group number.
   6483  *  port       - (IN) Port to assign replication list.
   6484  *  first_port - (IN) The first member port of the trunk.
   6485  *  tgid       - (IN) trunk id.
   6486  *
   6487  * Returns:
   6488  *      BCM_E_XXX
   6489  */
   6490 int
   6491 bcm_th_ipmc_egress_intf_set_for_same_pipe_member(
   6492     int unit, int repl_group, bcm_port_t port,
   6493     bcm_port_t first_port, bcm_trunk_t tgid)
   6494 {
   6495     int rv = BCM_E_NONE;
   6496 
   6497     IPMC_LOCK(unit);
   6498 #ifdef BCM_TOMAHAWK3_SUPPORT
   6499     if (SOC_IS_TOMAHAWK3(unit)) {
   6500         rv = _bcm_th3_ipmc_egress_intf_set_for_same_trunk_member(
   6501              unit, repl_group, port, first_port, tgid);
   6502     } else
   6503 #endif
   6504     {
   6505     rv = _bcm_th_ipmc_egress_intf_set_for_same_pipe_member(
   6506              unit, repl_group, port, first_port, tgid);
   6507     }
   6508     IPMC_UNLOCK(unit);
   6509 
   6510     return rv;
   6511 }
   6512 
   6513 /*
   6514  * Function:
   6515  *      bcm_th_ipmc_egress_intf_add_in_per_trunk_mode
   6516  * Purpose:
   6517  *      Add encap ID to selected ports' replication list for chosen
   6518  *      IPMC group in mc per trunk repl mode.
   6519  *      It is used for non-trunk port.
   6520  * Parameters:
   6521  *	unit       - (IN) StrataSwitch PCI device unit number.
   6522  *	repl_group - (IN) The replication group number.
   6523  *	port       - (IN) Port to assign replication list.
   6524  *  encap_id   - (IN) Encap ID.
   6525  *  is_l3      - (IN) Indicates if multicast group type is IPMC.
   6526  *
   6527  * Returns:
   6528  *      BCM_E_XXX
   6529  */
   6530 int
   6531 bcm_th_ipmc_egress_intf_add_in_per_trunk_mode(int unit, int repl_group,
   6532     bcm_port_t port, int encap_id, int is_l3)
   6533 {
   6534     int rv = BCM_E_NONE;
   6535 
   6536     IPMC_LOCK(unit);
   6537     rv = _bcm_th_ipmc_egress_intf_add_in_per_trunk_mode(
   6538              unit, repl_group, port, encap_id, is_l3);
   6539     IPMC_UNLOCK(unit);
   6540 
   6541     return rv;
   6542 }
   6543 
   6544 /*
   6545  * Function:
   6546  *      bcm_th_ipmc_egress_intf_del_in_per_trunk_mode
   6547  * Purpose:
   6548  *      Remove encap ID from selected ports' replication list for chosen
   6549  *      IPMC group in mc per trunk repl mode.
   6550  *      It is used for non-trunk port.
   6551  * Parameters:
   6552  *	unit       - (IN) StrataSwitch PCI device unit number.
   6553  *	repl_group - (IN) The replication group number.
   6554  *	port       - (IN) Port to assign replication list.
   6555  *  if_max     - (IN) Maximal interface.
   6556  *  encap_id   - (IN) Encap ID.
   6557  *  is_l3      - (IN) Indicates if multicast group type is IPMC.
   6558  * Returns:
   6559  *      BCM_E_XXX
   6560  */
   6561 int
   6562 bcm_th_ipmc_egress_intf_del_in_per_trunk_mode(int unit, int repl_group,
   6563     bcm_port_t port, int if_max, int encap_id, int is_l3)
   6564 {
   6565     int rv = BCM_E_NONE;
   6566 
   6567     IPMC_LOCK(unit);
   6568     rv = _bcm_th_ipmc_egress_intf_del_in_per_trunk_mode(
   6569              unit, repl_group, port, if_max, encap_id, is_l3);
   6570     IPMC_UNLOCK(unit);
   6571 
   6572     return rv;
   6573 }
   6574 
   6575 /*
   6576  * Function:
   6577  *      bcm_th_ipmc_egress_intf_add_for_trunk
   6578  * Purpose:
   6579  *      Add encap ID to a trunk.
   6580  * Parameters:
   6581  *	unit       - (IN) StrataSwitch PCI device unit number.
   6582  *	repl_group - (IN) The replication group number.
   6583  *	tgid       - (IN) Trunk ID.
   6584  *  encap_id   - (IN) Encap ID.
   6585  *  is_l3      - (IN) Indicates if multicast group type is IPMC.
   6586  *
   6587  * Returns:
   6588  *      BCM_E_XXX
   6589  */
   6590 int
   6591 bcm_th_ipmc_egress_intf_add_for_trunk(int unit, int repl_group,
   6592     bcm_trunk_t tgid, int encap_id, int is_l3)
   6593 {
   6594     int rv = BCM_E_NONE;
   6595 
   6596     IPMC_LOCK(unit);
   6597 #ifdef BCM_TOMAHAWK3_SUPPORT
   6598     if(SOC_IS_TOMAHAWK3(unit)) {
   6599         rv = _bcm_th3_ipmc_egress_intf_add_for_trunk(
   6600              unit, repl_group, tgid, encap_id, is_l3);
   6601 
   6602     } else
   6603 #endif
   6604     {
   6605     rv = _bcm_th_ipmc_egress_intf_add_for_trunk(
   6606              unit, repl_group, tgid, encap_id, is_l3);
   6607     }
   6608     IPMC_UNLOCK(unit);
   6609 
   6610     return rv;
   6611 }
   6612 
   6613 /*
   6614  * Function:
   6615  *      bcm_th_ipmc_egress_intf_del_for_trunk
   6616  * Purpose:
   6617  *      Remove encap ID from a trunk.
   6618  * Parameters:
   6619  *	unit       - (IN) StrataSwitch PCI device unit number.
   6620  *	repl_group - (IN) The replication group number.
   6621  *	tgid       - (IN) Trunk ID.
   6622  *  if_max     - (IN) Maximal interface.
   6623  *  encap_id   - (IN) Encap ID.
   6624  *  is_l3      - (IN) Indicates if multicast group type is IPMC.
   6625  *
   6626  * Returns:
   6627  *      BCM_E_XXX
   6628  */
   6629 int
   6630 bcm_th_ipmc_egress_intf_del_for_trunk(int unit, int repl_group,
   6631     bcm_trunk_t tgid, int if_max, int encap_id, int is_l3)
   6632 {
   6633     int rv = BCM_E_NONE;
   6634 
   6635     IPMC_LOCK(unit);
   6636 
   6637 #ifdef BCM_TOMAHAWK3_SUPPORT
   6638     if(SOC_IS_TOMAHAWK3(unit)) {
   6639         rv = _bcm_th3_ipmc_egress_intf_del_for_trunk(
   6640              unit, repl_group, tgid, if_max, encap_id, is_l3);
   6641     } else
   6642 #endif
   6643     {
   6644     rv = _bcm_th_ipmc_egress_intf_del_for_trunk(
   6645              unit, repl_group, tgid, if_max, encap_id, is_l3);
   6646     }
   6647     IPMC_UNLOCK(unit);
   6648 
   6649     return rv;
   6650 }
   6651 
   6652 /*
   6653  * Function:
   6654  *      bcm_th_ipmc_egress_intf_add_trunk_member
   6655  * Purpose:
   6656  *      Add a port member to a trunk for chosen IPMC group.
   6657  * Parameters:
   6658  *	unit       - (IN) StrataSwitch PCI device unit number.
   6659  *	repl_group - (IN) The replication group number.
   6660  *	port       - (IN) Trunk member port.
   6661  *
   6662  * Returns:
   6663  *      BCM_E_XXX
   6664  */
   6665 int
   6666 bcm_th_ipmc_egress_intf_add_trunk_member(int unit, int repl_group,
   6667                                            bcm_port_t port)
   6668 {
   6669     int rv = BCM_E_NONE;
   6670 
   6671     IPMC_LOCK(unit);
   6672     rv = _bcm_th_ipmc_egress_intf_add_trunk_member(
   6673              unit, repl_group, port);
   6674     IPMC_UNLOCK(unit);
   6675 
   6676     return rv;
   6677 }
   6678 
   6679 
   6680 /*
   6681  * Function:
   6682  *      bcm_th_ipmc_egress_intf_del_trunk_member
   6683  * Purpose:
   6684  *      Remove a port member from a trunk for chosen IPMC group.
   6685  * Parameters:
   6686  *	unit       - (IN) StrataSwitch PCI device unit number.
   6687  *	repl_group - (IN) The replication group number.
   6688  *	port       - (IN) Trunk member port.
   6689  *
   6690  * Returns:
   6691  *      BCM_E_XXX
   6692  */
   6693 int
   6694 bcm_th_ipmc_egress_intf_del_trunk_member(int unit, int repl_group,
   6695                                            bcm_port_t port)
   6696 {
   6697     int rv = BCM_E_NONE;
   6698 
   6699     IPMC_LOCK(unit);
   6700     rv = _bcm_th_ipmc_egress_intf_del_trunk_member(
   6701              unit, repl_group, port);
   6702     IPMC_UNLOCK(unit);
   6703 
   6704     return rv;
   6705 }
   6706 
   6707 /*
   6708  * Function:
   6709  *      bcm_th_ipmc_repl_port_attach
   6710  * Purpose:
   6711  *      Initialize replication per-port configuration in the runtime.
   6712  * Parameters:
   6713  *      unit - (IN) BCM device number.
   6714  *      port - local port number
   6715  * Returns:
   6716  *      BCM_E_XXX
   6717  */
   6718 int
   6719 bcm_th_ipmc_repl_port_attach(int unit, bcm_port_t port)
   6720 {
   6721     int rv = BCM_E_NONE;
   6722     int alloc_size;
   6723     int phy_port, mmu_port;
   6724     int port_speed, count_width;
   6725     uint32 regval;
   6726     soc_info_t *si;
   6727 
   6728 
   6729     if (_th_repl_info[unit] == NULL) {
   6730         return BCM_E_INIT;
   6731     }
   6732 
   6733     /* Detach the IPMC REPL in case it is already attached. */
   6734     SOC_IF_ERROR_RETURN
   6735         (bcm_th_ipmc_repl_port_detach(unit, port));
   6736 
   6737     _th_repl_info[unit]->port_info[port] =
   6738                     sal_alloc(sizeof(_th_repl_port_info_t), "repl port info");
   6739     if (NULL == _th_repl_info[unit]->port_info[port]) {
   6740         return BCM_E_MEMORY;
   6741     }
   6742     sal_memset(_th_repl_info[unit]->port_info[port], 0,
   6743                                                 sizeof(_th_repl_port_info_t));
   6744 
   6745     alloc_size = sizeof(int) * _th_repl_info[unit]->num_repl_groups;
   6746     _th_repl_info[unit]->port_info[port]->intf_count =
   6747                                 sal_alloc(alloc_size, "repl port intf count");
   6748     if (NULL == _th_repl_info[unit]->port_info[port]->intf_count) {
   6749         sal_free(_th_repl_info[unit]->port_info[port]);
   6750         return BCM_E_MEMORY;
   6751     }
   6752     sal_memset(_th_repl_info[unit]->port_info[port]->intf_count, 0, alloc_size);
   6753 
   6754     si = &SOC_INFO(unit);
   6755 
   6756     /* Initialize PORT_INITIAL_COPY_COUNT_WIDTH registers */
   6757     phy_port = si->port_l2p_mapping[port];
   6758     mmu_port = si->port_p2m_mapping[phy_port];
   6759 
   6760     if (SOC_IS_TOMAHAWK2(unit)) {
   6761         /* Single-lane ports are allocated 2 bits, while 2 or 4
   6762          * lane ports are allocated 3 bits. */
   6763         count_width = (si->port_num_lanes[port] > 1) ? 1 : 0;
   6764     } else {
   6765         /* For ports with speed 40G and above the copy count width
   6766          * is 3 bits (encoded value of 1) for lower speeds its
   6767          * 2 bits (encoded value of 0).
   6768          */
   6769         rv = bcm_esw_port_speed_get(unit, port, &port_speed);
   6770         if (BCM_FAILURE(rv)) {
   6771             (void)bcm_th_ipmc_repl_port_detach(unit, port);
   6772             return rv;
   6773         }
   6774 
   6775         count_width = (port_speed >= 40000) ? 1 : 0;
   6776     }
   6777 
   6778     if (!soc_feature(unit, soc_feature_skip_port_initial_copy_count)) {
   6779         regval = 0;
   6780         soc_reg_field_set(unit, PORT_INITIAL_COPY_COUNT_WIDTHr, &regval,
   6781                 BIT_WIDTHf, count_width);
   6782         rv = WRITE_PORT_INITIAL_COPY_COUNT_WIDTHr(unit, port, regval);
   6783         if (BCM_FAILURE(rv)) {
   6784             (void)bcm_th_ipmc_repl_port_detach(unit, port);
   6785             return rv;
   6786         }
   6787     }
   6788 
   6789     /* configure mmu port to repl aggregateId map */
   6790     regval = 0;
   6791     if(SOC_IS_TOMAHAWK3(unit)) {
   6792         soc_reg_field_set(unit, MMU_RQE_REPL_PORT_AGG_MAPr, &regval,
   6793                       L3MC_PORT_AGG_IDf, mmu_port % mmu_port_stride[unit]);
   6794         rv = soc_reg32_set(unit, MMU_RQE_REPL_PORT_AGG_MAPr, port,0,regval);
   6795     } else {
   6796         soc_reg_field_set(unit, MMU_DQS_REPL_PORT_AGG_MAPr, &regval,
   6797                       L3MC_PORT_AGG_IDf, mmu_port % mmu_port_stride[unit]);
   6798         rv = soc_reg32_set(unit, MMU_DQS_REPL_PORT_AGG_MAPr, port,0,regval);
   6799     }
   6800     if (BCM_FAILURE(rv)) {
   6801         (void)bcm_th_ipmc_repl_port_detach(unit, port);
   6802     }
   6803 
   6804     return rv;
   6805 }
   6806 
   6807 /*
   6808  * Function:
   6809  *      bcm_th_ipmc_repl_port_detach
   6810  * Purpose:
   6811  *      Clear replication per-port configuration in the runtime.
   6812  * Parameters:
   6813  *      unit - (IN) BCM device number.
   6814  *      port - local port number
   6815  * Returns:
   6816  *      BCM_E_XXX
   6817  */
   6818 int
   6819 bcm_th_ipmc_repl_port_detach(int unit, bcm_port_t port)
   6820 {
   6821     if (_th_repl_info[unit] == NULL) {
   6822         return BCM_E_INIT;
   6823     }
   6824 
   6825     if (_th_repl_info[unit]->port_info[port] != NULL) {
   6826         if (_th_repl_info[unit]->port_info[port]->intf_count != NULL) {
   6827             sal_free(_th_repl_info[unit]->port_info[port]->intf_count);
   6828             _th_repl_info[unit]->port_info[port]->intf_count = NULL;
   6829         }
   6830         sal_free(_th_repl_info[unit]->port_info[port]);
   6831         _th_repl_info[unit]->port_info[port] = NULL;
   6832     }
   6833 
   6834     if (!soc_feature(unit, soc_feature_skip_port_initial_copy_count)) {
   6835         /* Reset the BIT_WIDTHf to 0 */
   6836         SOC_IF_ERROR_RETURN
   6837             (WRITE_PORT_INITIAL_COPY_COUNT_WIDTHr(unit, port, 0));
   6838     }
   6839 
   6840     /* Reset L3MC_PORT_AGG_IDf to 0 */
   6841     if(SOC_IS_TOMAHAWK3(unit)) {
   6842         SOC_IF_ERROR_RETURN
   6843             (soc_reg32_set(unit, MMU_RQE_REPL_PORT_AGG_MAPr, port, 0, 0));
   6844 
   6845     } else {
   6846         SOC_IF_ERROR_RETURN
   6847             (soc_reg32_set(unit, MMU_DQS_REPL_PORT_AGG_MAPr, port, 0, 0));
   6848     }
   6849 
   6850 
   6851     return BCM_E_NONE;
   6852 }
   6853 
   6854 #ifdef BCM_TOMAHAWK3_SUPPORT
   6855 bcm_th3_repl_head_alloc_f bcm_th3_repl_head_alloc
   6856                                 = &_bcm_th_repl_head_block_alloc;
   6857 bcm_th3_repl_head_free_f bcm_th3_repl_head_free
   6858                                 = &_bcm_th_repl_head_block_free;
   6859 #endif
   6860 
   6861 #endif /* BCM_TOMAHAWK_SUPPORT && INCLUDE_L3 */