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

l2mcast.c (27107B)


      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/common/multicast.h>
     23 #if defined(BCM_TOMAHAWK3_SUPPORT)
     24 #include <bcm_int/esw/tomahawk3.h>
     25 #include <soc/tomahawk3.h>
     26 
     27 typedef struct {
     28     int         size;
     29     int         *used;
     30     soc_mem_t   l2mem;
     31     soc_mem_t   mcmem;
     32 } _bcm_th3_l2_mcast_t;
     33 
     34 static _bcm_th3_l2_mcast_t th3_l2mc_info[BCM_MAX_NUM_UNITS];
     35 
     36 #define L2MC_INFO(unit)          (&th3_l2mc_info[unit])
     37 #define L2MC_SIZE(unit)          L2MC_INFO(unit)->size
     38 #define L2MC_USED(unit)          L2MC_INFO(unit)->used
     39 #define L2MC_L2MEM(unit)         L2MC_INFO(unit)->l2mem
     40 #define L2MC_MCMEM(unit)         L2MC_INFO(unit)->mcmem
     41 #define L2MC_USED_SET(unit, n)   L2MC_USED(unit)[n] += 1
     42 #define L2MC_USED_CLR(unit, n)   L2MC_USED(unit)[n] -= 1
     43 #define L2MC_USED_ISSET(unit, n) (L2MC_USED(unit)[n] > 0)
     44 
     45 #define L2MC_INIT(unit) \
     46         if (L2MC_USED(unit) == NULL) { return BCM_E_INIT; }
     47 #define L2MC_ID(unit, id) \
     48         if (id < 0 || id >= L2MC_SIZE(unit)) { return BCM_E_PARAM; }
     49 
     50 #define L2MC_LOCK(unit)         do {            \
     51         soc_mem_lock(unit, L2MC_MCMEM(unit));   \
     52     } while(0)
     53 #define L2MC_UNLOCK(unit)       do {            \
     54         soc_mem_unlock(unit, L2MC_MCMEM(unit)); \
     55     } while(0)
     56 #define L2MC_ID_GET(l2mc_index) \
     57     (_BCM_MULTICAST_IS_SET(l2mc_index) &&    \
     58         _BCM_MULTICAST_IS_L2(l2mc_index)) ?  \
     59             _BCM_MULTICAST_ID_GET(l2mc_index) : l2mc_index
     60 
     61 /*
     62  * Function:
     63  *	_bcm_th3_l2_addr_delete_mcast
     64  * Description
     65  *	Delete L2 multicast entries
     66  * Parameters:
     67  *	unit  - device unit
     68  *	flags - BCM_L2_DELETE_XXX
     69  * Returns:
     70  *	BCM_E_XXX
     71  */
     72 int
     73 _bcm_th3_l2_addr_delete_mcast(int unit, uint32 flags)
     74 {
     75     l2x_entry_t *l2xe, *l2xep;
     76     int rv, chunksize, chunk, chunk_max, i;
     77     int dyn_only, chnk_end, mem_idx_max;
     78     bcm_mac_t mac;
     79 
     80     chunksize = soc_property_get(unit, spn_L2DELETE_CHUNKS,
     81                                  L2_MEM_CHUNKS_DEFAULT);
     82 
     83     l2xe = soc_cm_salloc(unit, chunksize * sizeof(*l2xe), "l2del_chunk");
     84     if (l2xe == NULL) {
     85         return BCM_E_MEMORY;
     86     }
     87 
     88     rv = BCM_E_NONE;
     89 
     90     dyn_only = !(flags & BCM_L2_DELETE_STATIC);
     91 
     92     mem_idx_max = soc_mem_index_max(unit, L2Xm);
     93     for (chunk = soc_mem_index_min(unit, L2Xm); chunk <= mem_idx_max;
     94          chunk += chunksize) {
     95 
     96         chunk_max = chunk + chunksize - 1;
     97         if (chunk_max > mem_idx_max) {
     98             chunk_max = mem_idx_max;
     99         }
    100 
    101         rv = soc_mem_read_range(unit, L2Xm, MEM_BLOCK_ANY,
    102                  chunk, chunk_max, l2xe);
    103         if (rv < 0) {
    104             break;
    105         }
    106 
    107         chnk_end = (chunk_max - chunk);
    108         for (i = 0; i <= chnk_end; i++) {
    109 
    110             l2xep = soc_mem_table_idx_to_pointer(unit, L2Xm,
    111                         l2x_entry_t *, l2xe, i);
    112 
    113             if (!soc_L2Xm_field32_get(unit, l2xep, BASE_VALIDf)) {
    114                 continue;
    115             }
    116 
    117             soc_L2Xm_mac_addr_get(unit, l2xep, MAC_ADDRf, mac);
    118             if (!BCM_MAC_IS_MCAST(mac)) {
    119                 continue;
    120             }
    121 
    122             if (dyn_only &&
    123                 soc_L2Xm_field32_get(unit, l2xep, STATIC_BITf)) {
    124                 continue;
    125             }
    126 
    127             rv = soc_mem_delete(unit, L2Xm, MEM_BLOCK_ALL, l2xep);
    128             if (rv < 0) {
    129                 break;
    130             }
    131         }
    132 
    133         if (rv < 0) {
    134             break;
    135         }
    136     }
    137 
    138     soc_cm_sfree(unit, l2xe);
    139 
    140     return rv;
    141 }
    142 
    143 /*
    144  * Function:
    145  *      _bcm_th3_l2mc_size_get
    146  * Description:
    147  *      Get number of L2MC groups.
    148  */
    149 int
    150 _bcm_th3_l2mc_size_get(int unit, int *size)
    151 {
    152     *size = L2MC_SIZE(unit);
    153     return BCM_E_NONE;
    154 }
    155 
    156 /*
    157  * Function:
    158  *      _bcm_th3_l2mc_index_is_set
    159  * Description:
    160  *      Check whether and l2mc index is used.
    161  */
    162 
    163 int
    164 _bcm_th3_l2mc_index_is_set(int unit, int l2mc_id, int *is_set)
    165 {
    166     L2MC_ID(unit, l2mc_id);
    167 
    168     *is_set = (0 != L2MC_USED_ISSET(unit, l2mc_id));
    169 
    170     return BCM_E_NONE;
    171 }
    172 
    173 /*
    174  * Function:
    175  *      _bcm_th3_l2mc_free_index
    176  * Description:
    177  *      Find an unused l2mc index and mark it used.
    178  */
    179 
    180 int
    181 _bcm_th3_l2mc_free_index(int unit, int *l2mc_id)
    182 {
    183     int i, rv;
    184 
    185     rv = BCM_E_FULL;
    186     for (i = 1; i < L2MC_SIZE(unit); i++) {
    187         if (!L2MC_USED_ISSET(unit, i)) {
    188             L2MC_USED_SET(unit, i);
    189             *l2mc_id = i;
    190             rv = BCM_E_NONE;
    191             break;
    192         }
    193     }
    194 
    195     return rv;
    196 }
    197 
    198 /*
    199  * Function:
    200  *      _bcm_th3_l2mc_id_alloc
    201  * Description:
    202  *      allocate the given l2mc entry (increment use count)
    203  */
    204 
    205 int
    206 _bcm_th3_l2mc_id_alloc(int unit, int l2mc_id)
    207 {
    208     L2MC_ID(unit, l2mc_id);
    209 
    210     L2MC_USED_SET(unit, l2mc_id);
    211 
    212     return BCM_E_NONE;
    213 }
    214 
    215 /*
    216  * Function:
    217  *      _bcm_th3_l2mc_id_free
    218  * Description:
    219  *      Marks an l2mc index as free (decrements use count)
    220  */
    221 
    222 int
    223 _bcm_th3_l2mc_id_free(int unit, int l2mc_id)
    224 {
    225     L2MC_ID(unit, l2mc_id);
    226 
    227     L2MC_USED_CLR(unit, l2mc_id);
    228 
    229     return BCM_E_NONE;
    230 }
    231 
    232 /*
    233  * Function:
    234  *      _bcm_th3_mcast_from_l2
    235  * Description:
    236  *      Fill in fields of bcm_mcast_addr_t from bcm_l2_addr_t
    237  * Parameters:
    238  *      unit    - (IN) device
    239  *      mcaddr  - (OUT) mcast addr struct
    240  *      l2addr  - (IN) l2 addr struct
    241  */
    242 
    243 STATIC void
    244 _bcm_th3_mcast_from_l2(int unit,
    245                        bcm_mcast_addr_t *mcaddr,
    246                        bcm_l2_addr_t  *l2addr)
    247 {
    248     int               rv;
    249     vlan_tab_entry_t vte;
    250     soc_mem_t        vlan_mem;
    251 
    252     sal_memcpy(mcaddr->mac, l2addr->mac, sizeof(bcm_mac_t));
    253     mcaddr->vid = l2addr->vid;
    254     mcaddr->cos_dst = l2addr->cos_dst;
    255     mcaddr->l2mc_index = l2addr->l2mc_group;
    256 
    257     /* Need to fill in the untagged port bitmap from the VLAN table */
    258     SOC_PBMP_CLEAR(mcaddr->ubmp);
    259     vlan_mem = EGR_VLANm;
    260     rv = soc_mem_read(unit, vlan_mem, MEM_BLOCK_ANY, mcaddr->vid, &vte);
    261     if (rv < 0) {
    262         return;
    263     }
    264 
    265     soc_mem_pbmp_field_get(unit, vlan_mem, &vte, UT_BITMAPf, &mcaddr->ubmp);
    266 }
    267 
    268 /*
    269  * Function:
    270  *      _bcm_th3_l2_mcast_to_l2
    271  * Description:
    272  *      Fill in fields of bcm_l2_addr_t from bcm_mcast_addr_t
    273  * Parameters:
    274  *      unit -  (IN) device
    275  *      l2addr - (OUT) Pointer to bcm_l2_addr_t
    276  *      mcaddr - (IN) Pointer to bcm_mcast_addr_t
    277  */
    278 
    279 STATIC void
    280 _bcm_th3_l2_mcast_to_l2(int unit,
    281                         bcm_l2_addr_t *l2addr,
    282                         bcm_mcast_addr_t *mcaddr)
    283 {
    284     sal_memset(l2addr, 0, sizeof(*l2addr));
    285     l2addr->flags = BCM_L2_STATIC | BCM_L2_MCAST | BCM_L2_REPLACE_DYNAMIC;
    286     l2addr->cos_dst = mcaddr->cos_dst;
    287     l2addr->vid = mcaddr->vid;
    288     sal_memcpy(l2addr->mac, mcaddr->mac, sizeof(bcm_mac_t));
    289     l2addr->l2mc_group = mcaddr->l2mc_index;
    290 }
    291 
    292 /*
    293  * Function:
    294  *      _bcm_th3_mcast_create
    295  * Description:
    296  *      Create a muticast entry
    297  * Parameters:
    298  *      unit -  (IN) device
    299  *      mcaddr - (IN) Pointer to bcm_mcast_addr_t
    300  *      mcindex - (IN) mcast index to use (-1 lets routine choose)
    301  * Returns:
    302  *      BCM_E_XXX
    303  */
    304 
    305 STATIC int
    306 _bcm_th3_mcast_create(int unit, bcm_mcast_addr_t *mcaddr,
    307                        int mcindex)
    308 {
    309     l2mc_entry_t        l2mc, rl2mc;
    310     bcm_l2_addr_t       l2addr, rl2addr;
    311     bcm_pbmp_t          pbm, rpbm;
    312     int                 rv;
    313 
    314     bcm_l2_addr_t_init (&l2addr, mcaddr->mac, mcaddr->vid);
    315     rv = bcm_tomahawk3_l2_addr_get(unit, mcaddr->mac, mcaddr->vid, &l2addr);
    316     if (rv >= 0) {
    317         if (!(l2addr.flags & BCM_L2_MCAST)) {
    318             return BCM_E_EXISTS;
    319         }
    320         l2addr.l2mc_group = L2MC_ID_GET(l2addr.l2mc_group);
    321         if (mcindex >= 0 && mcindex == l2addr.l2mc_group) {
    322             return BCM_E_NONE;
    323         }
    324         BCM_IF_ERROR_RETURN(_bcm_th3_l2mc_id_free(unit, l2addr.l2mc_group));
    325     }
    326 
    327     /* Before getting free MC index, make sure this is a valid Port */
    328     rv = soc_mem_field_pbmp_fit(unit, L2MC_MCMEM(unit), PORT_BITMAPf,
    329                                (uint32 *)&mcaddr->pbmp);
    330     if (rv != SOC_E_NONE) {
    331         return rv;
    332     }
    333 
    334     if (mcindex < 0) {
    335         BCM_IF_ERROR_RETURN(_bcm_th3_l2mc_free_index(unit, &mcindex));
    336     } else {
    337         BCM_IF_ERROR_RETURN(_bcm_th3_l2mc_id_alloc(unit, mcindex));
    338     }
    339 
    340     sal_memset(&l2mc, 0, sizeof(l2mc));
    341     soc_mem_field32_set(unit, L2MC_MCMEM(unit), &l2mc, VALIDf, 1);
    342     soc_mem_pbmp_field_set(unit, L2MC_MCMEM(unit), &l2mc, PORT_BITMAPf,
    343                            &mcaddr->pbmp);
    344     _bcm_th3_l2_mcast_to_l2(unit, &l2addr, mcaddr);
    345     l2addr.l2mc_group = mcindex;
    346 
    347     if (SOC_MCAST_ADD_ALL_ROUTER_PORTS(unit)) {
    348         sal_memset(&rl2addr, 0, sizeof(bcm_l2_addr_t));
    349         rv = bcm_tomahawk3_l2_addr_get(unit, (uint8 *)_soc_mac_all_routers,
    350                                        mcaddr->vid, &rl2addr);
    351         if (rv >= 0) {
    352             rl2addr.l2mc_group = L2MC_ID_GET(rl2addr.l2mc_group);
    353             SOC_IF_ERROR_RETURN
    354                 (soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY,
    355                               rl2addr.l2mc_group, &rl2mc));
    356             soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &rl2mc,
    357                                    PORT_BITMAPf, &rpbm);
    358             soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &l2mc, PORT_BITMAPf,
    359                                    &pbm);
    360             BCM_PBMP_OR(pbm, rpbm);
    361             soc_mem_pbmp_field_set(unit, L2MC_MCMEM(unit), &l2mc, PORT_BITMAPf,
    362                                    &pbm);
    363         }
    364     }
    365 
    366     /* add l2mc entry */
    367     SOC_IF_ERROR_RETURN
    368         (soc_mem_write(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL, mcindex, &l2mc));
    369 
    370     /* add l2 entry */
    371     rv = bcm_tomahawk3_l2_addr_add(unit, &l2addr);
    372     if (BCM_FAILURE(rv)) {
    373         _bcm_th3_l2mc_id_free(unit, l2addr.l2mc_group);
    374         if (!L2MC_USED_ISSET(unit, l2addr.l2mc_group)) {
    375           soc_mem_write(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL,
    376                         l2addr.l2mc_group,
    377                         soc_mem_entry_null(unit, L2MC_MCMEM(unit)));
    378         }
    379     }
    380 
    381     return rv;
    382 }
    383 
    384 /*
    385  * Function:
    386  *      _bcm_th3_mcast_port_add
    387  * Purpose:
    388  *      Add new ports to a multicast entry
    389  * Parameters:
    390  *      unit    - device
    391  *      mcaddr  - mcast addr struct with new ports
    392  * Returns:
    393  *      BCM_E_XXX
    394  */
    395 
    396 STATIC int
    397 _bcm_th3_mcast_port_add(int unit, bcm_mcast_addr_t *mcaddr)
    398 {
    399     bcm_l2_addr_t       l2addr;
    400     l2mc_entry_t        l2mc_entry;
    401     bcm_pbmp_t          pbmp;
    402 
    403     bcm_l2_addr_t_init(&l2addr, mcaddr->mac, mcaddr->vid);
    404     BCM_IF_ERROR_RETURN(bcm_tomahawk3_l2_addr_get(unit, mcaddr->mac,
    405                                                   mcaddr->vid, &l2addr));
    406     if (!(l2addr.flags & BCM_L2_MCAST)) {
    407         return BCM_E_NOT_FOUND;
    408     }
    409 
    410     l2addr.l2mc_group = L2MC_ID_GET(l2addr.l2mc_group);
    411 
    412     SOC_IF_ERROR_RETURN(soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY,
    413                                      l2addr.l2mc_group, &l2mc_entry));
    414 
    415     soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf,
    416                            &pbmp);
    417     BCM_PBMP_OR(pbmp, mcaddr->pbmp);
    418     soc_mem_pbmp_field_set(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf,
    419                            &pbmp);
    420 
    421     SOC_IF_ERROR_RETURN(soc_mem_write(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL,
    422                                       l2addr.l2mc_group, &l2mc_entry));
    423 
    424     return BCM_E_NONE;
    425 }
    426 
    427 /*
    428  * Function:
    429  *      _bcm_th3_mcast_port_delete
    430  * Purpose:
    431  *      Remove ports from a multicast entry
    432  * Parameters:
    433  *      unit    - device
    434  *      mcaddr  - mcast addr struct with ports to delete
    435  * Returns:
    436  *      BCM_E_XXX
    437  */
    438 
    439 STATIC int
    440 _bcm_th3_mcast_port_delete(int unit,
    441                             bcm_mcast_addr_t *mcaddr)
    442 {
    443     bcm_l2_addr_t       l2addr;
    444     l2mc_entry_t        l2mc_entry;
    445     bcm_pbmp_t          pbmp;
    446 
    447     bcm_l2_addr_t_init (&l2addr, mcaddr->mac, mcaddr->vid);
    448     BCM_IF_ERROR_RETURN(bcm_tomahawk3_l2_addr_get(unit, mcaddr->mac,
    449                                                   mcaddr->vid, &l2addr));
    450 
    451     if (!(l2addr.flags & BCM_L2_MCAST)) {
    452         return BCM_E_NOT_FOUND;
    453     }
    454 
    455     l2addr.l2mc_group = L2MC_ID_GET(l2addr.l2mc_group);
    456 
    457     SOC_IF_ERROR_RETURN(soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY,
    458                                      l2addr.l2mc_group, &l2mc_entry));
    459 
    460     soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf,
    461                            &pbmp);
    462     BCM_PBMP_REMOVE(pbmp, mcaddr->pbmp);
    463     soc_mem_pbmp_field_set(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf,
    464                            &pbmp);
    465 
    466     SOC_IF_ERROR_RETURN(soc_mem_write(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL,
    467                                       l2addr.l2mc_group, &l2mc_entry));
    468 
    469     return BCM_E_NONE;
    470 }
    471 
    472 /*
    473  * Function:
    474  *      bcm_th3_mcast_port_remove
    475  * Purpose:
    476  *      Remove ports from existing MC entry.
    477  * Returns:
    478  *      BCM_E_XXX
    479  */
    480 
    481 int
    482 bcm_th3_mcast_port_remove(int unit, bcm_mcast_addr_t *mcaddr)
    483 {
    484     int rv;
    485 
    486     L2MC_INIT(unit);
    487     L2MC_LOCK(unit);
    488     rv = _bcm_th3_mcast_port_delete(unit, mcaddr);
    489     L2MC_UNLOCK(unit);
    490     return rv;
    491 }
    492 
    493 /*
    494  * Function:
    495  *      bcm_th3_mcast_port_add
    496  * Purpose:
    497  *      Add ports to existing MC entry.
    498  * Returns:
    499  *      BCM_E_XXX
    500  */
    501 
    502 int
    503 bcm_th3_mcast_port_add(int unit, bcm_mcast_addr_t *mcaddr)
    504 {
    505     int rv;
    506 
    507     L2MC_INIT(unit);
    508     L2MC_LOCK(unit);
    509     rv = _bcm_th3_mcast_port_add(unit, mcaddr);
    510     L2MC_UNLOCK(unit);
    511     return rv;
    512 }
    513 
    514 /*
    515  * Function:
    516  *      bcm_th3_mcast_addr_add_w_l2mcindex
    517  * Purpose:
    518  *      Add a new MC entry to the L2 and L2MC tables, with given MC index.
    519  * Returns:
    520  *      BCM_E_XXX
    521  */
    522 
    523 int
    524 bcm_th3_mcast_addr_add_w_l2mcindex(int unit, bcm_mcast_addr_t *mcaddr)
    525 {
    526     int rv;
    527 
    528     L2MC_INIT(unit);
    529     L2MC_LOCK(unit);
    530     rv = _bcm_th3_mcast_create(unit, mcaddr, mcaddr->l2mc_index);
    531     L2MC_UNLOCK(unit);
    532     return rv;
    533 }
    534 
    535 /*
    536  * Function:
    537  *      bcm_th3_mcast_addr_add
    538  * Purpose:
    539  *      Add new L2 multicast entry
    540  * Returns:
    541  *      BCM_E_XXX
    542  */
    543 
    544 int
    545 bcm_th3_mcast_addr_add(int unit, bcm_mcast_addr_t *mcaddr)
    546 {
    547     int rv;
    548 
    549     L2MC_INIT(unit);
    550     L2MC_LOCK(unit);
    551     /*    coverity[negative_returns : FALSE]    */
    552     rv = _bcm_th3_mcast_create(unit, mcaddr, -1);
    553     L2MC_UNLOCK(unit);
    554     return rv;
    555 }
    556 
    557 /*
    558  * Function:
    559  *      bcm_th3_mcast_addr_remove
    560  * Purpose:
    561  *      Remove a multicast entry
    562  * Returns:
    563  *      BCM_E_XXX
    564  */
    565 
    566 int
    567 bcm_th3_mcast_addr_remove(int unit, sal_mac_addr_t mac, bcm_vlan_t vid)
    568 {
    569     int                 rv;
    570     bcm_l2_addr_t       l2addr;
    571 
    572     L2MC_INIT(unit);
    573     L2MC_LOCK(unit);
    574 
    575     bcm_l2_addr_t_init (&l2addr, mac, vid);
    576     rv = bcm_tomahawk3_l2_addr_get(unit, mac, vid, &l2addr);
    577     if (rv < 0) {
    578         L2MC_UNLOCK(unit);
    579         return rv;
    580     }
    581 
    582     if (!(l2addr.flags & BCM_L2_MCAST)) {
    583         L2MC_UNLOCK(unit);
    584         return BCM_E_NOT_FOUND;
    585     }
    586 
    587     rv = bcm_tomahawk3_l2_addr_delete(unit, mac, vid);
    588     if (rv < 0) {
    589         L2MC_UNLOCK(unit);
    590         return rv;
    591     }
    592 
    593     /* Check added to avoid Segmentation fault in regression tests */
    594     /* Sometimes l2mc_index may not have a multicast type set when
    595      * switchcontrol L2McIdxRetType is set to 0
    596      */
    597     if (_BCM_MULTICAST_IS_L2(l2addr.l2mc_group) ||
    598         !_BCM_MULTICAST_IS_SET(l2addr.l2mc_group)) {
    599          l2addr.l2mc_group = L2MC_ID_GET(l2addr.l2mc_group);
    600          _bcm_th3_l2mc_id_free(unit, l2addr.l2mc_group);
    601 
    602          if (!L2MC_USED_ISSET(unit, l2addr.l2mc_group)) {
    603               rv = soc_mem_write(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL,
    604                        l2addr.l2mc_group,
    605                        soc_mem_entry_null(unit, L2MC_MCMEM(unit)));
    606          }
    607     }
    608 
    609     L2MC_UNLOCK(unit);
    610     return rv;
    611 }
    612 
    613 /*
    614  * Function:
    615  *      bcm_th3_mcast_addr_remove_w_l2mcindex
    616  * Purpose:
    617  *      Remove a multicast entry with l2mc index provided
    618  * Returns:
    619  *      BCM_E_XXX
    620  */
    621 
    622 int
    623 bcm_th3_mcast_addr_remove_w_l2mcindex(int unit,
    624                                         bcm_mcast_addr_t *mcaddr)
    625 {
    626     return bcm_th3_mcast_addr_remove(unit, mcaddr->mac, mcaddr->vid);
    627 }
    628 
    629 /*
    630  * Function:
    631  *      _bcm_th3_mcast_index_port_get
    632  * Purpose:
    633  *      Get port bit maps for a multicast group by index.
    634  * Returns:
    635  *      BCM_E_XXX
    636  */
    637 
    638 int
    639 _bcm_th3_mcast_index_port_get(int unit, int l2mc_index,
    640                               bcm_mcast_addr_t *mcaddr)
    641 {
    642     l2mc_entry_t      l2mc_entry;
    643 
    644     L2MC_INIT(unit);
    645 
    646     SOC_IF_ERROR_RETURN(soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY,
    647                                      L2MC_ID_GET(l2mc_index), &l2mc_entry));
    648 
    649     soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf,
    650                            &mcaddr->pbmp);
    651 
    652     return BCM_E_NONE;
    653 }
    654 
    655 /*
    656  * Function:
    657  *      bcm_th3_mcast_port_get
    658  * Purpose:
    659  *      Get port bit maps for a multicast group.
    660  * Returns:
    661  *      BCM_E_XXX
    662  */
    663 
    664 int
    665 bcm_th3_mcast_port_get(int unit,
    666                          sal_mac_addr_t mac, bcm_vlan_t vid,
    667                          bcm_mcast_addr_t *mcaddr)
    668 {
    669     l2mc_entry_t      l2mc_entry;
    670     bcm_l2_addr_t     l2addr;
    671 
    672     L2MC_INIT(unit);
    673 
    674     bcm_l2_addr_t_init (&l2addr, mac, vid);
    675     BCM_IF_ERROR_RETURN(bcm_tomahawk3_l2_addr_get(unit, mac, vid, &l2addr));
    676 
    677     l2addr.l2mc_group = L2MC_ID_GET(l2addr.l2mc_group);
    678     SOC_IF_ERROR_RETURN
    679         (soc_mem_read(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY,
    680                       l2addr.l2mc_group, &l2mc_entry));
    681 
    682     _bcm_th3_mcast_from_l2(unit, mcaddr, &l2addr);
    683     soc_mem_pbmp_field_get(unit, L2MC_MCMEM(unit), &l2mc_entry, PORT_BITMAPf,
    684                            &mcaddr->pbmp);
    685 
    686     return BCM_E_NONE;
    687 }
    688 
    689 /*
    690  * Function:
    691  *      _bcm_th3_mcast_detach
    692  * Purpose:
    693  *      De-initialize multicast api components
    694  * Returns:
    695  *      BCM_E_XXX
    696  */
    697 int
    698 _bcm_th3_mcast_detach(int unit)
    699 {
    700     if (L2MC_USED(unit) != NULL) {
    701         sal_free(L2MC_USED(unit));
    702         L2MC_USED(unit) = NULL;
    703     }
    704     L2MC_SIZE(unit) = 0;
    705     L2MC_L2MEM(unit) = INVALIDm;
    706     L2MC_MCMEM(unit) = INVALIDm;
    707 
    708     return (BCM_E_NONE);
    709 }
    710 
    711 /*
    712  * Function:
    713  *      bcm_th3_l2_addr_mcast_delete_all
    714  * Purpose:
    715  *      Delete multicast address entries in l2 table
    716  * Returns:
    717  *      BCM_E_XXX
    718  */
    719 int
    720 bcm_th3_l2_addr_mcast_delete_all(int unit)
    721 {
    722     /* Delete all multicast entries from L2 */
    723     if (!SAL_BOOT_QUICKTURN && !SAL_BOOT_BCMSIM && !SAL_BOOT_XGSSIM) {
    724         if (!SAL_BOOT_BCMSIM) {
    725             BCM_IF_ERROR_RETURN(_bcm_th3_l2_addr_delete_mcast(unit,
    726                                     BCM_L2_DELETE_STATIC));
    727         }
    728     }
    729 
    730     return BCM_E_NONE;
    731 }
    732 
    733 /*
    734  * Function:
    735  *      bcm_th3_mcast_init
    736  * Purpose:
    737  *      Initialize multicast api components
    738  * Returns:
    739  *      BCM_E_XXX on error
    740  *      number of mcast entries supported on success
    741  */
    742 
    743 int
    744 bcm_th3_mcast_init(int unit)
    745 {
    746     if (L2MC_USED(unit) != NULL) {
    747         sal_free(L2MC_USED(unit));
    748     }
    749     L2MC_SIZE(unit) = 0;
    750 
    751     L2MC_L2MEM(unit) = L2Xm;
    752     L2MC_MCMEM(unit) = L2MCm;
    753 #if defined(BCM_BRADLEY_SUPPORT) || defined(BCM_TRX_SUPPORT)
    754     if (SOC_IS_HBX(unit) || SOC_IS_TRX(unit)) {
    755         int mc_base, mc_size;
    756 
    757 #ifdef BCM_WARM_BOOT_SUPPORT
    758         if (SOC_WARM_BOOT(unit)) {
    759             uint32 mc_ctrl;
    760             soc_control_t       *soc = SOC_CONTROL(unit);
    761 
    762             /* Recover the mcast size settings */
    763             if (SOC_REG_FIELD_VALID(unit, MC_CONTROL_5r,
    764                                     SHARED_TABLE_L2MC_SIZEf) &&
    765                 SOC_REG_FIELD_VALID(unit, MC_CONTROL_5r,
    766                                     SHARED_TABLE_IPMC_SIZEf)) {
    767                 SOC_IF_ERROR_RETURN(READ_MC_CONTROL_5r(unit, &mc_ctrl));
    768                 soc->mcast_size =
    769                     soc_reg_field_get(unit, MC_CONTROL_5r, mc_ctrl,
    770                                       SHARED_TABLE_L2MC_SIZEf);
    771                 soc->ipmc_size =
    772                     soc_reg_field_get(unit, MC_CONTROL_5r, mc_ctrl,
    773                                       SHARED_TABLE_IPMC_SIZEf);
    774             }
    775 
    776         }
    777 #endif /* BCM_WARM_BOOT_SUPPORT */
    778 
    779         /* We will keep the hbx calls for now */
    780         SOC_IF_ERROR_RETURN
    781             (soc_hbx_mcast_size_get(unit, &mc_base, &mc_size));
    782 
    783         L2MC_SIZE(unit) = mc_size;
    784     }
    785 #endif
    786 
    787     if (L2MC_SIZE(unit) <= 0) {
    788         L2MC_SIZE(unit) = soc_mem_index_count(unit, L2MC_MCMEM(unit));
    789     }
    790 
    791     L2MC_USED(unit) = sal_alloc(sizeof(int) * L2MC_SIZE(unit), "L2MC");
    792     if (L2MC_USED(unit) == NULL) {
    793         return BCM_E_MEMORY;
    794     }
    795     sal_memset(L2MC_USED(unit), 0, sizeof(int) * L2MC_SIZE(unit));
    796 
    797 #ifdef BCM_WARM_BOOT_SUPPORT
    798     if (SOC_WARM_BOOT(unit)) {
    799         l2x_entry_t  *l2_entry, *l2_table;
    800         l2mc_entry_t *l2mc_entry, *l2mc_table;
    801         int index, index_min, index_max, l2mc_tbl_sz, l2_tbl_sz;
    802         sal_mac_addr_t mcmac;
    803         int iter, dma_iter = 1;
    804 
    805         /*
    806          * Go through L2 table to get MC use counts
    807          */
    808 
    809         index_min = soc_mem_index_min(unit, L2MC_L2MEM(unit));
    810         index_max = soc_mem_index_max(unit, L2MC_L2MEM(unit));
    811         l2_tbl_sz = sizeof(l2x_entry_t) * (index_max - index_min + 1);
    812 
    813         for (iter = 0; iter < dma_iter; iter++) {
    814             l2_table = soc_cm_salloc(unit, l2_tbl_sz, "l2 tbl dma");
    815             if (l2_table == NULL) {
    816                 sal_free(L2MC_USED(unit));
    817                 return BCM_E_MEMORY;
    818             }
    819 
    820             memset((void *)l2_table, 0, l2_tbl_sz);
    821             if (soc_mem_read_range(unit, L2MC_L2MEM(unit), MEM_BLOCK_ANY,
    822                         index_min, index_max, l2_table) < 0) {
    823                 sal_free(L2MC_USED(unit));
    824                 soc_cm_sfree(unit, l2_table);
    825                 return BCM_E_INTERNAL;
    826             }
    827             for (index = index_min; index <= index_max; index++) {
    828                 int l2mc_idx;
    829                 l2mc_entry_t mc_entry;
    830                 soc_field_t  field_valid;
    831 
    832                 l2_entry =
    833                     soc_mem_table_idx_to_pointer(unit, L2MC_L2MEM(unit),
    834                                                  l2x_entry_t *, l2_table,
    835                                                  index - index_min);
    836                 field_valid = BASE_VALIDf;
    837                 if (!soc_mem_field32_get(unit, L2MC_L2MEM(unit), l2_entry,
    838                                          field_valid)) {
    839                     continue;
    840                 }
    841 
    842                 if (soc_mem_field_valid(unit, L2MC_L2MEM(unit), KEY_TYPEf)
    843                         && (soc_mem_field32_get(unit, L2MC_L2MEM(unit),
    844                                 l2_entry, KEY_TYPEf) !=
    845                                 TH3_L2_HASH_KEY_TYPE_BRIDGE)) {
    846 
    847                     /* Field L2MC_PTRf is only valid for key type BRIDGE */
    848                     continue;
    849                 }
    850 
    851                 soc_L2Xm_mac_addr_get(unit, l2_entry, MAC_ADDRf, mcmac);
    852                 if (!BCM_MAC_IS_MCAST(mcmac)) {
    853                     continue;
    854                 }
    855 
    856                 l2mc_idx = soc_mem_field32_get(unit, L2MC_L2MEM(unit),
    857                                l2_entry, L2MC_PTRf);
    858                 sal_memset(&mc_entry, 0, sizeof(l2mc_entry_t));
    859                 if (soc_mem_read(unit, L2MC_MCMEM(unit),  MEM_BLOCK_ANY,
    860                         l2mc_idx, &mc_entry) < 0) {
    861                     sal_free(L2MC_USED(unit));
    862                     soc_cm_sfree(unit, l2_table);
    863                     return BCM_E_INTERNAL;
    864                 }
    865 
    866                 if (!soc_mem_field32_get(unit, L2MC_MCMEM(unit), &mc_entry,
    867                                          VALIDf)) {
    868                     continue;
    869                 }
    870 
    871                 L2MC_USED_SET(unit, l2mc_idx);
    872             }
    873             soc_cm_sfree(unit, l2_table);
    874         }
    875 
    876         /*
    877          * But then L2 table may not have indices populated for
    878          * all valid L2MC entries.
    879          * Go through L2MC table to search for existing entries
    880          */
    881         index_min = soc_mem_index_min(unit, L2MC_MCMEM(unit));
    882         index_max = index_min + L2MC_SIZE(unit) - 1;
    883 
    884         l2mc_tbl_sz = sizeof(l2mc_entry_t) * L2MC_SIZE(unit);
    885         l2mc_table = soc_cm_salloc(unit, l2mc_tbl_sz, "l2mc tbl dma");
    886         if (l2mc_table == NULL) {
    887             sal_free(L2MC_USED(unit));
    888             return BCM_E_MEMORY;
    889         }
    890 
    891         memset((void *)l2mc_table, 0, l2mc_tbl_sz);
    892         if (soc_mem_read_range(unit, L2MC_MCMEM(unit), MEM_BLOCK_ANY,
    893                     index_min, index_max, l2mc_table) < 0) {
    894             sal_free(L2MC_USED(unit));
    895             soc_cm_sfree(unit, l2mc_table);
    896             return BCM_E_INTERNAL;
    897         }
    898 
    899         for (index = index_min; index <= index_max; index++) {
    900 
    901             l2mc_entry = soc_mem_table_idx_to_pointer(unit, L2MC_MCMEM(unit),
    902                                                       l2mc_entry_t *,
    903                                                       l2mc_table, index);
    904 
    905             if (!soc_mem_field32_get(unit, L2MC_MCMEM(unit),
    906                         l2mc_entry, VALIDf)) {
    907                 continue;
    908             }
    909 
    910             if (!L2MC_USED_ISSET(unit, index)) {
    911                 L2MC_USED_SET(unit, index);
    912             }
    913         }
    914 
    915         soc_cm_sfree(unit, l2mc_table);
    916 
    917         return L2MC_SIZE(unit);
    918     }
    919 #endif /* BCM_WARM_BOOT_SUPPORT */
    920 
    921     if (!SAL_BOOT_BCMSIM && !SAL_BOOT_QUICKTURN && !SAL_BOOT_XGSSIM) {
    922         SOC_IF_ERROR_RETURN
    923             (soc_mem_clear(unit, L2MC_MCMEM(unit), MEM_BLOCK_ALL, FALSE));
    924     }
    925 
    926     BCM_IF_ERROR_RETURN(bcm_th3_l2_addr_mcast_delete_all(unit));
    927 
    928     return L2MC_SIZE(unit);
    929 }
    930 
    931 #ifndef BCM_SW_STATE_DUMP_DISABLE
    932 /*
    933  * Function:
    934  *     _bcm_th3_l2_mcast_sw_dump
    935  * Purpose:
    936  *     Displays TH3 mcast information maintained by software.
    937  * Parameters:
    938  *     unit - Device unit number
    939  * Returns:
    940  *     None
    941  */
    942 void
    943 _bcm_th3_l2_mcast_sw_dump(int unit)
    944 {
    945     _bcm_th3_l2_mcast_t  *info;
    946     int                  *used;
    947     int                  i, j;
    948 
    949     info = &th3_l2mc_info[unit];
    950 
    951     LOG_CLI((BSL_META_U(unit,
    952                         "\n  L2 MCAST -\n")));
    953     LOG_CLI((BSL_META_U(unit,
    954                         "    Size   : %d\n"), info->size));
    955     LOG_CLI((BSL_META_U(unit,
    956                         "    L2 Mem : %d\n"), info->l2mem));
    957     LOG_CLI((BSL_META_U(unit,
    958                         "    MC Mem : %d\n"), info->mcmem));
    959 
    960     LOG_CLI((BSL_META_U(unit,
    961                         "    Used (index:value) :")));
    962     used = info->used;
    963     if (used != NULL) {
    964         for (i = 0, j = 0; i < info->size; i++) {
    965             /* If zero, skip print */
    966             if (used[i] == 0) {
    967                 continue;
    968             }
    969             if (!(j % 4)) {
    970                 LOG_CLI((BSL_META_U(unit,
    971                                     "\n    ")));
    972             }
    973             LOG_CLI((BSL_META_U(unit,
    974                                 "  %4d:%-5d"), i, used[i]));
    975             j++;
    976         }
    977     }
    978     LOG_CLI((BSL_META_U(unit,
    979                         "\n")));
    980 
    981     return;
    982 }
    983 #endif /* BCM_SW_STATE_DUMP_DISABLE */
    984 #endif /* BCM_TOMAHAWK3_SUPPORT */