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 (29907B)


      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  * Multicast Table Management
      8  */
      9 
     10 #include <shared/bsl.h>
     11 
     12 #include <sal/core/libc.h>
     13 #include <soc/drv.h>
     14 #include <soc/feature.h>
     15 #include <soc/mem.h>
     16 #if defined(BCM_BRADLEY_SUPPORT)
     17 #include <soc/bradley.h>
     18 #endif /* BCM_BRADLEY_SUPPORT */
     19 
     20 #include <bcm/error.h>
     21 #include <bcm/mcast.h>
     22 
     23 #include <bcm_int/esw/mbcm.h>
     24 #include <bcm_int/esw/mcast.h>
     25 #include <bcm_int/esw/firebolt.h>
     26 #include <bcm_int/common/multicast.h>
     27 #if defined(BCM_WARM_BOOT_SUPPORT) && defined(INCLUDE_L3)
     28 #include <bcm_int/esw/ipmc.h>
     29 #endif /* BCM_WARM_BOOT_SUPPORT && INCLUDE_L3 */
     30 
     31 #include <bcm_int/esw_dispatch.h>
     32 
     33 #define MCAST_INIT_RETURN(unit) \
     34         if (!_bcm_mcast_init[unit]) {return BCM_E_INIT;}
     35 
     36 static int _bcm_mcast_init[BCM_MAX_NUM_UNITS];
     37 static int _bcm_mcast_idx_ret_type[BCM_MAX_NUM_UNITS];
     38 
     39 /*
     40  * Function:
     41  *      _bcm_esw_mcast_detach
     42  * Purpose:
     43  *      De-initialize multicast bcm routines.
     44  * Parameters:
     45  *      unit - (IN) BCM device number.
     46  * Returns:
     47  *      BCM_E_XXX
     48  */
     49 
     50 int
     51 _bcm_esw_mcast_detach(int unit)
     52 {
     53     int rv;
     54 
     55     rv = mbcm_driver[unit]->mbcm_mcast_detach(unit);
     56     if (BCM_FAILURE(rv)) {
     57         return rv;
     58     }
     59 
     60     _bcm_mcast_init[unit] = FALSE;
     61 
     62     return rv;
     63 }
     64 
     65 /*
     66  * Function:
     67  *      bcm_esw_mcast_init
     68  * Purpose:
     69  *      Initialize multicast bcm routines.
     70  * Parameters:
     71  *      unit - StrataSwitch unit #
     72  * Returns:
     73  *      Mcast table size for XGS, or BCM_E_NONE for Strata
     74  *      BCM_E_INTERNAL if table write failed.
     75  */
     76 
     77 int
     78 bcm_esw_mcast_init(int unit)
     79 {
     80     int rv;
     81 
     82     LOG_INFO(BSL_LS_BCM_MCAST,
     83              (BSL_META_U(unit,
     84                          "MCAST %d: Init\n"),
     85               unit));
     86     if (SOC_IS_SHADOW(unit)) {
     87         return BCM_E_UNAVAIL;
     88     }
     89 
     90     rv = mbcm_driver[unit]->mbcm_mcast_init(unit);
     91     if (rv < 0) {
     92         return rv;
     93     }
     94 
     95     _bcm_mcast_init[unit] = TRUE;
     96     _bcm_mcast_idx_ret_type[unit] = 0;
     97 
     98 #if defined(BCM_WARM_BOOT_SUPPORT) && defined(INCLUDE_L3)
     99     if (SOC_WARM_BOOT(unit) && soc_feature(unit, soc_feature_l3)) {
    100         int rv2; /* Don't change return value holding mcast table size. */
    101         uint8 flags;
    102         rv2 = _bcm_esw_ipmc_repl_wb_flags_get(unit,
    103                       _BCM_IPMC_WB_L2MC_GROUP_TYPE_MULTICAST, &flags);
    104         if (BCM_SUCCESS(rv2)) {
    105             _bcm_mcast_idx_ret_type[unit] = (0 != flags);
    106         } else if (BCM_E_UNAVAIL != rv2) {
    107             return rv2;
    108         } /* Else ignore unavailable error. */
    109     }
    110 #endif /* BCM_WARM_BOOT_SUPPORT && INCLUDE_L3 */
    111 
    112     return rv;
    113 }
    114 
    115 /*
    116  * Function:
    117  *      bcm_esw_mcast_port_add
    118  * Purpose:
    119  *      Add ports to an existing entry in the multicast table
    120  * Parameters:
    121  *      unit - unit number.
    122  *	mcaddr - Pointer to fully filled-in bcm_mcast_addr_t
    123  * Returns:
    124  *      BCM_E_NONE
    125  *      BCM_E_INTERNAL if table write failed.
    126  */
    127 
    128 int
    129 bcm_esw_mcast_port_add(int unit, bcm_mcast_addr_t *mcaddr)
    130 {
    131     MCAST_INIT_RETURN(unit);
    132 
    133     LOG_INFO(BSL_LS_BCM_MCAST,
    134              (BSL_META_U(unit,
    135                          "MCAST %d: port add %2x:%2x:%2x:%2x:%2x:%2x, vid %d\n"),
    136               unit, mcaddr->mac[0], mcaddr->mac[1], mcaddr->mac[2],
    137               mcaddr->mac[3], mcaddr->mac[4], mcaddr->mac[5],
    138               mcaddr->vid));
    139     LOG_VERBOSE(BSL_LS_BCM_MCAST,
    140                 (BSL_META_U(unit,
    141                             "        : l2 idx %u, cos dest %d, ports 0x%x, ut 0x%x\n"),
    142                  mcaddr->l2mc_index, mcaddr->cos_dst,
    143                  SOC_PBMP_WORD_GET(mcaddr->pbmp, 0),
    144                  SOC_PBMP_WORD_GET(mcaddr->ubmp, 0)));
    145 
    146     /* Remove inactive stack ports; all from untagged */
    147     BCM_PBMP_REMOVE(mcaddr->pbmp, SOC_PBMP_STACK_INACTIVE(unit));
    148     BCM_PBMP_REMOVE(mcaddr->ubmp, SOC_PBMP_STACK_CURRENT(unit));
    149     return mbcm_driver[unit]->mbcm_mcast_port_add(unit, mcaddr);
    150 }
    151 
    152 /*
    153  * Function:
    154  *      bcm_esw_mcast_port_remove
    155  * Purpose:
    156  *      Remove ports from an existing entry in the multicast table
    157  * Parameters:
    158  *      unit - unit number.
    159  *	mcaddr - Pointer to fully filled-in bcm_mcast_addr_t
    160  * Returns:
    161  *      BCM_E_NONE
    162  *      BCM_E_INTERNAL if table write failed.
    163  */
    164 
    165 int
    166 bcm_esw_mcast_port_remove(int unit, bcm_mcast_addr_t *mcaddr)
    167 {
    168     MCAST_INIT_RETURN(unit);
    169 
    170     LOG_INFO(BSL_LS_BCM_MCAST,
    171              (BSL_META_U(unit,
    172                          "MCAST %d: port remove %2x:%2x:%2x:%2x:%2x:%2x, vid %d\n"),
    173               unit, mcaddr->mac[0], mcaddr->mac[1], mcaddr->mac[2],
    174               mcaddr->mac[3], mcaddr->mac[4], mcaddr->mac[5],
    175               mcaddr->vid));
    176     LOG_VERBOSE(BSL_LS_BCM_MCAST,
    177                 (BSL_META_U(unit,
    178                             "        : l2 idx %u, cos dest %d, ports 0x%x, ut 0x%x\n"),
    179                  mcaddr->l2mc_index, mcaddr->cos_dst,
    180                  SOC_PBMP_WORD_GET(mcaddr->pbmp, 0),
    181                  SOC_PBMP_WORD_GET(mcaddr->ubmp, 0)));
    182 
    183     /* Remove stack ports */
    184     BCM_PBMP_REMOVE(mcaddr->pbmp, SOC_PBMP_STACK_CURRENT(unit));
    185     BCM_PBMP_REMOVE(mcaddr->ubmp, SOC_PBMP_STACK_CURRENT(unit));
    186     return mbcm_driver[unit]->mbcm_mcast_port_remove(unit, mcaddr);
    187 }
    188 
    189 /* Add stack ports */
    190 
    191 STATIC void
    192 _esw_mcast_addr_update(int unit, bcm_mcast_addr_t *mcaddr)
    193 {
    194     bcm_pbmp_t active;
    195 
    196     SOC_PBMP_STACK_ACTIVE_GET(unit, active);
    197     BCM_PBMP_OR(mcaddr->pbmp, active);
    198     BCM_PBMP_REMOVE(mcaddr->ubmp, SOC_PBMP_STACK_CURRENT(unit));
    199 }
    200 
    201 /*
    202  * Function:
    203  *      _bcm_esw_mcast_convert_mcindex_m2h
    204  * Purpose:
    205  *      Convert a bcm_multicast_t l2mc index to a hardware l2mc index.
    206  * Parameters:
    207  *	mcindex - (IN/OUT) Pointer to a multicast index
    208  * Returns:
    209  *      BCM_E_NONE
    210  *      BCM_E_PARAM   If bcm_multicast_t is not L2 type 
    211  */
    212 
    213 STATIC int
    214 _bcm_esw_mcast_convert_mcindex_m2h(unsigned int *mcindex)
    215 {
    216     /* If the input parameter mc_index is a L2 type bcm_multicast_t, 
    217      * convert it to a hardware l2mc index.
    218      */
    219     if (_BCM_MULTICAST_IS_SET(*mcindex)) {
    220         if (_BCM_MULTICAST_IS_L2(*mcindex)) {
    221             *mcindex = _BCM_MULTICAST_ID_GET(*mcindex);
    222         } else {
    223             return BCM_E_PARAM;
    224         }
    225     } 
    226 
    227     return BCM_E_NONE;
    228 }
    229 
    230 /*
    231  * Function:
    232  *      _bcm_esw_mcast_convert_mcindex_h2m
    233  * Purpose:
    234  *      Convert a hardware l2mc index to a bcm_multicast_t l2mc index.
    235  * Parameters:
    236  *      unit - unit number.
    237  *	mcindex - (IN/OUT) Pointer to a multicast index 
    238  * Returns:
    239  *      None.
    240  */
    241 
    242 STATIC void
    243 _bcm_esw_mcast_convert_mcindex_h2m(int unit, unsigned int *mcindex)
    244 {
    245     if (_bcm_mcast_idx_ret_type[unit]) {
    246         /* Convert hardware l2mc index to L2 type bcm_multicast_t */
    247         _BCM_MULTICAST_GROUP_SET(*mcindex, _BCM_MULTICAST_TYPE_L2, *mcindex);
    248     }
    249 }
    250 
    251 /*
    252  * Function:
    253  *      bcm_esw_mcast_addr_add_w_l2mcindex
    254  * Purpose:
    255  *      Add an entry in the multicast table with l2mc index provided
    256  * Parameters:
    257  *      unit - unit number.
    258  *	mcaddr - Pointer to fully filled-in bcm_mcast_addr_t
    259  * Returns:
    260  *      BCM_E_NONE
    261  *      BCM_E_INTERNAL if table write failed.
    262  */
    263 
    264 int
    265 bcm_esw_mcast_addr_add_w_l2mcindex(int unit, bcm_mcast_addr_t *mcaddr)
    266 {
    267     int rv;
    268     int orig_mcindex;
    269 
    270     MCAST_INIT_RETURN(unit);
    271 
    272     LOG_INFO(BSL_LS_BCM_MCAST,
    273              (BSL_META_U(unit,
    274                          "MCAST %d: addr add w/ idx. %2x:%2x:%2x:%2x:%2x:%2x, vid %d\n"),
    275               unit, mcaddr->mac[0], mcaddr->mac[1], mcaddr->mac[2],
    276               mcaddr->mac[3], mcaddr->mac[4], mcaddr->mac[5],
    277               mcaddr->vid));
    278     LOG_VERBOSE(BSL_LS_BCM_MCAST,
    279                 (BSL_META_U(unit,
    280                             "        : l2 idx %u, cos dest %d, ports 0x%x, ut 0x%x\n"),
    281                  mcaddr->l2mc_index, mcaddr->cos_dst,
    282                  SOC_PBMP_WORD_GET(mcaddr->pbmp, 0),
    283                  SOC_PBMP_WORD_GET(mcaddr->ubmp, 0)));
    284     _esw_mcast_addr_update(unit, mcaddr);
    285 
    286     orig_mcindex = mcaddr->l2mc_index;
    287     BCM_IF_ERROR_RETURN(_bcm_esw_mcast_convert_mcindex_m2h(&mcaddr->l2mc_index));
    288 
    289     rv = mbcm_driver[unit]->mbcm_mcast_addr_add_w_l2mcindex(unit, mcaddr);
    290 
    291     /* Restore user-specified index */
    292     mcaddr->l2mc_index = orig_mcindex;
    293 
    294     return rv;
    295 }
    296 
    297 
    298 /*
    299  * Function:
    300  *      bcm_esw_mcast_addr_add
    301  * Purpose:
    302  *      Add an entry in the multicast table
    303  * Parameters:
    304  *      unit - StrataSwitch unit number.
    305  *	mcaddr - Pointer to fully filled-in bcm_mcast_addr_t
    306  * Returns:
    307  *      BCM_E_NONE
    308  *      BCM_E_INTERNAL if table write failed.
    309  */
    310 
    311 int
    312 bcm_esw_mcast_addr_add(int unit, bcm_mcast_addr_t *mcaddr)
    313 {
    314     MCAST_INIT_RETURN(unit);
    315 
    316     _esw_mcast_addr_update(unit, mcaddr);
    317     LOG_INFO(BSL_LS_BCM_MCAST,
    318              (BSL_META_U(unit,
    319                          "MCAST %d: addr add %2x:%2x:%2x:%2x:%2x:%2x, vid %d\n"),
    320               unit, mcaddr->mac[0], mcaddr->mac[1], mcaddr->mac[2],
    321               mcaddr->mac[3], mcaddr->mac[4], mcaddr->mac[5],
    322               mcaddr->vid));
    323     LOG_VERBOSE(BSL_LS_BCM_MCAST,
    324                 (BSL_META_U(unit,
    325                             "        : l2 idx %u, cos dest %d, ports 0x%x, ut 0x%x\n"),
    326                  mcaddr->l2mc_index, mcaddr->cos_dst,
    327                  SOC_PBMP_WORD_GET(mcaddr->pbmp, 0),
    328                  SOC_PBMP_WORD_GET(mcaddr->ubmp, 0)));
    329 
    330     return mbcm_driver[unit]->mbcm_mcast_addr_add(unit, mcaddr);
    331 }
    332 
    333 /*
    334  * Function:
    335  *      bcm_esw_mcast_addr_remove_w_l2mcindex
    336  * Purpose:
    337  *      Delete an entry from the multicast table and provide l2mcindex in
    338  *      bcm_mcast_addr_t of the deleted entry
    339  * Parameters:
    340  *      unit - unit number.
    341  *      mcaddr - Pointer to  filled-in bcm_mcast_addr_t with mac addr and vid
    342  *               l2mc_index is provided as output
    343  * Returns:
    344  *      BCM_E_NONE
    345  *      BCM_E_XXXX
    346  */
    347 
    348 int
    349 bcm_esw_mcast_addr_remove_w_l2mcindex(int unit, bcm_mcast_addr_t *mcaddr)
    350 {
    351     int rv;
    352     int orig_mcindex;
    353 
    354     MCAST_INIT_RETURN(unit);
    355 
    356     LOG_INFO(BSL_LS_BCM_MCAST,
    357              (BSL_META_U(unit,
    358                          "MCAST %d: addr rmv w/ idx %d\n"),
    359               unit, mcaddr->l2mc_index));
    360 
    361     orig_mcindex = mcaddr->l2mc_index;
    362     BCM_IF_ERROR_RETURN(_bcm_esw_mcast_convert_mcindex_m2h(&mcaddr->l2mc_index));
    363     
    364     rv = mbcm_driver[unit]->mbcm_mcast_addr_remove_w_l2mcindex(unit, mcaddr);
    365 
    366     /* Restore user-specified index */
    367     mcaddr->l2mc_index = orig_mcindex;
    368 
    369     return rv;
    370 }
    371 
    372 /*
    373  * Function:
    374  *      bcm_esw_mcast_addr_remove
    375  * Purpose:
    376  *      Delete an entry from the multicast table
    377  * Parameters:
    378  *      unit - StrataSwitch unit number.
    379  *      mac  - mac address
    380  *      vid  - vlan id
    381  * Returns:
    382  *      BCM_E_NONE
    383  *      BCM_E_XXXX
    384  */
    385 
    386 int
    387 bcm_esw_mcast_addr_remove(int unit, sal_mac_addr_t mac, bcm_vlan_t vid)
    388 {
    389     MCAST_INIT_RETURN(unit);
    390 
    391     LOG_INFO(BSL_LS_BCM_MCAST,
    392              (BSL_META_U(unit,
    393                          "MCAST %d: addr remove %2x:%2x:%2x:%2x:%2x:%2x, vid %d\n"),
    394               unit, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], vid));
    395 
    396     return mbcm_driver[unit]->mbcm_mcast_addr_remove(unit, mac, vid);
    397 }
    398 
    399 /*
    400  * Function:
    401  *      bcm_esw_mcast_port_get
    402  * Purpose:
    403  *      Get membership and untagged port bit maps for a MC group
    404  * Parameters:
    405  *      unit - StrataSwitch unit #.
    406  *      mac - mac address used for lookup.
    407  *      vid - vlan id used for lookup.
    408  *	mcaddr - pointer to bcm_mcast_addr_t that is fully filled in
    409  * Returns:
    410  *      BCM_E_NONE		Success (mcaddr filled in)
    411  *      BCM_E_INTERNAL		Chip access failure
    412  *	BCM_E_NOT_FOUND	Address not found (mcaddr not filled in)
    413  */
    414 
    415 int
    416 bcm_esw_mcast_port_get(int unit,
    417 		   sal_mac_addr_t mac, bcm_vlan_t vid,
    418 		   bcm_mcast_addr_t *mcaddr)
    419 {
    420     int rv;
    421 
    422     MCAST_INIT_RETURN(unit);
    423 
    424     rv = mbcm_driver[unit]->mbcm_mcast_port_get(unit, mac, vid, mcaddr);
    425 
    426     _bcm_esw_mcast_convert_mcindex_h2m(unit, &mcaddr->l2mc_index);
    427 
    428     return rv;
    429 }
    430 
    431 /*
    432  * Function:
    433  *	bcm_esw_mcast_leave
    434  * Purpose:
    435  *	This function removes the given port from the group membership
    436  *	of the given mcast mac address.
    437  * Parameters:
    438  *	unit    - device number
    439  *	mac	- Multicast MAC Address
    440  *	vlan    - Vlan ID
    441  *	port    - port to be removed from the given multicast address
    442  * Returns:
    443  *	BCM_MCAST_LEAVE_DELETED - If the entry with the given mcast
    444  *                                        addr is deleted from H/W table
    445  *	BCM_MCAST_LEAVE_UPDATED - If the mcast address is found in
    446  *                                        the table and bitmap is updated.
    447  *	BCM_MCAST_LEAVE_NOTFOUND - If the mcast address is not found in
    448  *                                         the table
    449  *	BCM_E_XXX		- an error occurred
    450  * Notes:
    451  *	BCM_MCAST_LEAVE_XXX  values are non-negative success codes
    452  */
    453 
    454 int
    455 bcm_esw_mcast_leave(int unit, bcm_mac_t mac, bcm_vlan_t vlan, bcm_port_t port)
    456 {
    457     int                 rv;
    458     bcm_mcast_addr_t	mcaddr;
    459     bcm_mcast_addr_t	rtaddr;
    460 
    461     MCAST_INIT_RETURN(unit);
    462 
    463     bcm_mcast_addr_t_init(&mcaddr, mac, vlan);
    464     if (BCM_GPORT_IS_SET(port)) {
    465         BCM_IF_ERROR_RETURN(bcm_esw_port_local_get(unit, port, &port));
    466     }
    467 
    468     BCM_PBMP_PORT_SET(mcaddr.pbmp, port);
    469     BCM_IF_ERROR_RETURN(bcm_esw_mcast_port_remove(unit, &mcaddr));
    470     BCM_IF_ERROR_RETURN(bcm_esw_mcast_port_get(unit, mac, vlan, &mcaddr));
    471 
    472     if (SOC_MCAST_ADD_ALL_ROUTER_PORTS(unit)) {
    473         rv = bcm_esw_mcast_port_get(unit, (uint8 *)_soc_mac_all_routers, vlan,
    474                                     &rtaddr);
    475         if (rv < 0) {
    476             bcm_mcast_addr_t_init(&rtaddr, (uint8 *)_soc_mac_all_routers, vlan);
    477         }
    478         /* Coverity: rtaddr.pbmp is initialized above by bcm_esw_mcast_port_get */
    479         /* coverity[uninit_use : FALSE] */
    480         BCM_PBMP_REMOVE(mcaddr.pbmp, rtaddr.pbmp);
    481     }
    482 
    483     
    484     if (BCM_PBMP_IS_NULL(mcaddr.pbmp)) {
    485 	BCM_IF_ERROR_RETURN(bcm_esw_mcast_addr_remove(unit, mac, vlan));
    486         return BCM_MCAST_LEAVE_DELETED;
    487     }
    488     return BCM_MCAST_LEAVE_UPDATED;
    489 }
    490 
    491 /*
    492  * Function:
    493  *	bcm_esw_mcast_join
    494  * Purpose:
    495  *	This function adds the given port to the membership of the
    496  *	given mcast mac address.
    497  * Parameters:
    498  *	unit	- device number
    499  *	mac	- Multicast MAC Address
    500  *	vlan    - Vlan ID
    501  *	port    - port to be added to the mulicast address
    502  *	mcaddr	- (OUT) If not NULL, returns the updated mcast_addr_t for
    503  *		  the given multicast address
    504  *	all_router_pbmp - (OUT) If not NULL, returns the ports associated with
    505  *			the all routers multicast address
    506  *
    507  * Returns:
    508  *	BCM_MCAST_JOIN_ADDED - If a new entry is created for the
    509  *                                     given mcast address.
    510  *	BCM_MCAST_JOIN_UPDATED - If the mcast address is found in
    511  *                                       the table and bitmap is updated.
    512  *	BCM_E_XXX		- an error occurred
    513  * Notes:
    514  *	BCM_MCAST_JOIN_XXX values are non-negative success codes
    515  */
    516 
    517 int
    518 bcm_esw_mcast_join(int unit, bcm_mac_t mac, bcm_vlan_t vlan, bcm_port_t port,
    519 	       bcm_mcast_addr_t *mcaddr,
    520 	       bcm_pbmp_t *all_router_pbmp)
    521 {
    522     int                 rv;
    523     bcm_mcast_addr_t	newmc;
    524 
    525     MCAST_INIT_RETURN(unit);
    526 
    527     /*
    528      * Fill in all_routers port bitmap
    529      */
    530     if (all_router_pbmp != NULL) {
    531 	rv = bcm_esw_mcast_port_get(unit, (uint8 *)_soc_mac_all_routers, vlan,
    532                                     &newmc);
    533         if (rv == BCM_E_NOT_FOUND) {
    534 	    BCM_PBMP_CLEAR(*all_router_pbmp);
    535         } else if (rv < 0) {
    536             return rv;
    537         } else {
    538             /* Coverity: newmc.pbmp is initialized above by bcm_esw_mcast_port_get */
    539             /* coverity[uninit_use : FALSE] */
    540 	    BCM_PBMP_ASSIGN(*all_router_pbmp, newmc.pbmp);
    541         }
    542     }
    543 
    544     /*
    545      * Now, join the actual multicast group
    546      */
    547     bcm_mcast_addr_t_init(&newmc, mac, vlan);
    548     if (BCM_GPORT_IS_SET(port)) {
    549         BCM_IF_ERROR_RETURN(bcm_esw_port_local_get(unit, port, &port));
    550     }
    551     
    552     BCM_PBMP_PORT_SET(newmc.pbmp, port);
    553     rv = bcm_esw_mcast_port_add(unit, &newmc);
    554 
    555     if (rv == BCM_E_NOT_FOUND) {
    556 	BCM_IF_ERROR_RETURN(bcm_esw_mcast_addr_add(unit, &newmc));
    557         rv = BCM_MCAST_JOIN_ADDED;
    558     } else if (rv < 0) {
    559 	return rv;
    560     } else {
    561 	rv = BCM_MCAST_JOIN_UPDATED;
    562     }
    563     if (mcaddr != NULL) {
    564 	BCM_IF_ERROR_RETURN(bcm_esw_mcast_port_get(unit, mac, vlan, mcaddr));
    565     }
    566     return rv;
    567 }
    568 
    569 /*
    570  * Function:	bcm_mcast_bitmap_max_get
    571  * Purpose:	provides maximum mcast index that this fabric can handle
    572  * Parameters:	unit		- device
    573  *		max_index	- (OUT) returned number of entries
    574  * Returns:	BCM_E_*
    575  * Note:
    576  * 	Fabric only
    577  */
    578 int
    579 bcm_esw_mcast_bitmap_max_get(int unit, int *max_index)
    580 {
    581 #ifdef	BCM_XGS12_FABRIC_SUPPORT
    582     if (SOC_IS_XGS12_FABRIC(unit)) {
    583 	*max_index = soc_mem_index_count(unit, MEM_MCm);
    584 	return BCM_E_NONE;
    585     }
    586 #endif	/* BCM_XGS12_FABRIC_SUPPORT */
    587 
    588 #ifdef	BCM_XGS3_FABRIC_SUPPORT
    589     if (SOC_IS_XGS3_FABRIC(unit)) {
    590 	int	mc_base, mc_size;
    591 
    592 	SOC_IF_ERROR_RETURN
    593 	    (soc_hbx_mcast_size_get(unit, &mc_base, &mc_size));
    594 	*max_index = mc_size;
    595 	return BCM_E_NONE;
    596     }
    597 #endif	/* BCM_XGS3_FABRIC_SUPPORT */
    598 
    599     *max_index = 0;
    600     return BCM_E_UNAVAIL;
    601 }
    602 
    603 /*
    604  * Function:
    605  *     bcm_esw_mcast_bitmap_set
    606  * Purpose:
    607  *     Set the L2 MC forwarding port bitmap
    608  * Parameters:
    609  *     unit     - SOC unit #
    610  *     index    - the MC index carried in HiGig header
    611  *     in_port  - ingress port number
    612  *     pbmp     - IPMC forwarding port bitmap
    613  * Returns:
    614  *     BCM_E_XXX
    615  * Note:
    616  *	Fabric only
    617  */
    618 int
    619 bcm_esw_mcast_bitmap_set(int unit, int index, bcm_port_t in_port, bcm_pbmp_t pbmp)
    620 {
    621 #ifdef	BCM_XGS12_FABRIC_SUPPORT
    622     if (SOC_IS_XGS12_FABRIC(unit)) {
    623 	mem_mc_entry_t      entry;
    624 	int                 blk, rv;
    625 
    626     if (BCM_GPORT_IS_SET(in_port)) {
    627         BCM_IF_ERROR_RETURN(bcm_esw_port_local_get(unit, in_port, &in_port));
    628     }
    629 	if (!SOC_PORT_VALID(unit, in_port)) {
    630 	    return BCM_E_PORT;
    631 	}
    632 	if (index < 0 || index > soc_mem_index_max(unit, MEM_MCm)) {
    633 	    return BCM_E_PARAM;
    634 	}
    635 
    636 	/* Make sure packet never goes back */
    637 	BCM_PBMP_PORT_REMOVE(pbmp, in_port);
    638 
    639 	blk = SOC_PORT_BLOCK(unit, in_port);
    640 
    641 	sal_memset(&entry, 0, sizeof(entry));
    642 
    643 	soc_mem_lock(unit, MEM_MCm);
    644 	rv = READ_MEM_MCm(unit, blk, index, &entry);
    645 	if (rv >= 0) {
    646 	    soc_MEM_MCm_field32_set(unit, &entry, MCBITMAPf,
    647 				    SOC_PBMP_WORD_GET(pbmp, 0));
    648 	    rv = WRITE_MEM_MCm(unit, blk, index, &entry);
    649 	}
    650 	soc_mem_unlock(unit, MEM_MCm);
    651 
    652 	return rv;
    653     }
    654 #endif	/* BCM_XGS12_FABRIC_SUPPORT */
    655 
    656 #ifdef	BCM_XGS3_FABRIC_SUPPORT
    657     if (SOC_IS_XGS3_FABRIC(unit)) {
    658 	int		rv, mc_base, mc_size;
    659 	l2mc_entry_t	l2mc;
    660 
    661 	COMPILER_REFERENCE(in_port);
    662 
    663         BCM_IF_ERROR_RETURN(_bcm_esw_mcast_convert_mcindex_m2h((unsigned int*)&index));
    664 
    665 	SOC_IF_ERROR_RETURN
    666 	    (soc_hbx_mcast_size_get(unit, &mc_base, &mc_size));
    667 	if (index < 0 || index > mc_size) {
    668 	    return BCM_E_PARAM;
    669 	}
    670 	index += mc_base;
    671 
    672 	soc_mem_lock(unit, L2MCm);
    673         rv = READ_L2MCm(unit, MEM_BLOCK_ANY, index, &l2mc);
    674 	if (rv >= 0) {
    675             soc_mem_pbmp_field_set(unit, L2MCm, &l2mc, PORT_BITMAPf, &pbmp);
    676 	    soc_mem_field32_set(unit, L2MCm, &l2mc, VALIDf, 1);
    677 	    rv = WRITE_L2MCm(unit, MEM_BLOCK_ALL, index, &l2mc);
    678 	}
    679 	soc_mem_unlock(unit, L2MCm);
    680 	return rv;
    681     }
    682 #endif	/* BCM_XGS3_FABRIC_SUPPORT */
    683 
    684     return BCM_E_UNAVAIL;
    685 }
    686 
    687 /*
    688  * Function:
    689  *     bcm_esw_mcast_bitmap_get
    690  * Purpose:
    691  *     Get the L2 MC forwarding port bitmap
    692  * Parameters:
    693  *     unit    - SOC unit #
    694  *     index   - the L2 MC index carried in HiGig header
    695  *     in_port - ingress port number
    696  *     pbmp    - IPMC forwarding port bitmap
    697  * Returns:
    698  *     BCM_E_xxxx
    699  * Note:
    700  * 	Fabric only
    701  */
    702 int
    703 bcm_esw_mcast_bitmap_get(int unit, int index, bcm_port_t in_port,
    704 		     bcm_pbmp_t *pbmp)
    705 {
    706 #ifdef	BCM_XGS12_FABRIC_SUPPORT
    707 
    708     if (SOC_IS_XGS12_FABRIC(unit)) {
    709 	mem_mc_entry_t	entry;
    710 	int		blk;
    711 	uint32		pword;
    712 
    713     if (BCM_GPORT_IS_SET(in_port)) {
    714         BCM_IF_ERROR_RETURN(bcm_esw_port_local_get(unit, in_port, &in_port));
    715     }
    716 	if (!SOC_PORT_VALID(unit, in_port)) {
    717 	    return BCM_E_PORT;
    718 	}
    719 	if (index < 0 || index > soc_mem_index_max(unit, MEM_MCm)) {
    720 	    return BCM_E_PARAM;
    721 	}
    722 
    723 	blk = SOC_PORT_BLOCK(unit, in_port);
    724 	SOC_IF_ERROR_RETURN(READ_MEM_MCm(unit, blk, index, &entry));
    725 	pword = soc_MEM_MCm_field32_get(unit, &entry, MCBITMAPf);
    726 	SOC_PBMP_CLEAR(*pbmp);
    727 	SOC_PBMP_WORD_SET(*pbmp, 0, pword);
    728 	return BCM_E_NONE;
    729     }
    730 #endif	/* BCM_XGS12_FABRIC_SUPPORT */
    731 
    732 #ifdef	BCM_XGS3_FABRIC_SUPPORT
    733     if (SOC_IS_XGS3_FABRIC(unit)) {
    734 	int		mc_base, mc_size;
    735 	l2mc_entry_t	l2mc;
    736 
    737 	COMPILER_REFERENCE(in_port);
    738 
    739         BCM_IF_ERROR_RETURN(_bcm_esw_mcast_convert_mcindex_m2h((unsigned int*)&index));
    740 
    741 	SOC_IF_ERROR_RETURN
    742 	    (soc_hbx_mcast_size_get(unit, &mc_base, &mc_size));
    743 	if (index < 0 || index > mc_size) {
    744 	    return BCM_E_PARAM;
    745 	}
    746 	index += mc_base;
    747 
    748         SOC_IF_ERROR_RETURN(READ_L2MCm(unit, MEM_BLOCK_ANY, index, &l2mc));
    749         soc_mem_pbmp_field_get(unit, L2MCm, &l2mc, PORT_BITMAPf, pbmp);
    750 	return BCM_E_NONE;
    751     }
    752 #endif	/* BCM_XGS3_FABRIC_SUPPORT */
    753 
    754     return BCM_E_UNAVAIL;
    755 }
    756 
    757 /*
    758  * Function:
    759  *     bcm_esw_mcast_bitmap_del
    760  * Purpose:
    761  *     Remove L2 MC forwarding port bitmap
    762  * Parameters:
    763  *     unit     - SOC unit #
    764  *     index    - the L2 MC index carried in HiGig header
    765  *     in_port  - ingress port number
    766  *     pbmp     - IPMC forwarding port bitmap
    767  * Returns:
    768  *     BCM_E_xxxx
    769  * Note:
    770  * 	Fabric only
    771  */
    772 int
    773 bcm_esw_mcast_bitmap_del(int unit, int index, bcm_port_t in_port, bcm_pbmp_t pbmp)
    774 {
    775 #ifdef	BCM_XGS12_FABRIC_SUPPORT
    776     if (SOC_IS_XGS12_FABRIC(unit)) {
    777 	mem_mc_entry_t      entry;
    778 	uint32              pword;
    779 	int                 rv, blk;
    780 
    781     if (BCM_GPORT_IS_SET(in_port)) {
    782         BCM_IF_ERROR_RETURN(bcm_esw_port_local_get(unit, in_port, &in_port));
    783     }
    784 	if (!SOC_PORT_VALID(unit, in_port)) {
    785 	    return BCM_E_PORT;
    786 	}
    787 	if (index < 0 || index > soc_mem_index_max(unit, MEM_MCm)) {
    788 	    return BCM_E_PARAM;
    789 	}
    790 
    791 	blk = SOC_PORT_BLOCK(unit, in_port);
    792 
    793 	soc_mem_lock(unit, MEM_MCm);
    794 
    795 	rv = READ_MEM_MCm(unit, blk, index, &entry);
    796 	if (rv >= 0) {
    797 	    pword = soc_MEM_MCm_field32_get(unit, &entry, MCBITMAPf);
    798 	    pword &= ~SOC_PBMP_WORD_GET(pbmp, 0);
    799 	    soc_MEM_MCm_field32_set(unit, &entry, MCBITMAPf, pword);
    800 	    rv = WRITE_MEM_MCm(unit, blk, index, &entry);
    801 	}
    802 
    803 	soc_mem_unlock(unit, MEM_MCm);
    804 
    805 	return rv;
    806     }
    807 #endif	/* BCM_XGS12_FABRIC_SUPPORT */
    808 
    809 #ifdef	BCM_XGS3_FABRIC_SUPPORT
    810     if (SOC_IS_XGS3_FABRIC(unit)) {
    811 	int		rv, mc_base, mc_size;
    812 	l2mc_entry_t	l2mc;
    813         bcm_pbmp_t      tmp_pbmp;
    814 
    815 	COMPILER_REFERENCE(in_port);
    816 
    817         BCM_IF_ERROR_RETURN(_bcm_esw_mcast_convert_mcindex_m2h((unsigned int*)&index));
    818 
    819 	SOC_IF_ERROR_RETURN
    820 	    (soc_hbx_mcast_size_get(unit, &mc_base, &mc_size));
    821 	if (index < 0 || index > mc_size) {
    822 	    return BCM_E_PARAM;
    823 	}
    824 	index += mc_base;
    825 
    826 	soc_mem_lock(unit, L2MCm);
    827         rv = READ_L2MCm(unit, MEM_BLOCK_ANY, index, &l2mc);
    828 	if (rv >= 0) {
    829             soc_mem_pbmp_field_get(unit, L2MCm, &l2mc, PORT_BITMAPf,
    830                                    &tmp_pbmp);
    831             SOC_PBMP_REMOVE(tmp_pbmp, pbmp);
    832             soc_mem_pbmp_field_set(unit, L2MCm, &l2mc, PORT_BITMAPf,
    833                                    &tmp_pbmp);
    834 	    soc_mem_field32_set(unit, L2MCm, &l2mc, VALIDf, 1);
    835 	    rv = WRITE_L2MCm(unit, MEM_BLOCK_ALL, index, &l2mc);
    836 	}
    837 	soc_mem_unlock(unit, L2MCm);
    838 	return rv;
    839     }
    840 #endif	/* BCM_XGS3_FABRIC_SUPPORT */
    841 
    842     return BCM_E_UNAVAIL;
    843 }
    844 
    845 STATIC int
    846 _xgs12_mcast_stk_update(int unit, bcm_pbmp_t add_ports,
    847                       bcm_pbmp_t remove_ports)
    848 {
    849     int rv = BCM_E_NONE;  /* Ignore if unavailable */
    850 
    851 #if defined(BCM_XGS12_SWITCH_SUPPORT)
    852     int i;
    853     bcm_pbmp_t new_ports, old_ports;
    854     l2x_mc_entry_t l2mc;
    855     int changed = 0;
    856 
    857     soc_mem_lock(unit, L2X_MCm);
    858     for (i = soc_mem_index_min(unit, L2X_MCm);
    859              i <= soc_mem_index_max(unit, L2X_MCm);
    860              i++) {
    861 
    862         rv = soc_mem_read(unit, L2X_MCm, MEM_BLOCK_ANY, i, &l2mc);
    863         if (rv < 0) {
    864             break;
    865         }
    866         if (soc_L2X_MCm_field32_get(unit, &l2mc, VALIDf) == 0) {
    867             continue;
    868         }
    869         _bcm_l2mcentry_pbmp_get(unit, &l2mc, &old_ports);
    870         BCM_PBMP_ASSIGN(new_ports, old_ports);
    871         BCM_PBMP_OR(new_ports, add_ports);
    872         BCM_PBMP_REMOVE(new_ports, remove_ports);
    873         if (BCM_PBMP_NEQ(new_ports, old_ports)) {
    874             ++changed;
    875             _bcm_l2mcentry_pbmp_set(unit, &l2mc, new_ports);
    876             rv = soc_mem_write(unit, L2X_MCm, MEM_BLOCK_ALL, i, &l2mc);
    877             if (rv < 0) {
    878                 break;
    879             }
    880         }
    881     }
    882     soc_mem_unlock(unit, L2X_MCm);
    883 
    884     if (changed) {
    885         LOG_VERBOSE(BSL_LS_BCM_MCAST,
    886                     (BSL_META_U(unit,
    887                                 "L2MC %d: xgs stk update changed %d entries\n"),
    888                      unit, changed));
    889     }
    890 #endif
    891 
    892     return rv;
    893 }
    894 
    895 STATIC int
    896 _xgs3_fb_mcast_stk_update(int unit, bcm_pbmp_t add_ports,
    897                        bcm_pbmp_t remove_ports)
    898 {
    899     int rv = BCM_E_NONE;  /* Ignore if unavailable */
    900 
    901 #if defined(BCM_FIREBOLT_SUPPORT)
    902     int i;
    903     bcm_pbmp_t new_ports, old_ports;
    904     l2mc_entry_t l2mc;
    905     int changed = 0;
    906 
    907     soc_mem_lock(unit, L2MCm);
    908     for (i = soc_mem_index_min(unit, L2MCm);
    909              i <= soc_mem_index_max(unit, L2MCm);
    910              i++) {
    911 
    912         rv = soc_mem_read(unit, L2MCm, MEM_BLOCK_ANY, i, &l2mc);
    913         if (rv < 0) {
    914             break;
    915         }
    916         if (soc_L2MCm_field32_get(unit, &l2mc, VALIDf) == 0) {
    917             continue;
    918         }
    919         soc_mem_pbmp_field_get(unit, L2MCm, &l2mc, PORT_BITMAPf, &old_ports);
    920         BCM_PBMP_ASSIGN(new_ports, old_ports);
    921         BCM_PBMP_OR(new_ports, add_ports);
    922         BCM_PBMP_REMOVE(new_ports, remove_ports);
    923         if (BCM_PBMP_NEQ(new_ports, old_ports)) {
    924             ++changed;
    925             soc_mem_pbmp_field_set(unit, L2MCm, &l2mc, PORT_BITMAPf,
    926                                    &new_ports);
    927             rv = soc_mem_write(unit, L2MCm, MEM_BLOCK_ALL, i, &l2mc);
    928             if (rv < 0) {
    929                 break;
    930             }
    931         }
    932     }
    933     soc_mem_unlock(unit, L2MCm);
    934 
    935     if (changed) {
    936         LOG_VERBOSE(BSL_LS_BCM_MCAST,
    937                     (BSL_META_U(unit,
    938                                 "L2MC %d: xgs stk update changed %d entries\n"),
    939                      unit, changed));
    940     }
    941 #endif
    942 
    943     return rv;
    944 }
    945 
    946 /*
    947  * Function:
    948  *      _bcm_esw_mcast_stk_update
    949  * Purpose:
    950  *      Update port bitmaps after stack change
    951  * Parameters:
    952  *      
    953  * Returns:
    954  *      BCM_E_XXX
    955  * Notes:
    956  */
    957 
    958 
    959 int
    960 _bcm_esw_mcast_stk_update(int unit, uint32 flags)
    961 {
    962     bcm_pbmp_t add_ports, remove_ports;
    963     int rv = BCM_E_NONE;
    964 
    965     /* Calculate ports that should and should not be in bitmap */
    966     SOC_PBMP_ASSIGN(add_ports, SOC_PBMP_STACK_CURRENT(unit));
    967     SOC_PBMP_REMOVE(add_ports, SOC_PBMP_STACK_INACTIVE(unit));
    968 
    969     /* Remove ports no longer stacking, or explicitly inactive */
    970     SOC_PBMP_ASSIGN(remove_ports, SOC_PBMP_STACK_PREVIOUS(unit));
    971     SOC_PBMP_REMOVE(remove_ports, SOC_PBMP_STACK_CURRENT(unit));
    972     SOC_PBMP_OR(remove_ports, SOC_PBMP_STACK_INACTIVE(unit));
    973 
    974     if (SOC_IS_XGS12_SWITCH(unit)) {
    975         rv = _xgs12_mcast_stk_update(unit, add_ports, remove_ports);
    976     } else if (SOC_IS_XGS3_SWITCH(unit)) {
    977         rv = _xgs3_fb_mcast_stk_update(unit, add_ports, remove_ports);
    978     } else { /* May update fabric in the future, but not needed yet */
    979         rv = BCM_E_NONE; /* Ignore if unavailable */
    980     }
    981 
    982     return rv;
    983 }
    984 
    985 #ifdef BCM_WARM_BOOT_SUPPORT
    986 int
    987 _bcm_mcast_cleanup(int unit)
    988 {
    989     int rv = BCM_E_NONE;
    990   	 
    991 #ifdef BCM_XGS3_SWITCH_SUPPORT
    992     if (SOC_IS_FB_FX_HX(unit)) {
    993         rv = _bcm_xgs3_mcast_detach(unit);
    994     }
    995 #endif
    996     return rv;
    997 }
    998 #endif /* BCM_WARM_BOOT_SUPPORT */
    999 
   1000 #ifndef BCM_SW_STATE_DUMP_DISABLE
   1001 /*
   1002  * Function:
   1003  *     _bcm_mcast_sw_dump
   1004  * Purpose:
   1005  *     Displays mcast information maintained by software.
   1006  * Parameters:
   1007  *     unit - Device unit number
   1008  * Returns:
   1009  *     None
   1010  */
   1011 void
   1012 _bcm_mcast_sw_dump(int unit)
   1013 {
   1014 
   1015     LOG_CLI((BSL_META_U(unit,
   1016                         "\nSW Information MCAST - Unit %d\n"), unit));
   1017     LOG_CLI((BSL_META_U(unit,
   1018                         "    Init : %d\n"), _bcm_mcast_init[unit]));
   1019     LOG_CLI((BSL_META_U(unit,
   1020                         "    Multicast Index Return Type : %d\n"), _bcm_mcast_idx_ret_type[unit]));
   1021 
   1022 #ifdef BCM_XGS3_SWITCH_SUPPORT
   1023     if (SOC_IS_XGS3_SWITCH(unit)) {
   1024         _bcm_xgs3_mcast_sw_dump(unit);
   1025     }
   1026 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   1027 
   1028     LOG_CLI((BSL_META_U(unit,
   1029                         "\n")));
   1030 
   1031     return;
   1032 }
   1033 #endif /* BCM_SW_STATE_DUMP_DISABLE */
   1034 
   1035 /*
   1036  * Function:
   1037  *      _bcm_esw_mcast_idx_ret_type_set
   1038  * Purpose:
   1039  *      Set multicast index return type.
   1040  * Parameters:
   1041  *      unit - StrataSwitch unit #
   1042  *      arg - 0 means hardware multicast index, 1 means bcm_multicast_t
   1043  * Returns:
   1044  *      BCM_E_NONE 
   1045  *      BCM_E_UNAVAIL
   1046  */
   1047 
   1048 int
   1049 _bcm_esw_mcast_idx_ret_type_set(int unit, int arg)
   1050 {
   1051     if (SOC_IS_XGS3_SWITCH(unit)) {
   1052         MCAST_INIT_RETURN(unit);
   1053         _bcm_mcast_idx_ret_type[unit] = arg;
   1054 
   1055 #if defined(BCM_WARM_BOOT_SUPPORT) && defined(INCLUDE_L3)
   1056         /* Record this value in HW for Warm Boot recovery. */
   1057         BCM_IF_ERROR_NOT_UNAVAIL_RETURN
   1058             (_bcm_esw_ipmc_repl_wb_flags_set(unit,
   1059                   (arg ? _BCM_IPMC_WB_L2MC_GROUP_TYPE_MULTICAST : 0),
   1060                          _BCM_IPMC_WB_L2MC_GROUP_TYPE_MULTICAST));
   1061 #endif /* BCM_WARM_BOOT_SUPPORT && INCLUDE_L3 */
   1062         
   1063         return BCM_E_NONE;
   1064     }
   1065 
   1066     return BCM_E_UNAVAIL;
   1067 }
   1068 
   1069 /*
   1070  * Function:
   1071  *      _bcm_esw_mcast_idx_ret_type_get
   1072  * Purpose:
   1073  *      Get multicast index return type.
   1074  * Parameters:
   1075  *      unit - StrataSwitch unit #
   1076  *      arg - Pointer to where retrieved value will be written
   1077  * Returns:
   1078  *      BCM_E_NONE 
   1079  *      BCM_E_UNAVAIL
   1080  */
   1081 
   1082 int
   1083 _bcm_esw_mcast_idx_ret_type_get(int unit, int *arg)
   1084 {
   1085     if (SOC_IS_XGS3_SWITCH(unit)) {
   1086         MCAST_INIT_RETURN(unit);
   1087         *arg = _bcm_mcast_idx_ret_type[unit];
   1088         return BCM_E_NONE;
   1089     }
   1090 
   1091     return BCM_E_UNAVAIL;
   1092 }
   1093