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

mcast.c (45087B)


      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:        mcast.c
      8  * Purpose:     Tracks and manages L2 Multicast tables.
      9  */
     10 
     11 #include <shared/bsl.h>
     12 #include <soc/drv.h>
     13 #include <soc/mem.h>
     14 #include <soc/l2x.h>
     15 #if defined(BCM_BRADLEY_SUPPORT)
     16 #include <soc/bradley.h>
     17 #endif /* BCM_BRADLEY_SUPPORT */
     18 
     19 #include <bcm/error.h>
     20 #include <bcm/l2.h>
     21 
     22 #include <bcm_int/esw/firebolt.h>
     23 #include <bcm_int/esw_dispatch.h>
     24 #include <bcm_int/esw/triumph3.h>
     25 #if defined(BCM_TRIDENT3_SUPPORT)
     26 #include <bcm_int/esw/trident3.h>
     27 #endif
     28 #include <bcm_int/common/multicast.h>
     29 
     30 typedef struct {
     31     int         size;
     32     int         *used;
     33     soc_mem_t   l2mem;
     34     soc_mem_t   mcmem;
     35 } _bcm_xgs3_mcast_t;
     36 
     37 static _bcm_xgs3_mcast_t xgs3_l2mc_info[BCM_MAX_NUM_UNITS];
     38 
     39 #define L2MC_INFO(unit)          (&xgs3_l2mc_info[unit])
     40 #define L2MC_SIZE(unit)          L2MC_INFO(unit)->size
     41 #define L2MC_USED(unit)          L2MC_INFO(unit)->used
     42 #define L2MC_L2MEM(unit)         L2MC_INFO(unit)->l2mem
     43 #define L2MC_MCMEM(unit)         L2MC_INFO(unit)->mcmem
     44 #define L2MC_USED_SET(unit, n)   L2MC_USED(unit)[n] += 1
     45 #define L2MC_USED_CLR(unit, n)   L2MC_USED(unit)[n] -= 1
     46 #define L2MC_USED_ISSET(unit, n) (L2MC_USED(unit)[n] > 0)
     47 
     48 #define L2MC_INIT(unit) \
     49         if (L2MC_USED(unit) == NULL) { return BCM_E_INIT; }
     50 #define L2MC_ID(unit, id) \
     51         if (id < 0 || id >= L2MC_SIZE(unit)) { return BCM_E_PARAM; }
     52 
     53 #define L2MC_LOCK(unit)         do {            \
     54         soc_mem_lock(unit, L2MC_MCMEM(unit));   \
     55     } while(0)
     56 #define L2MC_UNLOCK(unit)       do {            \
     57         soc_mem_unlock(unit, L2MC_MCMEM(unit)); \
     58     } while(0)
     59 #define L2MC_ID_GET(l2mc_index) \
     60     (_BCM_MULTICAST_IS_SET(l2mc_index) &&    \
     61         _BCM_MULTICAST_IS_L2(l2mc_index)) ?  \
     62             _BCM_MULTICAST_ID_GET(l2mc_index) : l2mc_index
     63 
     64 /*
     65  * Function:
     66  *	_bcm_xgs3_l2_addr_delete_mcast
     67  * Description
     68  *	Delete L2 multicast entries
     69  * Parameters:
     70  *	unit  - device unit
     71  *	flags - BCM_L2_DELETE_XXX
     72  * Returns:
     73  *	BCM_E_XXX
     74  */
     75 int
     76 _bcm_xgs3_l2_addr_delete_mcast(int unit, uint32 flags)
     77 {
     78     l2x_entry_t *l2xe, *l2xep;
     79     int		rv, chunksize, chunk, chunk_max, i;
     80     int		dyn_only, chnk_end, mem_idx_max;
     81     bcm_mac_t   mac;
     82     uint32 field_valid = INVALIDf;
     83 
     84     chunksize = soc_property_get(unit, spn_L2DELETE_CHUNKS,
     85 				 L2_MEM_CHUNKS_DEFAULT);
     86 
     87     l2xe = soc_cm_salloc(unit, chunksize * sizeof(*l2xe), "l2del_chunk");
     88     if (l2xe == NULL) {
     89 	return BCM_E_MEMORY;
     90     }
     91 
     92     rv = BCM_E_NONE;
     93 
     94     dyn_only = !(flags & BCM_L2_DELETE_STATIC);
     95 
     96     mem_idx_max = soc_mem_index_max(unit, L2Xm);
     97     for (chunk = soc_mem_index_min(unit, L2Xm); chunk <= mem_idx_max;
     98          chunk += chunksize) {
     99 
    100         chunk_max = chunk + chunksize - 1;
    101         if (chunk_max > mem_idx_max) {
    102             chunk_max = mem_idx_max;
    103         }
    104 
    105 	rv = soc_mem_read_range(unit, L2Xm, MEM_BLOCK_ANY,
    106 				chunk, chunk_max, l2xe);
    107 	if (rv < 0) {
    108 	    break;
    109 	}
    110         chnk_end = (chunk_max - chunk);
    111 	for (i = 0; i <= chnk_end; i++) {
    112 
    113 	    l2xep = soc_mem_table_idx_to_pointer(unit, L2Xm,
    114                                                  l2x_entry_t *, l2xe, i);
    115 
    116 
    117         field_valid = VALIDf;
    118         if (soc_feature(unit, soc_feature_base_valid)) {
    119             field_valid = BASE_VALIDf;
    120         }
    121         if(!soc_L2Xm_field32_get(unit, l2xep, field_valid)) {
    122             continue;
    123         }
    124 
    125         soc_L2Xm_mac_addr_get(unit, l2xep, MAC_ADDRf, mac);
    126         if (!BCM_MAC_IS_MCAST(mac)) {
    127             continue;
    128         }
    129 
    130 	    if (dyn_only &&
    131 		soc_L2Xm_field32_get(unit, l2xep, STATIC_BITf)) {
    132 		continue;
    133 	    }
    134 	    rv = soc_mem_delete(unit, L2Xm, MEM_BLOCK_ALL, l2xep);
    135 	    if (rv < 0) {
    136 	        break;
    137 	    }
    138 	}
    139 
    140 	if (rv < 0) {
    141 	    break;
    142 	}
    143     }
    144 
    145     soc_cm_sfree(unit, l2xe);
    146 
    147     return rv;
    148 }
    149 
    150 /*
    151  * Function:
    152  *      _bcm_xgs3_l2mc_size_get
    153  * Description:
    154  *      Get number of L2MC groups.
    155  */
    156 
    157 int
    158 _bcm_xgs3_l2mc_size_get(int unit, int *size)
    159 {
    160     *size = L2MC_SIZE(unit);
    161     return BCM_E_NONE;
    162 }
    163 
    164 /*
    165  * Function:
    166  *      _bcm_xgs3_l2mc_index_is_set
    167  * Description:
    168  *      Check whether and l2mc index is used.
    169  */
    170 
    171 int
    172 _bcm_xgs3_l2mc_index_is_set(int unit, int l2mc_id, int *is_set)
    173 {
    174     L2MC_ID(unit, l2mc_id);
    175 
    176     *is_set = (0 != L2MC_USED_ISSET(unit, l2mc_id));
    177 
    178     return BCM_E_NONE;
    179 }
    180 
    181 /*
    182  * Function:
    183  *      _bcm_xgs3_l2mc_free_index
    184  * Description:
    185  *      Find an unused l2mc index and mark it used.
    186  */
    187 
    188 int
    189 _bcm_xgs3_l2mc_free_index(int unit, int *l2mc_id)
    190 {
    191     int i, rv;
    192 
    193     rv = BCM_E_FULL;
    194     for (i = 1; i < L2MC_SIZE(unit); i++) {
    195         if (!L2MC_USED_ISSET(unit, i)) {
    196             L2MC_USED_SET(unit, i);
    197             *l2mc_id = i;
    198             rv = BCM_E_NONE;
    199             break;
    200         }
    201     }
    202 
    203     return rv;
    204 }
    205 
    206 /*
    207  * Function:
    208  *      _bcm_xgs3_l2mc_id_alloc
    209  * Description:
    210  *      allocate the given l2mc entry (increment use count)
    211  */
    212 
    213 int
    214 _bcm_xgs3_l2mc_id_alloc(int unit, int l2mc_id)
    215 {
    216     L2MC_ID(unit, l2mc_id);
    217 
    218     L2MC_USED_SET(unit, l2mc_id);
    219 
    220     return BCM_E_NONE;
    221 }
    222 
    223 /*
    224  * Function:
    225  *      _bcm_xgs3_l2mc_id_free
    226  * Description:
    227  *      Marks an l2mc index as free (decrements use count)
    228  */
    229 
    230 int
    231 _bcm_xgs3_l2mc_id_free(int unit, int l2mc_id)
    232 {
    233     L2MC_ID(unit, l2mc_id);
    234 
    235     L2MC_USED_CLR(unit, l2mc_id);
    236 
    237     return BCM_E_NONE;
    238 }
    239 
    240 /*
    241  * Function:
    242  *      _bcm_xgs3_mcast_from_l2
    243  * Description:
    244  *      Fill in fields of bcm_mcast_addr_t from bcm_l2_addr_t
    245  * Parameters:
    246  *      unit    - (IN) device
    247  *      mcaddr  - (OUT) mcast addr struct
    248  *      l2addr  - (IN) l2 addr struct
    249  */
    250 
    251 STATIC void
    252 _bcm_xgs3_mcast_from_l2(int unit,
    253                         bcm_mcast_addr_t *mcaddr,
    254                         bcm_l2_addr_t  *l2addr)
    255 {
    256     int         rv;
    257     vlan_tab_entry_t vte;
    258     soc_mem_t   vlan_mem;
    259 
    260     sal_memcpy(mcaddr->mac, l2addr->mac, sizeof(bcm_mac_t));
    261     mcaddr->vid = l2addr->vid;
    262     mcaddr->cos_dst = l2addr->cos_dst;
    263     mcaddr->l2mc_index = l2addr->l2mc_group;
    264 
    265     /* Need to fill in the untagged port bitmap from the VLAN table */
    266     SOC_PBMP_CLEAR(mcaddr->ubmp);
    267     vlan_mem = SOC_IS_FBX(unit) ? EGR_VLANm : VLAN_TABm;
    268     rv = soc_mem_read(unit, vlan_mem, MEM_BLOCK_ANY, mcaddr->vid, &vte);
    269     if (rv < 0) {
    270         return;
    271     }
    272 #if defined (BCM_TRIDENT3_SUPPORT)
    273     if (SOC_IS_TRIDENT3X(unit)) {
    274         (void)bcm_td3_vlan_table_ut_port_get(unit, mcaddr->vid, &mcaddr->ubmp);
    275     } else
    276 #endif
    277     {
    278         soc_mem_pbmp_field_get(unit, vlan_mem, &vte, UT_BITMAPf, &mcaddr->ubmp);
    279     }
    280 }
    281 
    282 /*
    283  * Function:
    284  *      _bcm_xgs3_mcast_to_l2
    285  * Description:
    286  *      Fill in fields of bcm_l2_addr_t from bcm_mcast_addr_t
    287  * Parameters:
    288  *      unit -  (IN) device
    289  *      l2addr - (OUT) Pointer to bcm_l2_addr_t
    290  *      mcaddr - (IN) Pointer to bcm_mcast_addr_t
    291  */
    292 
    293 STATIC void
    294 _bcm_xgs3_mcast_to_l2(int unit,
    295                       bcm_l2_addr_t *l2addr,
    296                       bcm_mcast_addr_t *mcaddr)
    297 {
    298     bcm_l2_addr_t_init(l2addr, mcaddr->mac, mcaddr->vid);
    299     l2addr->flags = BCM_L2_STATIC | BCM_L2_MCAST | BCM_L2_REPLACE_DYNAMIC;
    300     l2addr->cos_dst = mcaddr->cos_dst;
    301     l2addr->l2mc_group = mcaddr->l2mc_index;
    302 
    303 }
    304 
    305 /*
    306  * Function:
    307  *      _bcm_xgs3_mcast_create
    308  * Description:
    309  *      Create a muticast entry
    310  * Parameters:
    311  *      unit -  (IN) device
    312  *      mcaddr - (IN) Pointer to bcm_mcast_addr_t
    313  *      mcindex - (IN) mcast index to use (-1 lets routine choose)
    314  * Returns:
    315  *      BCM_E_XXX
    316  */
    317 
    318 STATIC int
    319 _bcm_xgs3_mcast_create(int unit, bcm_mcast_addr_t *mcaddr,
    320                        int mcindex)
    321 {
    322     l2mc_entry_t        l2mc, rl2mc;
    323     bcm_l2_addr_t       l2addr, rl2addr;
    324     bcm_pbmp_t          pbm, rpbm;
    325     int                 rv;
    326 
    327     bcm_l2_addr_t_init (&l2addr, mcaddr->mac, mcaddr->vid);
    328     rv = bcm_esw_l2_addr_get(unit, mcaddr->mac, mcaddr->vid, &l2addr);
    329     if (rv >= 0) {
    330         if (!(l2addr.flags & BCM_L2_MCAST)) {
    331             return BCM_E_EXISTS;
    332         }
    333         l2addr.l2mc_group = L2MC_ID_GET(l2addr.l2mc_group);
    334         if (mcindex >= 0 && mcindex == l2addr.l2mc_group) {
    335             return BCM_E_NONE;
    336         }
    337         BCM_IF_ERROR_RETURN(_bcm_xgs3_l2mc_id_free(unit, l2addr.l2mc_group));
    338 
    339     }
    340 
    341     /* Before getting free MC index, make sure this is a valid Port */
    342     rv = soc_mem_field_pbmp_fit(unit, L2MC_MCMEM(unit), PORT_BITMAPf,
    343                                (uint32 *)&mcaddr->pbmp);
    344     if (rv != SOC_E_NONE) {
    345         return rv;
    346     }
    347 
    348     if (mcindex < 0) {
    349         BCM_IF_ERROR_RETURN(_bcm_xgs3_l2mc_free_index(unit, &mcindex));
    350     } else {
    351         BCM_IF_ERROR_RETURN(_bcm_xgs3_l2mc_id_alloc(unit, mcindex));
    352     }
    353 
    354     sal_memset(&l2mc, 0, sizeof(l2mc));
    355     soc_mem_field32_set(unit, L2MC_MCMEM(unit), &l2mc, VALIDf, 1);
    356     soc_mem_pbmp_field_set(unit, L2MC_MCMEM(unit), &l2mc, PORT_BITMAPf,
    357                            &mcaddr->pbmp);
    358     _bcm_xgs3_mcast_to_l2(unit, &l2addr, mcaddr);
    359     l2addr.l2mc_group = mcindex;
    360 
    361     if (SOC_MCAST_ADD_ALL_ROUTER_PORTS(unit)) {
    362         sal_memset(&rl2addr, 0, sizeof(bcm_l2_addr_t));
    363         rv = bcm_esw_l2_addr_get(unit, (uint8 *)_soc_mac_all_routers,
    364                     mcaddr->vid, &rl2addr);
    365         if (rv >= 0) {
    366             rl2addr.l2mc_group = L2MC_ID_GET(rl2addr.l2mc_group);
    367             SOC_IF_ERROR_RETURN
    368                 (soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY,
    369                               rl2addr.l2mc_group, &rl2mc));
    370             soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &rl2mc,
    371                                    PORT_BITMAPf, &rpbm);
    372             soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &l2mc, PORT_BITMAPf,
    373                                    &pbm);
    374             BCM_PBMP_OR(pbm, rpbm);
    375             soc_mem_pbmp_field_set(unit, L2MC_MCMEM(unit), &l2mc, PORT_BITMAPf,
    376                                    &pbm);
    377         }
    378     }
    379 
    380     /* add l2mc entry */
    381     SOC_IF_ERROR_RETURN
    382         (soc_mem_write(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL, mcindex, &l2mc));
    383 
    384     /* add l2 entry */
    385     rv = bcm_esw_l2_addr_add(unit, &l2addr);
    386     if (BCM_FAILURE(rv)) {
    387         _bcm_xgs3_l2mc_id_free(unit, l2addr.l2mc_group);
    388         if (!L2MC_USED_ISSET(unit, l2addr.l2mc_group)) {
    389           soc_mem_write(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL,
    390                         l2addr.l2mc_group,
    391                         soc_mem_entry_null(unit, L2MC_MCMEM(unit)));
    392         }
    393     }
    394 
    395     return rv;
    396 }
    397 
    398 /*
    399  * Function:
    400  *      _bcm_xgs3_mcast_port_add
    401  * Purpose:
    402  *      Add new ports to a multicast entry
    403  * Parameters:
    404  *      unit    - device
    405  *      mcaddr  - mcast addr struct with new ports
    406  * Returns:
    407  *      BCM_E_XXX
    408  */
    409 
    410 STATIC int
    411 _bcm_xgs3_mcast_port_add(int unit, bcm_mcast_addr_t *mcaddr)
    412 {
    413     bcm_l2_addr_t       l2addr;
    414     l2mc_entry_t        l2mc_entry;
    415     bcm_pbmp_t          pbmp;
    416 
    417     bcm_l2_addr_t_init(&l2addr, mcaddr->mac, mcaddr->vid);
    418     BCM_IF_ERROR_RETURN
    419             (bcm_esw_l2_addr_get(unit, mcaddr->mac, mcaddr->vid, &l2addr));
    420 
    421     if (!(l2addr.flags & BCM_L2_MCAST)) {
    422         return BCM_E_NOT_FOUND;
    423     }
    424 
    425     l2addr.l2mc_group = L2MC_ID_GET(l2addr.l2mc_group);
    426 
    427     SOC_IF_ERROR_RETURN
    428         (soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY,
    429                       l2addr.l2mc_group, &l2mc_entry));
    430 
    431     soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf,
    432                            &pbmp);
    433     BCM_PBMP_OR(pbmp, mcaddr->pbmp);
    434     soc_mem_pbmp_field_set(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf,
    435                            &pbmp);
    436 
    437     SOC_IF_ERROR_RETURN
    438         (soc_mem_write(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL,
    439                        l2addr.l2mc_group, &l2mc_entry));
    440 
    441     return BCM_E_NONE;
    442 }
    443 
    444 /*
    445  * Function:
    446  *      _bcm_xgs3_mcast_port_delete
    447  * Purpose:
    448  *      Remove ports from a multicast entry
    449  * Parameters:
    450  *      unit    - device
    451  *      mcaddr  - mcast addr struct with ports to delete
    452  * Returns:
    453  *      BCM_E_XXX
    454  */
    455 
    456 STATIC int
    457 _bcm_xgs3_mcast_port_delete(int unit,
    458                             bcm_mcast_addr_t *mcaddr)
    459 {
    460     bcm_l2_addr_t       l2addr;
    461     l2mc_entry_t        l2mc_entry;
    462     bcm_pbmp_t          pbmp;
    463 
    464     bcm_l2_addr_t_init (&l2addr, mcaddr->mac, mcaddr->vid);
    465     BCM_IF_ERROR_RETURN
    466             (bcm_esw_l2_addr_get(unit, mcaddr->mac, mcaddr->vid, &l2addr));
    467 
    468     if (!(l2addr.flags & BCM_L2_MCAST)) {
    469         return BCM_E_NOT_FOUND;
    470     }
    471 
    472     l2addr.l2mc_group = L2MC_ID_GET(l2addr.l2mc_group);
    473 
    474     SOC_IF_ERROR_RETURN
    475         (soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY,
    476                       l2addr.l2mc_group, &l2mc_entry));
    477 
    478     soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf,
    479                            &pbmp);
    480     BCM_PBMP_REMOVE(pbmp, mcaddr->pbmp);
    481     soc_mem_pbmp_field_set(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf,
    482                            &pbmp);
    483 
    484     SOC_IF_ERROR_RETURN
    485         (soc_mem_write(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL,
    486                        l2addr.l2mc_group, &l2mc_entry));
    487 
    488     return BCM_E_NONE;
    489 }
    490 
    491 /*
    492  * Function:
    493  *      bcm_xgs3_mcast_port_remove
    494  * Purpose:
    495  *      Remove ports from existing MC entry.
    496  * Returns:
    497  *      BCM_E_XXX
    498  */
    499 
    500 int
    501 bcm_xgs3_mcast_port_remove(int unit, bcm_mcast_addr_t *mcaddr)
    502 {
    503     int rv;
    504 
    505     L2MC_INIT(unit);
    506     L2MC_LOCK(unit);
    507     rv = _bcm_xgs3_mcast_port_delete(unit, mcaddr);
    508     L2MC_UNLOCK(unit);
    509     return rv;
    510 }
    511 
    512 /*
    513  * Function:
    514  *      bcm_xgs3_mcast_port_add
    515  * Purpose:
    516  *      Add ports to existing MC entry.
    517  * Returns:
    518  *      BCM_E_XXX
    519  */
    520 
    521 int
    522 bcm_xgs3_mcast_port_add(int unit, bcm_mcast_addr_t *mcaddr)
    523 {
    524     int rv;
    525 
    526     L2MC_INIT(unit);
    527     L2MC_LOCK(unit);
    528     rv = _bcm_xgs3_mcast_port_add(unit, mcaddr);
    529     L2MC_UNLOCK(unit);
    530     return rv;
    531 }
    532 
    533 /*
    534  * Function:
    535  *      bcm_xgs3_mcast_addr_add_w_l2mcindex
    536  * Purpose:
    537  *      Add a new MC entry to the L2 and L2MC tables, with given MC index.
    538  * Returns:
    539  *      BCM_E_XXX
    540  */
    541 
    542 int
    543 bcm_xgs3_mcast_addr_add_w_l2mcindex(int unit, bcm_mcast_addr_t *mcaddr)
    544 {
    545     int rv;
    546 
    547     L2MC_INIT(unit);
    548     L2MC_LOCK(unit);
    549     rv = _bcm_xgs3_mcast_create(unit, mcaddr, mcaddr->l2mc_index);
    550     L2MC_UNLOCK(unit);
    551     return rv;
    552 }
    553 
    554 /*
    555  * Function:
    556  *      bcm_xgs3_mcast_addr_add
    557  * Purpose:
    558  *      Add new L2 multicast entry
    559  * Returns:
    560  *      BCM_E_XXX
    561  */
    562 
    563 int
    564 bcm_xgs3_mcast_addr_add(int unit, bcm_mcast_addr_t *mcaddr)
    565 {
    566     int rv;
    567 
    568     L2MC_INIT(unit);
    569     L2MC_LOCK(unit);
    570     /*    coverity[negative_returns : FALSE]    */
    571     rv = _bcm_xgs3_mcast_create(unit, mcaddr, -1);
    572     L2MC_UNLOCK(unit);
    573     return rv;
    574 }
    575 
    576 /*
    577  * Function:
    578  *      bcm_xgs3_mcast_addr_remove
    579  * Purpose:
    580  *      Remove a multicast entry
    581  * Returns:
    582  *      BCM_E_XXX
    583  */
    584 
    585 int
    586 bcm_xgs3_mcast_addr_remove(int unit, sal_mac_addr_t mac, bcm_vlan_t vid)
    587 {
    588     int                 rv;
    589     bcm_l2_addr_t       l2addr;
    590 
    591     L2MC_INIT(unit);
    592     L2MC_LOCK(unit);
    593 
    594     bcm_l2_addr_t_init (&l2addr, mac, vid);
    595     rv = bcm_esw_l2_addr_get(unit, mac, vid, &l2addr);
    596     if (rv < 0) {
    597         L2MC_UNLOCK(unit);
    598         return rv;
    599     }
    600 
    601     if (!(l2addr.flags & BCM_L2_MCAST)) {
    602         L2MC_UNLOCK(unit);
    603         return BCM_E_NOT_FOUND;
    604     }
    605 
    606     rv = bcm_esw_l2_addr_delete(unit, mac, vid);
    607     if (rv < 0) {
    608         L2MC_UNLOCK(unit);
    609         return rv;
    610     }
    611 
    612     /* Check added to avoid Segmentation fault in regression tests */
    613     /* Sometimes l2mc_index may not have a multicast type set when switchcontrol L2McIdxRetType is set to 0*/
    614     if (_BCM_MULTICAST_IS_L2(l2addr.l2mc_group) || 
    615         !_BCM_MULTICAST_IS_SET(l2addr.l2mc_group)) {
    616          l2addr.l2mc_group = L2MC_ID_GET(l2addr.l2mc_group);
    617          _bcm_xgs3_l2mc_id_free(unit, l2addr.l2mc_group);
    618 
    619          if (!L2MC_USED_ISSET(unit, l2addr.l2mc_group)) {
    620               rv = soc_mem_write(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL,
    621                        l2addr.l2mc_group,
    622                        soc_mem_entry_null(unit, L2MC_MCMEM(unit)));
    623          }
    624     }
    625 
    626     L2MC_UNLOCK(unit);
    627     return rv;
    628 }
    629 
    630 /*
    631  * Function:
    632  *      bcm_fb_mcast_addr_remove_w_l2mcindex
    633  * Purpose:
    634  *      Remove a multicast entry with l2mc index provided
    635  * Returns:
    636  *      BCM_E_XXX
    637  */
    638 
    639 int
    640 bcm_xgs3_mcast_addr_remove_w_l2mcindex(int unit,
    641                                         bcm_mcast_addr_t *mcaddr)
    642 {
    643     return bcm_xgs3_mcast_addr_remove(unit, mcaddr->mac, mcaddr->vid);
    644 }
    645 
    646 /*
    647  * Function:
    648  *      _bcm_xgs3_mcast_index_port_get
    649  * Purpose:
    650  *      Get port bit maps for a multicast group by index.
    651  * Returns:
    652  *      BCM_E_XXX
    653  */
    654 
    655 int
    656 _bcm_xgs3_mcast_index_port_get(int unit, int l2mc_index, 
    657                               bcm_mcast_addr_t *mcaddr)
    658 {
    659     l2mc_entry_t      l2mc_entry;
    660     
    661     L2MC_INIT(unit);
    662 
    663     SOC_IF_ERROR_RETURN
    664         (soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY,
    665                       L2MC_ID_GET(l2mc_index), &l2mc_entry));
    666 
    667     soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf,
    668                            &mcaddr->pbmp);
    669 
    670     return BCM_E_NONE;
    671 }
    672 
    673 
    674 /*
    675  * Function:
    676  *      bcm_xgs3_mcast_port_get
    677  * Purpose:
    678  *      Get port bit maps for a multicast group.
    679  * Returns:
    680  *      BCM_E_XXX
    681  */
    682 
    683 int
    684 bcm_xgs3_mcast_port_get(int unit,
    685                          sal_mac_addr_t mac, bcm_vlan_t vid,
    686                          bcm_mcast_addr_t *mcaddr)
    687 {
    688     l2mc_entry_t      l2mc_entry;
    689     bcm_l2_addr_t     l2addr;
    690 
    691     L2MC_INIT(unit);
    692 
    693     bcm_l2_addr_t_init (&l2addr, mac, vid);
    694     BCM_IF_ERROR_RETURN(bcm_esw_l2_addr_get(unit, mac, vid, &l2addr));
    695 
    696     l2addr.l2mc_group = L2MC_ID_GET(l2addr.l2mc_group);
    697     SOC_IF_ERROR_RETURN
    698         (soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY,
    699                       l2addr.l2mc_group, &l2mc_entry));
    700 
    701     _bcm_xgs3_mcast_from_l2(unit, mcaddr, &l2addr);
    702     soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf,
    703                            &mcaddr->pbmp);
    704 
    705     return BCM_E_NONE;
    706 }
    707 
    708 #ifdef BCM_WARM_BOOT_SUPPORT
    709 #ifdef BCM_TRIUMPH3_SUPPORT
    710 /*
    711  * Function:
    712  *      _bcm_tr3_mcast_l2_table_recover
    713  * Purpose:
    714  *      Recover L2MC group usage from L2 table.
    715  * Returns:
    716  *      BCM_E_XXX 
    717  */
    718 STATIC int
    719 _bcm_tr3_mcast_l2_table_recover(int unit)
    720 {
    721     int             rv = BCM_E_NONE;
    722     int             buf_size, chunksize;
    723     uint32          *l2_tbl_chnk;
    724     soc_mem_t       mem;
    725     int             chnk_idx, chnk_idx_max, mem_idx_max;
    726     int             chnk_end, ent_idx;
    727     uint32          *l2_entry;
    728     int             key_type;
    729     bcm_mac_t       mac_addr;
    730     int             l2mc_idx;
    731     l2mc_entry_t    mc_entry;
    732 
    733     chunksize = soc_property_get(unit, spn_L2DELETE_CHUNKS,
    734             L2_MEM_CHUNKS_DEFAULT);
    735     buf_size = 4 * SOC_MAX_MEM_FIELD_WORDS * chunksize;
    736     l2_tbl_chnk = soc_cm_salloc(unit, buf_size, "l2 mcast delete");
    737     if (NULL == l2_tbl_chnk) {
    738         return BCM_E_MEMORY;
    739     }
    740 
    741     /* First work on L2_ENTRY_1 */
    742 
    743     mem = L2_ENTRY_1m;
    744     mem_idx_max = soc_mem_index_max(unit, mem);
    745     for (chnk_idx = soc_mem_index_min(unit, mem); 
    746             chnk_idx <= mem_idx_max; 
    747             chnk_idx += chunksize) {
    748 
    749         sal_memset((void *)l2_tbl_chnk, 0, buf_size);
    750         chnk_idx_max = ((chnk_idx + chunksize) <= mem_idx_max) ? 
    751             (chnk_idx + chunksize - 1) : mem_idx_max;
    752         rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY,
    753                 chnk_idx, chnk_idx_max, l2_tbl_chnk);
    754         if (BCM_FAILURE(rv)) {
    755             break;
    756         }
    757 
    758         chnk_end = (chnk_idx_max - chnk_idx);
    759         for (ent_idx = 0 ; ent_idx <= chnk_end; ent_idx++) {
    760             l2_entry = soc_mem_table_idx_to_pointer(unit, mem, uint32 *, 
    761                     l2_tbl_chnk, ent_idx);
    762 
    763             if (!soc_mem_field32_get(unit, mem, l2_entry, VALIDf)) {
    764                 continue;
    765             }
    766 
    767             key_type = soc_mem_field32_get(unit, mem, l2_entry, KEY_TYPEf);
    768             if (SOC_MEM_KEY_L2_ENTRY_1_L2_BRIDGE != key_type) {
    769                 continue;
    770             }
    771 
    772             soc_mem_mac_addr_get(unit, mem, l2_entry, L2__MAC_ADDRf, mac_addr);
    773             if (!BCM_MAC_IS_MCAST(mac_addr)) {
    774                 continue;
    775             }
    776 
    777             l2mc_idx = soc_mem_field32_get(unit, mem, l2_entry, L2__L2MC_PTRf);
    778             rv = soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, l2mc_idx,
    779                     &mc_entry);
    780             if (BCM_FAILURE(rv)) {
    781                 break;
    782             }
    783             if (soc_mem_field32_get(unit, L2MC_MCMEM(unit), &mc_entry,
    784                         VALIDf)) {
    785                 L2MC_USED_SET(unit, l2mc_idx);
    786             }
    787         }
    788     }
    789 
    790     if (BCM_FAILURE(rv)) {
    791         sal_free(L2MC_USED(unit));
    792         soc_cm_sfree(unit, l2_tbl_chnk);
    793         return rv;  
    794     }
    795 
    796     /* Then work on L2_ENTRY_2 */
    797 
    798     mem = L2_ENTRY_2m;
    799     mem_idx_max = soc_mem_index_max(unit, mem);
    800     for (chnk_idx = soc_mem_index_min(unit, mem); 
    801             chnk_idx <= mem_idx_max; 
    802             chnk_idx += chunksize) {
    803 
    804         sal_memset((void *)l2_tbl_chnk, 0, buf_size);
    805         chnk_idx_max = ((chnk_idx + chunksize) <= mem_idx_max) ? 
    806             (chnk_idx + chunksize - 1) : mem_idx_max;
    807         rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY,
    808                 chnk_idx, chnk_idx_max, l2_tbl_chnk);
    809         if (BCM_FAILURE(rv)) {
    810             break;
    811         }
    812 
    813         chnk_end = (chnk_idx_max - chnk_idx);
    814         for (ent_idx = 0 ; ent_idx <= chnk_end; ent_idx++) {
    815             l2_entry = soc_mem_table_idx_to_pointer(unit, mem, uint32 *, 
    816                     l2_tbl_chnk, ent_idx);
    817 
    818             if (!soc_mem_field32_get(unit, mem, l2_entry, VALID_0f)) {
    819                 continue;
    820             }
    821             if (!soc_mem_field32_get(unit, mem, l2_entry, VALID_1f)) {
    822                 continue;
    823             }
    824 
    825             key_type = soc_mem_field32_get(unit, mem, l2_entry,
    826                     KEY_TYPE_0f);
    827             if (SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE != key_type) {
    828                 continue;
    829             }
    830 
    831             soc_mem_mac_addr_get(unit, mem, l2_entry, L2__MAC_ADDRf, mac_addr);
    832             if (!BCM_MAC_IS_MCAST(mac_addr)) {
    833                 continue;
    834             }
    835 
    836             l2mc_idx = soc_mem_field32_get(unit, mem, l2_entry, L2__L2MC_PTRf);
    837             rv = soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, l2mc_idx,
    838                     &mc_entry);
    839             if (BCM_FAILURE(rv)) {
    840                 break;
    841             }
    842             if (soc_mem_field32_get(unit, L2MC_MCMEM(unit), &mc_entry,
    843                         VALIDf)) {
    844                 L2MC_USED_SET(unit, l2mc_idx);
    845             }
    846         }
    847     }
    848 
    849     if (BCM_FAILURE(rv)) {
    850         sal_free(L2MC_USED(unit));
    851         soc_cm_sfree(unit, l2_tbl_chnk);
    852         return rv;  
    853     }
    854 
    855     /* Next work on EXT_L2_ENTRY_1 */
    856 
    857     if (!soc_feature(unit, soc_feature_esm_support)) {
    858         return BCM_E_NONE;
    859     }
    860 
    861     mem = EXT_L2_ENTRY_1m;
    862     mem_idx_max = soc_mem_index_max(unit, mem);
    863     for (chnk_idx = soc_mem_index_min(unit, mem); 
    864             chnk_idx <= mem_idx_max; 
    865             chnk_idx += chunksize) {
    866 
    867         sal_memset((void *)l2_tbl_chnk, 0, buf_size);
    868         chnk_idx_max = ((chnk_idx + chunksize) <= mem_idx_max) ? 
    869             (chnk_idx + chunksize - 1) : mem_idx_max;
    870         rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY,
    871                 chnk_idx, chnk_idx_max, l2_tbl_chnk);
    872         if (BCM_FAILURE(rv)) {
    873             break;
    874         }
    875 
    876         chnk_end = (chnk_idx_max - chnk_idx);
    877         for (ent_idx = 0 ; ent_idx <= chnk_end; ent_idx++) {
    878             l2_entry = soc_mem_table_idx_to_pointer(unit, mem, uint32 *, 
    879                     l2_tbl_chnk, ent_idx);
    880 
    881             if (soc_mem_field32_get(unit, mem, l2_entry, FREEf)) {
    882                 continue;
    883             }
    884 
    885             key_type = soc_mem_field32_get(unit, mem, l2_entry,
    886                     KEY_TYPEf);
    887             if (0 != key_type) {
    888                 continue;
    889             }
    890 
    891             soc_mem_mac_addr_get(unit, mem, l2_entry, MAC_ADDRf, mac_addr);
    892             if (!BCM_MAC_IS_MCAST(mac_addr)) {
    893                 continue;
    894             }
    895 
    896             l2mc_idx = soc_mem_field32_get(unit, mem, l2_entry, DESTINATIONf);
    897             rv = soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, l2mc_idx,
    898                     &mc_entry);
    899             if (BCM_FAILURE(rv)) {
    900                 break;
    901             }
    902             if (soc_mem_field32_get(unit, L2MC_MCMEM(unit), &mc_entry,
    903                         VALIDf)) {
    904                 L2MC_USED_SET(unit, l2mc_idx);
    905             }
    906         }
    907     }
    908 
    909     if (BCM_FAILURE(rv)) {
    910         sal_free(L2MC_USED(unit));
    911         soc_cm_sfree(unit, l2_tbl_chnk);
    912         return rv;  
    913     }
    914 
    915     /* Finally work on EXT_L2_ENTRY_2 */
    916 
    917     mem = EXT_L2_ENTRY_2m;
    918     mem_idx_max = soc_mem_index_max(unit, mem);
    919     for (chnk_idx = soc_mem_index_min(unit, mem); 
    920             chnk_idx <= mem_idx_max; 
    921             chnk_idx += chunksize) {
    922 
    923         sal_memset((void *)l2_tbl_chnk, 0, buf_size);
    924         chnk_idx_max = ((chnk_idx + chunksize) <= mem_idx_max) ? 
    925             (chnk_idx + chunksize - 1) : mem_idx_max;
    926         rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY,
    927                 chnk_idx, chnk_idx_max, l2_tbl_chnk);
    928         if (BCM_FAILURE(rv)) {
    929             break;
    930         }
    931 
    932         chnk_end = (chnk_idx_max - chnk_idx);
    933         for (ent_idx = 0 ; ent_idx <= chnk_end; ent_idx++) {
    934             l2_entry = soc_mem_table_idx_to_pointer(unit, mem, uint32 *, 
    935                     l2_tbl_chnk, ent_idx);
    936 
    937             if (soc_mem_field32_get(unit, mem, l2_entry, FREEf)) {
    938                 continue;
    939             }
    940 
    941             key_type = soc_mem_field32_get(unit, mem, l2_entry,
    942                     KEY_TYPEf);
    943             if (0 != key_type) {
    944                 continue;
    945             }
    946 
    947             soc_mem_mac_addr_get(unit, mem, l2_entry, MAC_ADDRf, mac_addr);
    948             if (!BCM_MAC_IS_MCAST(mac_addr)) {
    949                 continue;
    950             }
    951 
    952             l2mc_idx = soc_mem_field32_get(unit, mem, l2_entry, DESTINATIONf);
    953             rv = soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY, l2mc_idx,
    954                     &mc_entry);
    955             if (BCM_FAILURE(rv)) {
    956                 break;
    957             }
    958             if (soc_mem_field32_get(unit, L2MC_MCMEM(unit), &mc_entry,
    959                         VALIDf)) {
    960                 L2MC_USED_SET(unit, l2mc_idx);
    961             }
    962         }
    963     }
    964 
    965     if (BCM_FAILURE(rv)) {
    966         sal_free(L2MC_USED(unit));
    967     }
    968 
    969     soc_cm_sfree(unit, l2_tbl_chnk);
    970     return rv;        
    971 }
    972 #endif /* BCM_TRIUMPH3_SUPPORT */
    973 #endif /* BCM_WARM_BOOT_SUPPORT */
    974 
    975 /*
    976  * Function:
    977  *      _bcm_xgs3_mcast_detach
    978  * Purpose:
    979  *      De-initialize multicast api components
    980  * Returns:
    981  *      BCM_E_XXX 
    982  */
    983 int
    984 _bcm_xgs3_mcast_detach(int unit)
    985 {
    986     if (L2MC_USED(unit) != NULL) {
    987         sal_free(L2MC_USED(unit));
    988         L2MC_USED(unit) = NULL;
    989     }
    990     L2MC_SIZE(unit) = 0;
    991     L2MC_L2MEM(unit) = INVALIDm;
    992     L2MC_MCMEM(unit) = INVALIDm;
    993 
    994     return (BCM_E_NONE);
    995 }
    996 
    997 /*
    998  * Function:
    999  *      bcm_xgs3_l2_addr_mcast_delete_all 
   1000  * Purpose:
   1001  *      Delete multicast address entries in l2 table
   1002  * Returns:
   1003  *      BCM_E_XXX 
   1004  */
   1005 int
   1006 bcm_xgs3_l2_addr_mcast_delete_all(int unit)
   1007 {
   1008     /* Delete all multicast entries from L2 */
   1009     if (!SAL_BOOT_QUICKTURN && !SAL_BOOT_BCMSIM && !SAL_BOOT_XGSSIM) {
   1010 #ifdef BCM_TRIDENT_SUPPORT
   1011         if (soc_feature(unit, soc_feature_l2_bulk_control) &&
   1012                 !SAL_BOOT_PLISIM) {
   1013 #ifdef BCM_TRIUMPH3_SUPPORT
   1014             if (soc_feature(unit, soc_feature_ism_memory)) {
   1015                 BCM_IF_ERROR_RETURN
   1016                     (bcm_tr3_l2_addr_delete_mcast(unit, TRUE));
   1017             } else
   1018 #endif /* BCM_TRIUMPH3_SUPPORT */
   1019 #ifdef BCM_TOMAHAWK_SUPPORT
   1020             if (soc_feature(unit, soc_feature_l2_bulk_unified_table)) {
   1021                 l2_bulk_entry_t match_mask;
   1022                 l2_bulk_entry_t match_data;
   1023                 bcm_mac_t mac_mask;
   1024                 int field_len;
   1025 
   1026                 BCM_IF_ERROR_RETURN
   1027                     (soc_reg_field32_modify(unit, L2_BULK_CONTROLr,
   1028                                             REG_PORT_ANY, ACTIONf, 1));
   1029                 BCM_IF_ERROR_RETURN
   1030                     (soc_reg_field32_modify(unit, L2_BULK_CONTROLr,
   1031                                             REG_PORT_ANY, NUM_ENTRIESf,
   1032                                             soc_mem_index_count(unit, L2Xm)));
   1033 
   1034                 sal_memset(&match_mask, 0, sizeof(match_mask));
   1035                 sal_memset(&match_data, 0, sizeof(match_data));
   1036 
   1037                 if (soc_feature(unit, soc_feature_base_valid)) {
   1038                     soc_mem_field32_set(unit, L2_BULKm, &match_mask,
   1039                                         BASE_VALIDf, 1);
   1040                     soc_mem_field32_set(unit, L2_BULKm, &match_data,
   1041                                         BASE_VALIDf, 1);
   1042                 } else {
   1043                     soc_mem_field32_set(unit, L2_BULKm, &match_mask,
   1044                                         VALIDf, 1);
   1045                     soc_mem_field32_set(unit, L2_BULKm, &match_data,
   1046                                         VALIDf, 1);
   1047                 }
   1048 
   1049                 field_len = soc_mem_field_length(unit, L2_BULKm,
   1050                                                  KEY_TYPEf);
   1051                 soc_mem_field32_set(unit, L2_BULKm, &match_mask,
   1052                                     KEY_TYPEf, (1 << field_len) - 1);
   1053                 /* KEY_TYPE field in data is 0 */
   1054 
   1055                 sal_memset(&mac_mask, 0, sizeof(mac_mask));
   1056                 mac_mask[0] = 1; /* bit 40 */
   1057                 soc_mem_mac_addr_set(unit, L2_BULKm, &match_mask,
   1058                                      MAC_ADDRf, mac_mask);
   1059                 soc_mem_mac_addr_set(unit, L2_BULKm, &match_data,
   1060                                      MAC_ADDRf, mac_mask);
   1061 
   1062                 BCM_IF_ERROR_RETURN
   1063                     (WRITE_L2_BULKm(unit, MEM_BLOCK_ALL, 1,
   1064                                                &match_mask));
   1065                 BCM_IF_ERROR_RETURN
   1066                     (WRITE_L2_BULKm(unit, MEM_BLOCK_ALL, 0,
   1067                                                &match_data));
   1068                 if (!SAL_BOOT_BCMSIM) {
   1069                     BCM_IF_ERROR_RETURN
   1070                         (soc_l2x_port_age(unit, L2_BULK_CONTROLr, INVALIDr));
   1071                 }
   1072             } else
   1073 #endif /* BCM_TOMAHAWK_SUPPORT */
   1074             {
   1075                 l2_bulk_match_mask_entry_t match_mask;
   1076                 l2_bulk_match_data_entry_t match_data;
   1077                 bcm_mac_t mac_mask;
   1078                 int field_len;
   1079 
   1080                 BCM_IF_ERROR_RETURN
   1081                     (soc_reg_field32_modify(unit, L2_BULK_CONTROLr,
   1082                                             REG_PORT_ANY, ACTIONf, 1));
   1083 
   1084                 sal_memset(&match_mask, 0, sizeof(match_mask));
   1085                 sal_memset(&match_data, 0, sizeof(match_data));
   1086 
   1087                 soc_mem_field32_set(unit, L2_BULK_MATCH_MASKm, &match_mask,
   1088                                     VALIDf, 1);
   1089                 soc_mem_field32_set(unit, L2_BULK_MATCH_DATAm, &match_data,
   1090                                     VALIDf, 1);
   1091 
   1092                 field_len = soc_mem_field_length(unit, L2_BULK_MATCH_MASKm,
   1093                                                  KEY_TYPEf);
   1094                 soc_mem_field32_set(unit, L2_BULK_MATCH_MASKm, &match_mask,
   1095                                     KEY_TYPEf, (1 << field_len) - 1);
   1096                 /* KEY_TYPE field in data is 0 */
   1097 
   1098                 sal_memset(&mac_mask, 0, sizeof(mac_mask));
   1099                 mac_mask[0] = 1; /* bit 40 */
   1100                 soc_mem_mac_addr_set(unit, L2_BULK_MATCH_MASKm, &match_mask,
   1101                                      MAC_ADDRf, mac_mask);
   1102                 soc_mem_mac_addr_set(unit, L2_BULK_MATCH_DATAm, &match_data,
   1103                                      MAC_ADDRf, mac_mask);
   1104 
   1105                 BCM_IF_ERROR_RETURN
   1106                     (WRITE_L2_BULK_MATCH_MASKm(unit, MEM_BLOCK_ALL, 0,
   1107                                                &match_mask));
   1108                 BCM_IF_ERROR_RETURN
   1109                     (WRITE_L2_BULK_MATCH_DATAm(unit, MEM_BLOCK_ALL, 0,
   1110                                                &match_data));
   1111                 if (!SAL_BOOT_BCMSIM) {
   1112                     BCM_IF_ERROR_RETURN
   1113                         (soc_l2x_port_age(unit, L2_BULK_CONTROLr, INVALIDr));
   1114                 }
   1115             }
   1116         } else
   1117 #endif /* BCM_TRIDENT_SUPPORT */
   1118         {
   1119 #ifdef BCM_TRIUMPH3_SUPPORT
   1120             if (soc_feature(unit, soc_feature_ism_memory)) {
   1121                 if (!SAL_BOOT_PLISIM) {
   1122                     BCM_IF_ERROR_RETURN
   1123                         (bcm_tr3_l2_addr_delete_mcast(unit, FALSE));
   1124                 }
   1125             } else
   1126 #endif /* BCM_TRIUMPH3_SUPPORT */
   1127             {
   1128                 if (!SAL_BOOT_BCMSIM) {
   1129                 BCM_IF_ERROR_RETURN
   1130                     (_bcm_xgs3_l2_addr_delete_mcast(unit, BCM_L2_DELETE_STATIC));
   1131                 }
   1132             }
   1133         }
   1134     }
   1135 
   1136     return BCM_E_NONE;    
   1137 }
   1138 
   1139 /*
   1140  * Function:
   1141  *      bcm_xgs3_mcast_init
   1142  * Purpose:
   1143  *      Initialize multicast api components
   1144  * Returns:
   1145  *      BCM_E_XXX on error
   1146  *      number of mcast entries supported on success
   1147  */
   1148 
   1149 int
   1150 bcm_xgs3_mcast_init(int unit)
   1151 {
   1152     if (L2MC_USED(unit) != NULL) {
   1153         sal_free(L2MC_USED(unit));
   1154     }
   1155     L2MC_SIZE(unit) = 0;
   1156 
   1157     L2MC_L2MEM(unit) = soc_feature(unit, soc_feature_ism_memory) ?
   1158         L2_ENTRY_1m: L2Xm;
   1159     L2MC_MCMEM(unit) = L2MCm;
   1160 #if defined(BCM_BRADLEY_SUPPORT) || defined(BCM_TRX_SUPPORT)
   1161     if (SOC_IS_HBX(unit) || SOC_IS_TRX(unit)) {
   1162         int mc_base, mc_size;
   1163         
   1164 #ifdef BCM_WARM_BOOT_SUPPORT
   1165         if (SOC_WARM_BOOT(unit)) {
   1166             uint32 mc_ctrl;
   1167             soc_control_t       *soc = SOC_CONTROL(unit);
   1168 
   1169             /* Recover the mcast size settings */
   1170             if (soc_feature(unit, soc_feature_higig2)) {
   1171                 SOC_IF_ERROR_RETURN
   1172                     (READ_MC_CONTROL_1r(unit, &mc_ctrl));
   1173                 soc->higig2_bcast_size =
   1174                     soc_reg_field_get(unit, MC_CONTROL_1r, mc_ctrl,
   1175                                       HIGIG2_BC_SIZEf);
   1176 
   1177                 SOC_IF_ERROR_RETURN
   1178                     (READ_MC_CONTROL_2r(unit, &mc_ctrl));
   1179                 soc->higig2_mcast_size =
   1180                     soc_reg_field_get(unit, MC_CONTROL_2r, mc_ctrl,
   1181                                       HIGIG2_L2MC_SIZEf);
   1182 
   1183                 SOC_IF_ERROR_RETURN
   1184                     (READ_MC_CONTROL_3r(unit, &mc_ctrl));
   1185                 soc->higig2_ipmc_size =
   1186                     soc_reg_field_get(unit, MC_CONTROL_3r, mc_ctrl,
   1187                                       HIGIG2_IPMC_SIZEf);
   1188             }
   1189 
   1190             if (!SOC_IS_MONTEREY(unit)) {
   1191                 if (SOC_REG_FIELD_VALID(unit, MC_CONTROL_5r,
   1192                                         SHARED_TABLE_L2MC_SIZEf) &&
   1193                     SOC_REG_FIELD_VALID(unit, MC_CONTROL_5r,
   1194                                         SHARED_TABLE_IPMC_SIZEf)) {
   1195                     SOC_IF_ERROR_RETURN
   1196                         (READ_MC_CONTROL_5r(unit, &mc_ctrl));
   1197                     soc->mcast_size =
   1198                         soc_reg_field_get(unit, MC_CONTROL_5r, mc_ctrl,
   1199                                           SHARED_TABLE_L2MC_SIZEf);
   1200                     soc->ipmc_size =
   1201                         soc_reg_field_get(unit, MC_CONTROL_5r, mc_ctrl,
   1202                                           SHARED_TABLE_IPMC_SIZEf);
   1203                 }
   1204             }
   1205 
   1206         }
   1207 #endif /* BCM_WARM_BOOT_SUPPORT */
   1208 
   1209         SOC_IF_ERROR_RETURN
   1210             (soc_hbx_mcast_size_get(unit, &mc_base, &mc_size));
   1211 
   1212         L2MC_SIZE(unit) = mc_size;
   1213     }
   1214 #endif
   1215 
   1216     if (L2MC_SIZE(unit) <= 0) {
   1217         L2MC_SIZE(unit) = soc_mem_index_count(unit, L2MC_MCMEM(unit));
   1218     }
   1219 
   1220     L2MC_USED(unit) = sal_alloc(sizeof(int) * L2MC_SIZE(unit), "L2MC");
   1221     if (L2MC_USED(unit) == NULL) {
   1222         return BCM_E_MEMORY;
   1223     }
   1224     sal_memset(L2MC_USED(unit), 0, sizeof(int) * L2MC_SIZE(unit));
   1225 
   1226 #ifdef BCM_WARM_BOOT_SUPPORT
   1227     if (SOC_WARM_BOOT(unit)) {
   1228         l2x_entry_t  *l2_entry, *l2_table;
   1229         l2mc_entry_t *l2mc_entry, *l2mc_table;
   1230         int index, index_min, index_max, l2mc_tbl_sz, l2_tbl_sz;
   1231         sal_mac_addr_t mcmac;
   1232 
   1233         /*
   1234          * Go through L2 table to get MC use counts
   1235          */
   1236 #ifdef BCM_TRIUMPH3_SUPPORT
   1237         if (soc_feature(unit, soc_feature_ism_memory)) {
   1238             _bcm_tr3_mcast_l2_table_recover(unit);
   1239         } else
   1240 #endif /* BCM_TRIUMPH3_SUPPORT */
   1241         {
   1242             int iter, dma_iter = 1;
   1243 #ifdef BCM_TRIDENT2PLUS_SUPPORT
   1244             int index_half = 0;
   1245 #endif /* BCM_TRIDENT2PLUS_SUPPORT */
   1246             index_min = soc_mem_index_min(unit, L2MC_L2MEM(unit));
   1247             index_max = soc_mem_index_max(unit, L2MC_L2MEM(unit));
   1248             l2_tbl_sz = sizeof(l2x_entry_t) * (index_max - index_min + 1);
   1249 
   1250 #ifdef BCM_TRIDENT2PLUS_SUPPORT
   1251             if (SOC_IS_TRIDENT2PLUS(unit)) {
   1252                 /* Trident2 has a Max L2_ENTRY Table Size of 294911 and TD2Plus
   1253                  * has double the entries, So for the DMA allocation to succeed
   1254                  * we are reading the L2_Entries in 2 chuncks for TD2Plus.
   1255                  */
   1256                 if ((index_max - index_min) > 294911) {
   1257                     dma_iter = 2;
   1258                     index_half = (index_max - index_min) / 2;
   1259                     l2_tbl_sz = sizeof(l2x_entry_t) *  (index_half + 1);
   1260                 }
   1261             }
   1262 #endif /* BCM_TRIDENT2PLUS_SUPPORT */
   1263 
   1264             for (iter = 0; iter < dma_iter; iter++) {
   1265  #ifdef BCM_TRIDENT2PLUS_SUPPORT
   1266                 if (SOC_IS_TRIDENT2PLUS(unit)) {
   1267                     if (dma_iter == 2) {
   1268                         if(iter == 0) {
   1269                             index_max = index_half;
   1270                         } else if (iter == 1) {
   1271                             index_min = index_half + 1;
   1272                             index_max = soc_mem_index_max(unit,
   1273                                                           L2MC_L2MEM(unit));
   1274                         }
   1275                     } 
   1276                 }
   1277 #endif /* BCM_TRIDENT2PLUS_SUPPORT */
   1278                 l2_table = soc_cm_salloc(unit, l2_tbl_sz, "l2 tbl dma");
   1279                 if (l2_table == NULL) {
   1280                     sal_free(L2MC_USED(unit));
   1281                     return BCM_E_MEMORY;
   1282                 }
   1283 
   1284                 memset((void *)l2_table, 0, l2_tbl_sz);
   1285                 if (soc_mem_read_range(unit, L2MC_L2MEM(unit), MEM_BLOCK_ANY,
   1286                             index_min, index_max, l2_table) < 0) {
   1287                     sal_free(L2MC_USED(unit));
   1288                     soc_cm_sfree(unit, l2_table);
   1289                     return SOC_E_INTERNAL;
   1290                 }
   1291                 for (index = index_min; index <= index_max; index++) {
   1292                     int l2mc_idx;
   1293                     l2mc_entry_t mc_entry;
   1294                     soc_field_t  field_valid;
   1295 
   1296                     l2_entry =
   1297                         soc_mem_table_idx_to_pointer(unit, L2MC_L2MEM(unit),
   1298                                                      l2x_entry_t *, l2_table,
   1299                                                      index - index_min);
   1300                     field_valid = VALIDf;
   1301                     if (soc_feature(unit, soc_feature_base_valid)) {
   1302                         field_valid = BASE_VALIDf;
   1303                     }
   1304                     if (!soc_mem_field32_get(unit, L2MC_L2MEM(unit),
   1305                                 l2_entry, field_valid)) {
   1306                         continue;
   1307                     }
   1308 
   1309 #ifdef BCM_TRX_SUPPORT
   1310                     /* We're already traversing the L2 memory here, so
   1311                      * check for non-bridge items */
   1312                     if ((FALSE == SOC_CONTROL(unit)->l2x_ppa_bypass) &&
   1313                             soc_feature(unit, soc_feature_ppa_bypass) &&
   1314                             (soc_mem_field32_get(unit, L2MC_L2MEM(unit),
   1315                                                  l2_entry, KEY_TYPEf) !=
   1316                              TR_L2_HASH_KEY_TYPE_BRIDGE)) {
   1317                         SOC_CONTROL(unit)->l2x_ppa_bypass = TRUE;
   1318                     }
   1319 
   1320                     if (soc_mem_field_valid(unit, 
   1321                                             L2MC_L2MEM(unit), KEY_TYPEf) &&
   1322                             (soc_mem_field32_get(unit, L2MC_L2MEM(unit),
   1323                                                  l2_entry, KEY_TYPEf) !=
   1324                              TR_L2_HASH_KEY_TYPE_BRIDGE)) {
   1325                         /* The field L2MC_PTRf is only valid for key
   1326                          * type BRIDGE */
   1327                         continue;
   1328                     }
   1329 #endif /* BCM_TRX_SUPPORT */
   1330 
   1331                     soc_L2Xm_mac_addr_get(unit, l2_entry, MAC_ADDRf, mcmac);
   1332                     if (!BCM_MAC_IS_MCAST(mcmac)) {
   1333                         continue;
   1334                     }
   1335 
   1336                     if (soc_feature(unit, soc_feature_generic_dest)) {
   1337                         uint32 dest_type;
   1338                         l2mc_idx = soc_mem_field32_dest_get(unit,
   1339                                     L2MC_L2MEM(unit), l2_entry,
   1340                                     DESTINATIONf, &dest_type);
   1341                         if (dest_type != SOC_MEM_FIF_DEST_L2MC) {
   1342                             l2mc_idx = 0;
   1343                         }
   1344                     } else {
   1345                         l2mc_idx = soc_mem_field32_get(unit, L2MC_L2MEM(unit),
   1346                                                        l2_entry, L2MC_PTRf);
   1347                     }
   1348                     sal_memset(&mc_entry, 0, sizeof(l2mc_entry_t));
   1349                     if (soc_mem_read(unit, L2MC_MCMEM(unit),  MEM_BLOCK_ANY,
   1350                                 l2mc_idx, &mc_entry) < 0) {
   1351                         sal_free(L2MC_USED(unit));
   1352                         soc_cm_sfree(unit, l2_table);
   1353                         return SOC_E_INTERNAL;
   1354                     }
   1355 
   1356                     if (!soc_mem_field32_get(unit, L2MC_MCMEM(unit),
   1357                                 &mc_entry, VALIDf)) {
   1358                         continue;
   1359                     }
   1360                     L2MC_USED_SET(unit, l2mc_idx);
   1361                 }
   1362                 soc_cm_sfree(unit, l2_table);
   1363             }
   1364         }
   1365 
   1366         /*
   1367          * But then L2 table may not have indices populated for
   1368          * all valid L2MC entries..
   1369          * Go through L2MC table to search for existing entries
   1370          */
   1371         index_min = soc_mem_index_min(unit, L2MC_MCMEM(unit));
   1372         index_max = index_min + L2MC_SIZE(unit) - 1;
   1373 
   1374         l2mc_tbl_sz = sizeof(l2mc_entry_t) * L2MC_SIZE(unit);
   1375         l2mc_table = soc_cm_salloc(unit, l2mc_tbl_sz, "l2mc tbl dma");
   1376         if (l2mc_table == NULL) {
   1377             sal_free(L2MC_USED(unit));
   1378             return BCM_E_MEMORY;
   1379         }
   1380 
   1381         memset((void *)l2mc_table, 0, l2mc_tbl_sz);
   1382         if (soc_mem_read_range(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY,
   1383                     index_min, index_max, l2mc_table) < 0) {
   1384             sal_free(L2MC_USED(unit));
   1385             soc_cm_sfree(unit, l2mc_table);
   1386             return SOC_E_INTERNAL;
   1387         }
   1388 
   1389         for (index = index_min; index <= index_max; index++) {
   1390 
   1391             l2mc_entry = soc_mem_table_idx_to_pointer(unit, L2MC_MCMEM(unit),
   1392                     l2mc_entry_t *, l2mc_table, index);
   1393 
   1394             if (!soc_mem_field32_get(unit, L2MC_MCMEM(unit),
   1395                         l2mc_entry, VALIDf)) {
   1396                 continue;
   1397             }
   1398 
   1399             if (!L2MC_USED_ISSET(unit, index)) {
   1400                 L2MC_USED_SET(unit, index);
   1401             }
   1402         }
   1403 
   1404         soc_cm_sfree(unit, l2mc_table);
   1405 
   1406         return L2MC_SIZE(unit);
   1407     }
   1408 #endif /* BCM_WARM_BOOT_SUPPORT */
   1409 
   1410     if (!SAL_BOOT_BCMSIM && !SAL_BOOT_QUICKTURN && !SAL_BOOT_XGSSIM) {
   1411         SOC_IF_ERROR_RETURN
   1412             (soc_mem_clear(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL, FALSE));
   1413     }
   1414 
   1415     BCM_IF_ERROR_RETURN(bcm_xgs3_l2_addr_mcast_delete_all(unit)); 
   1416 
   1417     return L2MC_SIZE(unit);
   1418 }
   1419 
   1420 #ifndef BCM_SW_STATE_DUMP_DISABLE
   1421 /*
   1422  * Function:
   1423  *     _bcm_xgs3_mcast_sw_dump
   1424  * Purpose:
   1425  *     Displays XGS3 mcast information maintained by software.
   1426  * Parameters:
   1427  *     unit - Device unit number
   1428  * Returns:
   1429  *     None
   1430  */
   1431 void
   1432 _bcm_xgs3_mcast_sw_dump(int unit)
   1433 {
   1434     _bcm_xgs3_mcast_t  *info;
   1435     int                *used;
   1436     int                i, j;
   1437 
   1438     info = &xgs3_l2mc_info[unit];
   1439 
   1440     LOG_CLI((BSL_META_U(unit,
   1441                         "\n  XGS3 MCAST -\n")));
   1442     LOG_CLI((BSL_META_U(unit,
   1443                         "    Size   : %d\n"), info->size));
   1444     LOG_CLI((BSL_META_U(unit,
   1445                         "    L2 Mem : %d\n"), info->l2mem));
   1446     LOG_CLI((BSL_META_U(unit,
   1447                         "    MC Mem : %d\n"), info->mcmem));
   1448 
   1449     LOG_CLI((BSL_META_U(unit,
   1450                         "    Used (index:value) :")));
   1451     used = info->used;
   1452     if (used != NULL) {
   1453         for (i = 0, j = 0; i < info->size; i++) {
   1454             /* If zero, skip print */
   1455             if (used[i] == 0) {
   1456                 continue;
   1457             }
   1458             if (!(j % 4)) {
   1459                 LOG_CLI((BSL_META_U(unit,
   1460                                     "\n    ")));
   1461             }
   1462             LOG_CLI((BSL_META_U(unit,
   1463                                 "  %4d:%-5d"), i, used[i]));
   1464             j++;
   1465         }
   1466     }
   1467     LOG_CLI((BSL_META_U(unit,
   1468                         "\n")));
   1469 
   1470     return;
   1471 }
   1472 #endif /* BCM_SW_STATE_DUMP_DISABLE */