openbcm

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

ipmc.c (70559B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:        ipmc.c
      8  * Purpose:     Trident2 PIM-BIDIR implementation.
      9  */
     10 
     11 #include <soc/defs.h>
     12 #include <sal/core/libc.h>
     13 #include <shared/bsl.h>
     14 #if defined(BCM_TRIDENT2_SUPPORT) && defined(INCLUDE_L3)
     15 
     16 #include <soc/drv.h>
     17 #include <soc/profile_mem.h>
     18 
     19 #include <bcm/error.h>
     20 #include <bcm/ipmc.h>
     21 #include <bcm/l3.h>
     22 
     23 #include <bcm_int/esw/trident2.h>
     24 
     25 typedef struct _bcm_td2_l3_iif_s {
     26     bcm_if_t l3_iif;
     27     struct _bcm_td2_l3_iif_s *next;
     28 } _bcm_td2_l3_iif_t;
     29 
     30 typedef struct _bcm_td2_rp_s {
     31     int valid; /* Indicates if this rendezvous point is valid */
     32     int ref_count; /* Number of IPMC entries referring to
     33                       this rendezvous point */
     34     _bcm_td2_l3_iif_t *l3_iif_list; /* Linked list of active L3 IIFs
     35                                        belonging to this rendezvous point */
     36 } _bcm_td2_rp_t;
     37 
     38 typedef struct _bcm_td2_pim_bidir_s {
     39     int num_rp; /* Number of rendezvous points */
     40     _bcm_td2_rp_t *rp_info; /* Rendezvous points info */
     41     soc_profile_mem_t *active_l3_iif_profile; /* Active L3 IIF profile */
     42     SHR_BITDCL *ipmc_tcam_bitmap; /* Bitmap of valid IPMC TCAM entries */
     43 } _bcm_td2_pim_bidir_t;
     44 
     45 STATIC _bcm_td2_pim_bidir_t *_bcm_td2_pim_bidir_info[BCM_MAX_NUM_UNITS];
     46 
     47 #define IPMC_NUM_RP(unit) \
     48         (_bcm_td2_pim_bidir_info[unit]->num_rp)
     49 
     50 #define IPMC_RP_INFO(unit, rp_id) \
     51         (&_bcm_td2_pim_bidir_info[unit]->rp_info[rp_id])
     52 
     53 #define IPMC_ACTIVE_L3_IIF_PROFILE(unit) \
     54         (_bcm_td2_pim_bidir_info[unit]->active_l3_iif_profile)
     55 
     56 #define IPMC_TCAM_BITMAP(unit) \
     57         (_bcm_td2_pim_bidir_info[unit]->ipmc_tcam_bitmap)
     58 
     59 #ifdef BCM_WARM_BOOT_SUPPORT
     60 STATIC int _bcm_td2_ipmc_pim_bidir_recover(int unit);
     61 #endif /* BCM_WARM_BOOT_SUPPORT */
     62 
     63 /*
     64  * Function:
     65  *      bcm_td2_ipmc_pim_bidir_detach
     66  * Purpose:
     67  *      Free data structures related to PIM-BIDIR.
     68  * Parameters:
     69  *      unit - StrataSwitch unit #
     70  * Returns:
     71  *      BCM_E_xxx
     72  */
     73 int 
     74 bcm_td2_ipmc_pim_bidir_detach(int unit)
     75 {
     76     int rv = BCM_E_NONE;
     77     _bcm_td2_pim_bidir_t *pim_bidir_info = NULL;
     78     int i;
     79     _bcm_td2_l3_iif_t *current_ptr, *next_ptr;
     80 
     81     if (NULL != _bcm_td2_pim_bidir_info[unit]) {
     82         pim_bidir_info = _bcm_td2_pim_bidir_info[unit];
     83 
     84         /* Free rendezvous point info array */
     85         if (NULL != pim_bidir_info->rp_info) {
     86             for (i = 0; i < pim_bidir_info->num_rp; i++) {
     87                 /* Free linked list of active L3 IIFs */
     88                 current_ptr = pim_bidir_info->rp_info[i].l3_iif_list;
     89                 while (NULL != current_ptr) {
     90                     next_ptr = current_ptr->next;
     91                     sal_free(current_ptr);
     92                     current_ptr = next_ptr;
     93                 }
     94                 pim_bidir_info->rp_info[i].l3_iif_list = NULL;
     95             }
     96             sal_free(pim_bidir_info->rp_info);
     97             pim_bidir_info->rp_info = NULL;
     98         }
     99 
    100         if (NULL != pim_bidir_info->active_l3_iif_profile) {
    101             (void) soc_profile_mem_destroy(unit,
    102                     pim_bidir_info->active_l3_iif_profile);
    103             sal_free(pim_bidir_info->active_l3_iif_profile);
    104             pim_bidir_info->active_l3_iif_profile = NULL;
    105         }
    106 
    107         if (NULL != pim_bidir_info->ipmc_tcam_bitmap) {
    108             sal_free(pim_bidir_info->ipmc_tcam_bitmap);
    109             pim_bidir_info->ipmc_tcam_bitmap = NULL;
    110         }
    111 
    112         sal_free(_bcm_td2_pim_bidir_info[unit]);
    113         _bcm_td2_pim_bidir_info[unit] = NULL;
    114     }
    115 
    116     return rv;
    117 }
    118 
    119 /*
    120  * Function:
    121  *      bcm_td2_ipmc_pim_bidir_init
    122  * Purpose:
    123  *      Initialize data structures related to PIM-BIDIR.
    124  * Parameters:
    125  *      unit - StrataSwitch unit #
    126  * Returns:
    127  *      BCM_E_xxx
    128  */
    129 int 
    130 bcm_td2_ipmc_pim_bidir_init(int unit)
    131 {
    132     int rv = BCM_E_NONE;
    133     _bcm_td2_pim_bidir_t *pim_bidir_info = NULL;
    134     soc_mem_t profile_mem;
    135     int entry_words;
    136     void *entry_ptr;
    137     uint32 profile_index;
    138     int ipmc_tcam_bitmap_length;
    139     int i;
    140     iif_entry_t *l3_iif_entry;
    141     uint8 *mbuf;
    142 
    143     if (NULL == _bcm_td2_pim_bidir_info[unit]) {
    144         _bcm_td2_pim_bidir_info[unit] = sal_alloc(sizeof(_bcm_td2_pim_bidir_t),
    145                 "PIM BIDIR info");
    146         if (NULL == _bcm_td2_pim_bidir_info[unit]) {
    147             bcm_td2_ipmc_pim_bidir_detach(unit);
    148             return BCM_E_MEMORY;
    149         }
    150     }
    151     sal_memset(_bcm_td2_pim_bidir_info[unit], 0, sizeof(_bcm_td2_pim_bidir_t));
    152     pim_bidir_info = _bcm_td2_pim_bidir_info[unit];
    153 
    154     /* Allocate an array to keep track of rendezvous point info */
    155     pim_bidir_info->num_rp = soc_mem_field_length(unit,
    156             ING_ACTIVE_L3_IIF_PROFILEm, RPA_ID_PROFILEf);
    157     pim_bidir_info->rp_info = sal_alloc(pim_bidir_info->num_rp *
    158             sizeof(_bcm_td2_rp_t), "RP info array");
    159     if (NULL == pim_bidir_info->rp_info) {
    160         bcm_td2_ipmc_pim_bidir_detach(unit);
    161         return BCM_E_MEMORY;
    162     }
    163     sal_memset(pim_bidir_info->rp_info, 0,
    164             pim_bidir_info->num_rp * sizeof(_bcm_td2_rp_t));
    165 
    166     /* Allocate active L3 IIF profile */
    167     pim_bidir_info->active_l3_iif_profile =
    168         sal_alloc(sizeof(soc_profile_mem_t), "Active L3 IIF Profile");
    169     if (NULL == pim_bidir_info->active_l3_iif_profile) {
    170         bcm_td2_ipmc_pim_bidir_detach(unit);
    171         return BCM_E_MEMORY;
    172     }
    173     soc_profile_mem_t_init(pim_bidir_info->active_l3_iif_profile);
    174 
    175     /* Initialize the active L3 IIF profile */
    176     profile_mem = ING_ACTIVE_L3_IIF_PROFILEm;
    177     entry_words = sizeof(ing_active_l3_iif_profile_entry_t) / sizeof(uint32);
    178     rv = soc_profile_mem_create(unit, &profile_mem, &entry_words, 1,
    179                                 pim_bidir_info->active_l3_iif_profile);
    180     if (BCM_FAILURE(rv)) {
    181         bcm_td2_ipmc_pim_bidir_detach(unit);
    182         return rv;
    183     }
    184 
    185     if (!SOC_WARM_BOOT(unit)) {
    186         /* Initially, all L3_IIF entries point to an active L3 IIF profile
    187          * that contains no valid rendezvous points.
    188          */ 
    189         entry_ptr = soc_mem_entry_null(unit, ING_ACTIVE_L3_IIF_PROFILEm);
    190         rv = soc_profile_mem_add(unit, pim_bidir_info->active_l3_iif_profile,
    191                 &entry_ptr, 1, &profile_index);
    192         if (BCM_FAILURE(rv)) {
    193             bcm_td2_ipmc_pim_bidir_detach(unit);
    194             return rv;
    195         }
    196         /* If the default HW value is same to profile index, skip it */
    197         if (!(SOC_HW_RESET(unit) && profile_index == 0)) {
    198              /* Program the table */
    199             mbuf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, L3_IIFm),
    200                                  "L3_iif");
    201             if (NULL == mbuf) {
    202                 bcm_td2_ipmc_pim_bidir_detach(unit);
    203                 return BCM_E_MEMORY;
    204             }
    205             rv = soc_mem_read_range(unit, L3_IIFm, MEM_BLOCK_ANY,
    206                                     soc_mem_index_min(unit, L3_IIFm),
    207                                     soc_mem_index_max(unit, L3_IIFm),
    208                                     mbuf);
    209             if (BCM_FAILURE(rv)) {
    210                 bcm_td2_ipmc_pim_bidir_detach(unit);
    211                 soc_cm_sfree(unit, mbuf);
    212                 return rv;
    213             }
    214 
    215             for (i = 0; i < soc_mem_index_count(unit, L3_IIFm); i++) {
    216                 l3_iif_entry = soc_mem_table_idx_to_pointer(unit, L3_IIFm, 
    217                                     iif_entry_t *, mbuf, i);
    218                 soc_L3_IIFm_field32_set(unit, l3_iif_entry,
    219                                         ACTIVE_L3_IIF_PROFILE_INDEXf,
    220                                         profile_index);
    221             }
    222 
    223             rv = soc_mem_write_range(unit, L3_IIFm, MEM_BLOCK_ANY,
    224                                      soc_mem_index_min(unit, L3_IIFm),
    225                                      soc_mem_index_max(unit, L3_IIFm),
    226                                      mbuf);
    227             soc_cm_sfree(unit, mbuf);
    228             if (BCM_FAILURE(rv)) {
    229                 bcm_td2_ipmc_pim_bidir_detach(unit);
    230                 return rv;
    231             }
    232         }
    233         SOC_PROFILE_MEM_REFERENCE(unit, pim_bidir_info->active_l3_iif_profile,
    234                 profile_index, soc_mem_index_count(unit, L3_IIFm) - 1);
    235 
    236         if (SOC_IS_TRIDENT2PLUS(unit) && 
    237             soc_feature(unit, soc_feature_alpm) &&
    238             soc_feature(unit, soc_feature_td2p_a0_sw_war) &&
    239             soc_property_get(unit, spn_L3_ALPM_ENABLE, 0)) {
    240             int rpa_id = IPMC_NUM_RP(unit) - 1;
    241             /* Reserve RPA 63 for ALPM WAR */
    242             bcm_td2_ipmc_rp_create(unit, BCM_IPMC_RP_WITH_ID, &rpa_id);
    243         }
    244     } 
    245 
    246     /* Allocate a bitmap indicating which IP_MULTICAST_TCAM entry is valid */
    247     ipmc_tcam_bitmap_length = soc_mem_index_count(unit, IP_MULTICAST_TCAMm);
    248     pim_bidir_info->ipmc_tcam_bitmap =
    249         sal_alloc(SHR_BITALLOCSIZE(ipmc_tcam_bitmap_length), "IPMC TCAM bitmap");
    250     if (NULL == pim_bidir_info->ipmc_tcam_bitmap) {
    251         bcm_td2_ipmc_pim_bidir_detach(unit);
    252         return BCM_E_MEMORY;
    253     }
    254     sal_memset(pim_bidir_info->ipmc_tcam_bitmap, 0,
    255             SHR_BITALLOCSIZE(ipmc_tcam_bitmap_length));
    256 
    257 #ifdef BCM_WARM_BOOT_SUPPORT
    258     if (SOC_WARM_BOOT(unit)) {
    259         rv = _bcm_td2_ipmc_pim_bidir_recover(unit);
    260         if (BCM_FAILURE(rv)) {
    261             bcm_td2_ipmc_pim_bidir_detach(unit);
    262             return rv;
    263         }
    264     }
    265 #endif /* BCM_WARM_BOOT_SUPPORT */
    266 
    267     return rv;
    268 }
    269 
    270 /*
    271  * Function:
    272  *      bcm_td2_ipmc_rp_create
    273  * Purpose:
    274  *      Create a rendezvous point.
    275  * Parameters:
    276  *      unit - StrataSwitch unit #
    277  *      flags - BCM_IPMC_RP_xxx flags.
    278  *      rp_id - (IN/OUT) Rendezvous point ID.
    279  * Returns:
    280  *      BCM_E_xxx
    281  */
    282 int 
    283 bcm_td2_ipmc_rp_create(
    284     int unit, 
    285     uint32 flags, 
    286     int *rp_id)
    287 {
    288     int rv = BCM_E_NONE;
    289     int i;
    290     int rp_min = 0;
    291 
    292 #ifdef BCM_TRIDENT3_SUPPORT
    293     if (SOC_IS_TRIDENT3X(unit)) {
    294     /* RPA_ID 0 is invalid for TD3X devices */
    295        rp_min = 1;
    296     }
    297 #endif
    298 
    299     if (NULL == _bcm_td2_pim_bidir_info[unit]) {
    300         return BCM_E_INIT;
    301     }
    302 
    303     if (NULL == rp_id) {
    304         return BCM_E_PARAM;
    305     }
    306 
    307     if (flags & BCM_IPMC_RP_WITH_ID) {
    308         if ((*rp_id < rp_min) || (*rp_id >= IPMC_NUM_RP(unit))) {
    309             return BCM_E_PARAM;
    310         }
    311         if (IPMC_RP_INFO(unit, *rp_id)->valid) {
    312             return BCM_E_EXISTS;
    313         }
    314         IPMC_RP_INFO(unit, *rp_id)->valid = 1;
    315     } else {
    316         for (i = rp_min; i < IPMC_NUM_RP(unit); i++) {
    317             if (!IPMC_RP_INFO(unit, i)->valid) {
    318                 IPMC_RP_INFO(unit, i)->valid = 1;
    319                 *rp_id = i;
    320                 break;
    321             }
    322         }
    323         if (i == IPMC_NUM_RP(unit)) {
    324             /* No available rendezvous point ID */
    325             return BCM_E_RESOURCE;
    326         }
    327     }
    328 
    329     return rv;
    330 }
    331 
    332 /*
    333  * Function:
    334  *      bcm_td2_ipmc_rp_destroy
    335  * Purpose:
    336  *      Destroy a rendezvous point.
    337  * Parameters:
    338  *      unit - StrataSwitch unit #
    339  *      rp_id - Rendezvous point ID.
    340  * Returns:
    341  *      BCM_E_xxx
    342  */
    343 int 
    344 bcm_td2_ipmc_rp_destroy(
    345     int unit, 
    346     int rp_id)
    347 {
    348     int rv = BCM_E_NONE;
    349 
    350     if (NULL == _bcm_td2_pim_bidir_info[unit]) {
    351         return BCM_E_INIT;
    352     }
    353 
    354     if ((rp_id < 0) || (rp_id >= IPMC_NUM_RP(unit))) {
    355         return BCM_E_PARAM;
    356     }
    357 
    358     if (!IPMC_RP_INFO(unit, rp_id)->valid) {
    359         return BCM_E_NOT_FOUND;
    360     }
    361 
    362     if (IPMC_RP_INFO(unit, rp_id)->ref_count > 0) {
    363         /* RP ID is still being referenced by IPMC entries. */
    364         return BCM_E_BUSY;
    365     }
    366     
    367     /* Delete all active L3 interfaces associated with this RP ID */
    368     BCM_IF_ERROR_RETURN(bcm_td2_ipmc_rp_delete_all(unit, rp_id));
    369 
    370     IPMC_RP_INFO(unit, rp_id)->valid = 0;
    371 
    372     return rv;
    373 }
    374 
    375 /*
    376  * Function:
    377  *      _bcm_td2_ipmc_rp_add
    378  * Purpose:
    379  *      Add an active L3 interface to a rendezvous point.
    380  * Parameters:
    381  *      unit  - StrataSwitch unit #
    382  *      rp_id - Rendezvous point ID
    383  *      intf_id - Active L3 interface ID
    384  * Returns:
    385  *      BCM_E_xxx
    386  */
    387 STATIC int 
    388 _bcm_td2_ipmc_rp_add(
    389     int unit, 
    390     int rp_id, 
    391     bcm_if_t intf_id)
    392 {
    393     int rv = BCM_E_NONE;
    394     iif_entry_t l3_iif_entry;
    395     uint32 profile_index, new_profile_index;
    396     ing_active_l3_iif_profile_entry_t profile_entry;
    397     int rp_bitmap_length;
    398     SHR_BITDCL *rp_bitmap = NULL;
    399     void *entry_ptr;
    400 
    401     /* Get L3 IIF's current active L3 interface profile */
    402     SOC_IF_ERROR_RETURN
    403         (READ_L3_IIFm(unit, MEM_BLOCK_ANY, intf_id, &l3_iif_entry));
    404     profile_index = soc_L3_IIFm_field32_get(unit, &l3_iif_entry,
    405             ACTIVE_L3_IIF_PROFILE_INDEXf);
    406     SOC_IF_ERROR_RETURN
    407         (READ_ING_ACTIVE_L3_IIF_PROFILEm(unit, MEM_BLOCK_ANY, profile_index,
    408                                          &profile_entry));
    409 
    410     /* Get a bitmap of the rendezvous points L3 IIF currently belongs to */
    411     rp_bitmap_length = soc_mem_field_length(unit, ING_ACTIVE_L3_IIF_PROFILEm,
    412             RPA_ID_PROFILEf);
    413     rp_bitmap = sal_alloc(SHR_BITALLOCSIZE(rp_bitmap_length), "RP bitmap");
    414     if (NULL == rp_bitmap) {
    415         return BCM_E_MEMORY;
    416     }
    417     soc_ING_ACTIVE_L3_IIF_PROFILEm_field_get(unit, &profile_entry,
    418             RPA_ID_PROFILEf, rp_bitmap);
    419 
    420     /* Check if L3 IIF already belongs to the given rendezvous point */
    421     if (SHR_BITGET(rp_bitmap, rp_id)) {
    422         sal_free(rp_bitmap);
    423         return BCM_E_EXISTS;
    424     }
    425 
    426     /* Add L3 IIF to the given rendezvous point */
    427     SHR_BITSET(rp_bitmap, rp_id);
    428 
    429     /* Add a new active L3 interface profile */
    430     soc_ING_ACTIVE_L3_IIF_PROFILEm_field_set(unit, &profile_entry,
    431             RPA_ID_PROFILEf, rp_bitmap);
    432     entry_ptr = &profile_entry;
    433     rv = soc_profile_mem_add(unit, IPMC_ACTIVE_L3_IIF_PROFILE(unit),
    434             &entry_ptr, 1, &new_profile_index);
    435     if (SOC_FAILURE(rv)) {
    436         sal_free(rp_bitmap);
    437         return rv;
    438     }
    439     soc_L3_IIFm_field32_set(unit, &l3_iif_entry, ACTIVE_L3_IIF_PROFILE_INDEXf,
    440             new_profile_index);
    441     rv = WRITE_L3_IIFm(unit, MEM_BLOCK_ALL, intf_id, &l3_iif_entry);
    442     if (SOC_FAILURE(rv)) {
    443         sal_free(rp_bitmap);
    444         return rv;
    445     }
    446 
    447     /* Delete the old active L3 interface profile */
    448     rv = soc_profile_mem_delete(unit, IPMC_ACTIVE_L3_IIF_PROFILE(unit),
    449             profile_index);
    450     if (SOC_FAILURE(rv)) {
    451         sal_free(rp_bitmap);
    452         return rv;
    453     }
    454 
    455     sal_free(rp_bitmap);
    456     return rv;
    457 }
    458 
    459 /*
    460  * Function:
    461  *      _bcm_td2_ipmc_rp_delete
    462  * Purpose:
    463  *      Delete an active L3 interface from a rendezvous point.
    464  * Parameters:
    465  *      unit  - StrataSwitch unit #
    466  *      rp_id - Rendezvous point ID
    467  *      intf_id - Active L3 interface ID
    468  * Returns:
    469  *      BCM_E_xxx
    470  */
    471 STATIC int 
    472 _bcm_td2_ipmc_rp_delete(
    473     int unit, 
    474     int rp_id, 
    475     bcm_if_t intf_id)
    476 {
    477     int rv = BCM_E_NONE;
    478     iif_entry_t l3_iif_entry;
    479     uint32 profile_index, new_profile_index;
    480     ing_active_l3_iif_profile_entry_t profile_entry;
    481     int rp_bitmap_length;
    482     SHR_BITDCL *rp_bitmap = NULL;
    483     void *entry_ptr;
    484 
    485     /* Get L3 IIF's current active L3 interface profile */
    486     SOC_IF_ERROR_RETURN
    487         (READ_L3_IIFm(unit, MEM_BLOCK_ANY, intf_id, &l3_iif_entry));
    488     profile_index = soc_L3_IIFm_field32_get(unit, &l3_iif_entry,
    489             ACTIVE_L3_IIF_PROFILE_INDEXf);
    490     SOC_IF_ERROR_RETURN
    491         (READ_ING_ACTIVE_L3_IIF_PROFILEm(unit, MEM_BLOCK_ANY, profile_index,
    492                                          &profile_entry));
    493 
    494     /* Get a bitmap of the rendezvous points L3 IIF currently belongs to */
    495     rp_bitmap_length = soc_mem_field_length(unit, ING_ACTIVE_L3_IIF_PROFILEm,
    496             RPA_ID_PROFILEf);
    497     rp_bitmap = sal_alloc(SHR_BITALLOCSIZE(rp_bitmap_length), "RP bitmap");
    498     if (NULL == rp_bitmap) {
    499         return BCM_E_MEMORY;
    500     }
    501     soc_ING_ACTIVE_L3_IIF_PROFILEm_field_get(unit, &profile_entry,
    502             RPA_ID_PROFILEf, rp_bitmap);
    503 
    504     /* Make sure L3 IIF belongs to the given rendezvous point */
    505     if (!SHR_BITGET(rp_bitmap, rp_id)) {
    506         sal_free(rp_bitmap);
    507         return BCM_E_NOT_FOUND;
    508     }
    509 
    510     /* Delete L3 IIF from the given rendezvous point */
    511     SHR_BITCLR(rp_bitmap, rp_id);
    512 
    513     /* Add a new active L3 interface profile */
    514     soc_ING_ACTIVE_L3_IIF_PROFILEm_field_set(unit, &profile_entry,
    515             RPA_ID_PROFILEf, rp_bitmap);
    516     entry_ptr = &profile_entry;
    517     rv = soc_profile_mem_add(unit, IPMC_ACTIVE_L3_IIF_PROFILE(unit),
    518             &entry_ptr, 1, &new_profile_index);
    519     if (SOC_FAILURE(rv)) {
    520         sal_free(rp_bitmap);
    521         return rv;
    522     }
    523     soc_L3_IIFm_field32_set(unit, &l3_iif_entry, ACTIVE_L3_IIF_PROFILE_INDEXf,
    524             new_profile_index);
    525     rv = WRITE_L3_IIFm(unit, MEM_BLOCK_ALL, intf_id, &l3_iif_entry);
    526     if (SOC_FAILURE(rv)) {
    527         sal_free(rp_bitmap);
    528         return rv;
    529     }
    530 
    531     /* Delete the old active L3 interface profile */
    532     rv = soc_profile_mem_delete(unit, IPMC_ACTIVE_L3_IIF_PROFILE(unit),
    533             profile_index);
    534     if (SOC_FAILURE(rv)) {
    535         sal_free(rp_bitmap);
    536         return rv;
    537     }
    538 
    539     sal_free(rp_bitmap);
    540     return rv;
    541 }
    542 
    543 /*
    544  * Function:
    545  *      bcm_td2_ipmc_rp_set
    546  * Purpose:
    547  *      Set active L3 interfaces for a rendezvous point.
    548  * Parameters:
    549  *      unit - StrataSwitch unit #
    550  *      rp_id - Rendezvous point ID
    551  *      intf_count - Number of elements in intf_array
    552  *      intf_array - Array of active L3 interfaces
    553  * Returns:
    554  *      BCM_E_xxx
    555  */
    556 int 
    557 bcm_td2_ipmc_rp_set(
    558     int unit, 
    559     int rp_id, 
    560     int intf_count, 
    561     bcm_if_t *intf_array)
    562 {
    563     int rv = BCM_E_NONE;
    564     SHR_BITDCL *intf_bitmap = NULL;
    565     SHR_BITDCL *still_active_bitmap = NULL;
    566     int num_l3_iif;
    567     int i;
    568     _bcm_td2_l3_iif_t *prev_ptr, *current_ptr;
    569 
    570     if (NULL == _bcm_td2_pim_bidir_info[unit]) {
    571         return BCM_E_INIT;
    572     }
    573 
    574     /* Input check */
    575     if (rp_id < 0 || rp_id >= IPMC_NUM_RP(unit)) {
    576         return BCM_E_PARAM;
    577     }
    578     if (!IPMC_RP_INFO(unit, rp_id)->valid) {
    579         return BCM_E_CONFIG;
    580     }
    581     if (intf_count > 0 && intf_array == NULL) {
    582         return BCM_E_PARAM;
    583     }
    584 
    585     /* Convert intf_array to a bitmap */
    586     num_l3_iif = soc_mem_index_count(unit, L3_IIFm);
    587     intf_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_l3_iif),
    588             "L3 interface bitmap");
    589     if (NULL == intf_bitmap) {
    590         return BCM_E_MEMORY;
    591     }
    592     sal_memset(intf_bitmap, 0, SHR_BITALLOCSIZE(num_l3_iif));
    593     for (i = 0; i < intf_count; i++) {
    594         if (intf_array[i] < 0 || intf_array[i] >= num_l3_iif) { 
    595             rv = BCM_E_PARAM;
    596             goto cleanup;
    597         }
    598         SHR_BITSET(intf_bitmap, intf_array[i]);
    599     }
    600 
    601     /* Traverse rendezvous point's existing linked list of active L3 IIFs.
    602      * Delete the L3 IIFs that are no longer active, i.e. not in intf_array.
    603      * Keep track of L3 IIFs that remain active in still_active_bitmap.
    604      */
    605     still_active_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_l3_iif),
    606             "Still active L3 interface bitmap");
    607     if (NULL == still_active_bitmap) {
    608         rv = BCM_E_MEMORY;
    609         goto cleanup;
    610     }
    611     sal_memset(still_active_bitmap, 0, SHR_BITALLOCSIZE(num_l3_iif));
    612     prev_ptr = NULL;
    613     current_ptr = IPMC_RP_INFO(unit, rp_id)->l3_iif_list;
    614     while (NULL != current_ptr) {
    615         if (SHR_BITGET(intf_bitmap, current_ptr->l3_iif)) {
    616             /* This L3 IIF remains active. */
    617             SHR_BITSET(still_active_bitmap, current_ptr->l3_iif);
    618             prev_ptr = current_ptr;
    619             current_ptr = current_ptr->next;
    620         } else {
    621             /* Delete inactive L3 IIF from rendezvous point */
    622             rv = _bcm_td2_ipmc_rp_delete(unit, rp_id, current_ptr->l3_iif);
    623             if (BCM_FAILURE(rv)) {
    624                 goto cleanup;
    625             }
    626             if (current_ptr == IPMC_RP_INFO(unit, rp_id)->l3_iif_list) {
    627                 IPMC_RP_INFO(unit, rp_id)->l3_iif_list = current_ptr->next;
    628                 sal_free(current_ptr);
    629                 current_ptr = IPMC_RP_INFO(unit, rp_id)->l3_iif_list;
    630             } else {
    631                 prev_ptr->next = current_ptr->next;
    632                 sal_free(current_ptr);
    633                 current_ptr = prev_ptr->next;
    634             }
    635         }
    636     }
    637 
    638     /* Traverse intf_array. Add the L3 IIFs that are not already active,
    639      * i.e. not in still_active_bitmap.
    640      */
    641     for (i = 0; i < intf_count; i++) {
    642         if (SHR_BITGET(still_active_bitmap, intf_array[i])) {
    643             /* This L3 IIF is already active. */
    644             continue;
    645         }
    646         rv = _bcm_td2_ipmc_rp_add(unit, rp_id, intf_array[i]);
    647         if (BCM_FAILURE(rv)) {
    648             goto cleanup;
    649         }
    650         current_ptr = sal_alloc(sizeof(_bcm_td2_l3_iif_t), "Active L3 IIF");
    651         if (NULL == current_ptr) {
    652             rv = BCM_E_MEMORY;
    653             goto cleanup;
    654         }
    655         current_ptr->l3_iif = intf_array[i];
    656         current_ptr->next = IPMC_RP_INFO(unit, rp_id)->l3_iif_list;
    657         IPMC_RP_INFO(unit, rp_id)->l3_iif_list = current_ptr;
    658     }
    659 
    660 cleanup:
    661     if (NULL != intf_bitmap) {
    662         sal_free(intf_bitmap);
    663     }
    664     if (NULL != still_active_bitmap) {
    665         sal_free(still_active_bitmap);
    666     }
    667     return rv;
    668 }
    669 
    670 /*
    671  * Function:
    672  *      bcm_td2_ipmc_rp_get
    673  * Purpose:
    674  *      Get active L3 interfaces for a rendezvous point.
    675  * Parameters:
    676  *      unit - StrataSwitch unit #
    677  *      rp_id - Rendezvous point ID
    678  *      intf_max - Number of elements in intf_array
    679  *      intf_array - (OUT) Array of active L3 interfaces
    680  *      intf_count - (OUT) Number of elements returned in intf_array
    681  * Returns:
    682  *      BCM_E_xxx
    683  */
    684 int 
    685 bcm_td2_ipmc_rp_get(
    686     int unit, 
    687     int rp_id, 
    688     int intf_max, 
    689     bcm_if_t *intf_array, 
    690     int *intf_count)
    691 {
    692     int rv = BCM_E_NONE;
    693     _bcm_td2_l3_iif_t *current_ptr;
    694 
    695     if (NULL == _bcm_td2_pim_bidir_info[unit]) {
    696         return BCM_E_INIT;
    697     }
    698 
    699     /* Input check */
    700     if (rp_id < 0 || rp_id >= IPMC_NUM_RP(unit)) {
    701         return BCM_E_PARAM;
    702     }
    703     if (!IPMC_RP_INFO(unit, rp_id)->valid) {
    704         return BCM_E_CONFIG;
    705     }
    706     if ((intf_max > 0 && intf_array == NULL) ||
    707         (intf_max == 0 && intf_array != NULL)) {
    708         return BCM_E_PARAM;
    709     }
    710     if (NULL == intf_count) {
    711         return BCM_E_PARAM;
    712     }
    713 
    714     /* Traverse rendezvous point's linked list of active L3 IIFs. */
    715     *intf_count = 0;
    716     current_ptr = IPMC_RP_INFO(unit, rp_id)->l3_iif_list;
    717     while (NULL != current_ptr) {
    718         if (NULL != intf_array) {
    719             intf_array[*intf_count] = current_ptr->l3_iif;
    720         }
    721         (*intf_count)++;
    722         if (*intf_count == intf_max) {
    723             break;
    724         }
    725         current_ptr = current_ptr->next;
    726     }
    727 
    728     return rv;
    729 }
    730 
    731 /*
    732  * Function:
    733  *      bcm_td2_ipmc_rp_add
    734  * Purpose:
    735  *      Add an active L3 interface to a rendezvous point.
    736  * Parameters:
    737  *      unit - StrataSwitch unit #
    738  *      rp_id - Rendezvous point ID
    739  *      intf_id - L3 interface ID
    740  * Returns:
    741  *      BCM_E_xxx
    742  */
    743 int 
    744 bcm_td2_ipmc_rp_add(
    745     int unit, 
    746     int rp_id, 
    747     bcm_if_t intf_id)
    748 {
    749     int rv = BCM_E_NONE;
    750     _bcm_td2_l3_iif_t *current_ptr;
    751 
    752     if (NULL == _bcm_td2_pim_bidir_info[unit]) {
    753         return BCM_E_INIT;
    754     }
    755 
    756     /* Input check */
    757     if (rp_id < 0 || rp_id >= IPMC_NUM_RP(unit)) {
    758         return BCM_E_PARAM;
    759     }
    760     if (!IPMC_RP_INFO(unit, rp_id)->valid) {
    761         return BCM_E_CONFIG;
    762     }
    763     if (intf_id < 0 || intf_id > soc_mem_index_max(unit, L3_IIFm)) {
    764         return BCM_E_PARAM;
    765     }
    766 
    767     /* Add intf_id to rendezvous point */
    768     BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_rp_add(unit, rp_id, intf_id));
    769 
    770     /* Insert intf_id to head of rendezvous point's linked list of L3 IIFs */
    771     current_ptr = sal_alloc(sizeof(_bcm_td2_l3_iif_t), "Active L3 IIF");
    772     if (NULL == current_ptr) {
    773         return BCM_E_MEMORY;
    774     }
    775     current_ptr->l3_iif = intf_id;
    776     current_ptr->next = IPMC_RP_INFO(unit, rp_id)->l3_iif_list;
    777     IPMC_RP_INFO(unit, rp_id)->l3_iif_list = current_ptr;
    778 
    779     return rv;
    780 }
    781 
    782 /*
    783  * Function:
    784  *      bcm_td2_ipmc_rp_delete
    785  * Purpose:
    786  *      Delete an active L3 interface from a rendezvous point.
    787  * Parameters:
    788  *      unit - StrataSwitch unit #
    789  *      rp_id - Rendezvous point ID
    790  *      intf_id - L3 interface ID
    791  * Returns:
    792  *      BCM_E_xxx
    793  */
    794 int 
    795 bcm_td2_ipmc_rp_delete(
    796     int unit, 
    797     int rp_id, 
    798     bcm_if_t intf_id)
    799 {
    800     int rv = BCM_E_NONE;
    801     _bcm_td2_l3_iif_t *current_ptr, *prev_ptr;
    802 
    803     if (NULL == _bcm_td2_pim_bidir_info[unit]) {
    804         return BCM_E_INIT;
    805     }
    806 
    807     /* Input check */
    808     if (rp_id < 0 || rp_id >= IPMC_NUM_RP(unit)) {
    809         return BCM_E_PARAM;
    810     }
    811     if (!IPMC_RP_INFO(unit, rp_id)->valid) {
    812         return BCM_E_CONFIG;
    813     }
    814     if (intf_id < 0 || intf_id > soc_mem_index_max(unit, L3_IIFm)) {
    815         return BCM_E_PARAM;
    816     }
    817 
    818     /* Traverse rendezvous point's linked list of active L3 IIFs to
    819      * find and delete the given intf_id.
    820      */
    821     prev_ptr = NULL;
    822     current_ptr = IPMC_RP_INFO(unit, rp_id)->l3_iif_list;
    823     while (NULL != current_ptr) {
    824         if (current_ptr->l3_iif == intf_id) {
    825             BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_rp_delete(unit, rp_id, intf_id));
    826             if (current_ptr == IPMC_RP_INFO(unit, rp_id)->l3_iif_list) {
    827                 IPMC_RP_INFO(unit, rp_id)->l3_iif_list = current_ptr->next;
    828             } else {
    829                 /* 
    830                  * In the following line of code, Coverity thinks the
    831                  * prev_ptr pointer may still be NULL when 
    832                  * dereferenced. This situation will never occur because 
    833                  * if current_ptr is not pointing to the head of the 
    834                  * linked list, prev_ptr would not be NULL.
    835                  */
    836                 /* coverity[var_deref_op : FALSE] */
    837                 prev_ptr->next = current_ptr->next;
    838             }
    839             sal_free(current_ptr);
    840             break;
    841         } else {
    842             prev_ptr = current_ptr;
    843             current_ptr = current_ptr->next;
    844         }
    845     }
    846     if (NULL == current_ptr) {
    847         return BCM_E_NOT_FOUND;
    848     }
    849 
    850     return rv;
    851 }
    852 
    853 /*
    854  * Function:
    855  *      bcm_td2_ipmc_rp_delete_all
    856  * Purpose:
    857  *      Delete all active L3 interfaces from a rendezvous point.
    858  * Parameters:
    859  *      unit - StrataSwitch unit #
    860  *      rp_id - Rendezvous point ID
    861  * Returns:
    862  *      BCM_E_xxx
    863  */
    864 int 
    865 bcm_td2_ipmc_rp_delete_all(
    866     int unit, 
    867     int rp_id) 
    868 {
    869     return bcm_td2_ipmc_rp_set(unit, rp_id, 0, NULL);
    870 }
    871 
    872 /*
    873  * Function:
    874  *      bcm_td2_ipmc_rp_ref_count_incr
    875  * Purpose:
    876  *      Increment reference count of rendezvous point.
    877  * Parameters:
    878  *      unit - StrataSwitch unit #
    879  *      rp_id - Rendezvous point ID
    880  * Returns:
    881  *      BCM_E_xxx
    882  */
    883 int 
    884 bcm_td2_ipmc_rp_ref_count_incr(
    885     int unit, 
    886     int rp_id) 
    887 {
    888     int rv = BCM_E_NONE;
    889 
    890     if (NULL == _bcm_td2_pim_bidir_info[unit]) {
    891         return BCM_E_INIT;
    892     }
    893 
    894     if ((rp_id < 0) || (rp_id >= IPMC_NUM_RP(unit))) {
    895         return BCM_E_PARAM;
    896     }
    897 
    898     if (!IPMC_RP_INFO(unit, rp_id)->valid) {
    899         return BCM_E_NOT_FOUND;
    900     }
    901 
    902     IPMC_RP_INFO(unit, rp_id)->ref_count++;
    903 
    904     return rv;
    905 }
    906 
    907 /*
    908  * Function:
    909  *      bcm_td2_ipmc_rp_ref_count_decr
    910  * Purpose:
    911  *      Decrement reference count of rendezvous point.
    912  * Parameters:
    913  *      unit - StrataSwitch unit #
    914  *      rp_id - Rendezvous point ID
    915  * Returns:
    916  *      BCM_E_xxx
    917  */
    918 int 
    919 bcm_td2_ipmc_rp_ref_count_decr(
    920     int unit, 
    921     int rp_id) 
    922 {
    923     int rv = BCM_E_NONE;
    924 
    925     if (NULL == _bcm_td2_pim_bidir_info[unit]) {
    926         return BCM_E_INIT;
    927     }
    928 
    929     if ((rp_id < 0) || (rp_id >= IPMC_NUM_RP(unit))) {
    930         return BCM_E_PARAM;
    931     }
    932 
    933     if (!IPMC_RP_INFO(unit, rp_id)->valid) {
    934         return BCM_E_NOT_FOUND;
    935     }
    936 
    937     if (IPMC_RP_INFO(unit, rp_id)->ref_count == 0) {
    938         return BCM_E_INTERNAL;
    939     }
    940 
    941     IPMC_RP_INFO(unit, rp_id)->ref_count--;
    942 
    943     return rv;
    944 }
    945 
    946 /*
    947  * Function:
    948  *      bcm_td2_ipmc_range_add
    949  * Purpose:
    950  *      Add a range of PIM-BIDIR IPMC addresses.
    951  * Parameters:
    952  *      unit - StrataSwitch unit #
    953  *      range_id - (IN/OUT) Range ID
    954  *      range - IPMC address range info
    955  * Returns:
    956  *      BCM_E_xxx
    957  */
    958 int 
    959 bcm_td2_ipmc_range_add(
    960     int unit, 
    961     int *range_id, 
    962     bcm_ipmc_range_t *range)
    963 {
    964     int rv = BCM_E_NONE;
    965     int tcam_index = 0;
    966     int i, valid_bit=1;
    967     ip_multicast_tcam_entry_t tcam_entry;
    968     uint32 group_addr[4], group_addr_mask[4];
    969 
    970     if (NULL == _bcm_td2_pim_bidir_info[unit]) {
    971         return BCM_E_INIT;
    972     }
    973 
    974     /* Input check */
    975     if (NULL == range_id || NULL == range) {
    976         return BCM_E_PARAM;
    977     }
    978     if (range->flags & BCM_IPMC_RANGE_WITH_ID) {
    979         if (*range_id < 0 ||
    980             *range_id > soc_mem_index_max(unit, IP_MULTICAST_TCAMm)) {
    981             return BCM_E_PARAM;
    982         }
    983     }
    984     if (!(range->flags & BCM_IPMC_RANGE_PIM_BIDIR)) {
    985         /* On Trident2, only PIM-BIDIR eligible addresses can be specified.
    986          * Addresses not eligible for PIM-BIDIR cannot be specified.
    987          */
    988         return BCM_E_PARAM;
    989     }
    990     if (range->priority != 0) {
    991         /* On Trident2, only PIM-BIDIR eligible addresses can be specified.
    992          * Hence, there is no need to specify relative priority among the
    993          * ranges of PIM-BIDIR eligible addresses.
    994          */
    995         return BCM_E_PARAM;
    996     }
    997     if ((range->vrf > SOC_VRF_MAX(unit)) ||
    998         (range->vrf < BCM_L3_VRF_DEFAULT)) {
    999         return BCM_E_PARAM;
   1000     }
   1001 
   1002     /* Get index to IP_MULTICAST_TCAM */
   1003     if (range->flags & BCM_IPMC_RANGE_REPLACE) {
   1004         if (!(range->flags & BCM_IPMC_RANGE_WITH_ID)) {
   1005             return BCM_E_PARAM;
   1006         }
   1007         tcam_index = *range_id;
   1008         if (!SHR_BITGET(IPMC_TCAM_BITMAP(unit), tcam_index)) {
   1009             return BCM_E_NOT_FOUND;
   1010         }
   1011     } else {
   1012         if (range->flags & BCM_IPMC_RANGE_WITH_ID) {
   1013             tcam_index = *range_id;
   1014             if (SHR_BITGET(IPMC_TCAM_BITMAP(unit), tcam_index)) {
   1015                 return BCM_E_EXISTS;
   1016             }
   1017             SHR_BITSET(IPMC_TCAM_BITMAP(unit), tcam_index);
   1018         } else {
   1019             /* Find a free TCAM index */
   1020             for (i = 0; i < soc_mem_index_count(unit, IP_MULTICAST_TCAMm); i++) {
   1021                 if (!SHR_BITGET(IPMC_TCAM_BITMAP(unit), i)) {
   1022                     SHR_BITSET(IPMC_TCAM_BITMAP(unit), i);
   1023                     tcam_index = i;
   1024                     *range_id = tcam_index;
   1025                     break;
   1026                 }
   1027             }
   1028             if (i == soc_mem_index_count(unit, IP_MULTICAST_TCAMm)) {
   1029                 return BCM_E_RESOURCE;
   1030             }
   1031         }
   1032     }
   1033 
   1034     /* Write entry to IP_MULTICAST_TCAM */
   1035     sal_memset(&tcam_entry, 0, sizeof(tcam_entry));
   1036 #if defined(BCM_TOMAHAWK2_SUPPORT)
   1037     if (SOC_IS_TOMAHAWK2(unit)) {
   1038         soc_IP_MULTICAST_TCAMm_field32_set(unit, &tcam_entry, VALIDf, 3);
   1039     } else 
   1040 #endif 
   1041     {
   1042         valid_bit = 1 <<  soc_mem_field_length(unit, IP_MULTICAST_TCAMm, VALIDf);
   1043         valid_bit -= 1;
   1044         soc_IP_MULTICAST_TCAMm_field32_set(unit, &tcam_entry, VALIDf, valid_bit);
   1045     }
   1046     soc_IP_MULTICAST_TCAMm_field32_set(unit, &tcam_entry, VRFf,
   1047             range->vrf);
   1048     soc_IP_MULTICAST_TCAMm_field32_set(unit, &tcam_entry, VRF_MASKf,
   1049             range->vrf_mask);
   1050     if (range->flags & BCM_IPMC_RANGE_IP6) {
   1051         soc_IP_MULTICAST_TCAMm_field32_set(unit, &tcam_entry,
   1052                 MODEf, 1);
   1053         soc_IP_MULTICAST_TCAMm_field32_set(unit, &tcam_entry,
   1054                 MODE_MASKf, 1);
   1055         soc_mem_ip6_addr_set(unit, IP_MULTICAST_TCAMm, &tcam_entry,
   1056                 GROUP_ADDRf, range->mc_ip6_addr, 0);
   1057         soc_mem_ip6_addr_set(unit, IP_MULTICAST_TCAMm, &tcam_entry,
   1058                 GROUP_ADDR_MASKf, range->mc_ip6_addr_mask, 0);
   1059     } else {
   1060         soc_IP_MULTICAST_TCAMm_field32_set(unit, &tcam_entry,
   1061                 MODEf, 0);
   1062         soc_IP_MULTICAST_TCAMm_field32_set(unit, &tcam_entry,
   1063                 MODE_MASKf, 1);
   1064         sal_memset(group_addr, 0, sizeof(group_addr));
   1065         group_addr[0] = range->mc_ip_addr;
   1066         soc_IP_MULTICAST_TCAMm_field_set(unit, &tcam_entry,
   1067                 GROUP_ADDRf, group_addr);
   1068         sal_memset(group_addr_mask, 0, sizeof(group_addr_mask));
   1069         group_addr_mask[0] = range->mc_ip_addr_mask;
   1070         soc_IP_MULTICAST_TCAMm_field_set(unit, &tcam_entry,
   1071                 GROUP_ADDR_MASKf, group_addr_mask);
   1072     }
   1073     SOC_IF_ERROR_RETURN(WRITE_IP_MULTICAST_TCAMm(unit, MEM_BLOCK_ALL,
   1074                 tcam_index, &tcam_entry));
   1075 
   1076     return rv;
   1077 }
   1078 
   1079 /*
   1080  * Function:
   1081  *      bcm_td2_ipmc_range_delete
   1082  * Purpose:
   1083  *      Delete a range of PIM-BIDIR IPMC addresses.
   1084  * Parameters:
   1085  *      unit - StrataSwitch unit #
   1086  *      range_id - Range ID
   1087  * Returns:
   1088  *      BCM_E_xxx
   1089  */
   1090 int 
   1091 bcm_td2_ipmc_range_delete(
   1092     int unit, 
   1093     int range_id)
   1094 {
   1095     int rv = BCM_E_NONE;
   1096     int tcam_index;
   1097 
   1098     if (NULL == _bcm_td2_pim_bidir_info[unit]) {
   1099         return BCM_E_INIT;
   1100     }
   1101 
   1102     /* Input check */
   1103     if (range_id < 0 ||
   1104             range_id > soc_mem_index_max(unit, IP_MULTICAST_TCAMm)) {
   1105         return BCM_E_PARAM;
   1106     }
   1107 
   1108     /* Delete the TCAM entry referenced by range_id */
   1109     tcam_index = range_id;
   1110     if (!SHR_BITGET(IPMC_TCAM_BITMAP(unit), tcam_index)) {
   1111         return BCM_E_NOT_FOUND;
   1112     }
   1113     SOC_IF_ERROR_RETURN(WRITE_IP_MULTICAST_TCAMm(unit, MEM_BLOCK_ALL,
   1114                 tcam_index, soc_mem_entry_null(unit, IP_MULTICAST_TCAMm)));
   1115     SHR_BITCLR(IPMC_TCAM_BITMAP(unit), tcam_index);
   1116 
   1117     return rv;
   1118 }
   1119 
   1120 /*
   1121  * Function:
   1122  *      bcm_td2_ipmc_range_delete_all
   1123  * Purpose:
   1124  *      Delete all ranges of PIM-BIDIR IPMC addresses.
   1125  * Parameters:
   1126  *      unit - StrataSwitch unit #
   1127  * Returns:
   1128  *      BCM_E_xxx
   1129  */
   1130 int 
   1131 bcm_td2_ipmc_range_delete_all(
   1132     int unit)
   1133 {
   1134     int rv = BCM_E_NONE;
   1135     int ipmc_tcam_bitmap_length;
   1136 
   1137     if (NULL == _bcm_td2_pim_bidir_info[unit]) {
   1138         return BCM_E_INIT;
   1139     }
   1140 
   1141     /* Clear IP Multicast TCAM table */
   1142     SOC_IF_ERROR_RETURN
   1143         (soc_mem_clear(unit, IP_MULTICAST_TCAMm, MEM_BLOCK_ALL, 0));
   1144 
   1145     /* Clear bitmap indicating which IP_MULTICAST_TCAM entry is valid */
   1146     ipmc_tcam_bitmap_length = soc_mem_index_count(unit, IP_MULTICAST_TCAMm);
   1147     sal_memset(IPMC_TCAM_BITMAP(unit), 0,
   1148             SHR_BITALLOCSIZE(ipmc_tcam_bitmap_length));
   1149 
   1150     return rv;
   1151 }
   1152 
   1153 /*
   1154  * Function:
   1155  *      bcm_td2_ipmc_range_get
   1156  * Purpose:
   1157  *      Get a range of PIM-BIDIR IPMC addresses.
   1158  * Parameters:
   1159  *      unit - StrataSwitch unit #
   1160  *      range_id - Range ID
   1161  *      range - (OUT) Range info
   1162  * Returns:
   1163  *      BCM_E_xxx
   1164  */
   1165 int 
   1166 bcm_td2_ipmc_range_get(
   1167     int unit, 
   1168     int range_id, 
   1169     bcm_ipmc_range_t *range)
   1170 {
   1171     int rv = BCM_E_NONE;
   1172     int tcam_index;
   1173     ip_multicast_tcam_entry_t tcam_entry;
   1174     uint32 group_addr[4], group_addr_mask[4];
   1175 
   1176     if (NULL == _bcm_td2_pim_bidir_info[unit]) {
   1177         return BCM_E_INIT;
   1178     }
   1179 
   1180     /* Input check */
   1181     if (range_id < 0 ||
   1182         range_id > soc_mem_index_max(unit, IP_MULTICAST_TCAMm)) {
   1183         return BCM_E_PARAM;
   1184     }
   1185     if (NULL == range) {
   1186         return BCM_E_PARAM;
   1187     }
   1188 
   1189     /* Read the TCAM entry referenced by range_id */
   1190     tcam_index = range_id;
   1191     if (!SHR_BITGET(IPMC_TCAM_BITMAP(unit), tcam_index)) {
   1192         return BCM_E_NOT_FOUND;
   1193     }
   1194     SOC_IF_ERROR_RETURN
   1195         (READ_IP_MULTICAST_TCAMm(unit, MEM_BLOCK_ANY, tcam_index, &tcam_entry));
   1196     if (!soc_IP_MULTICAST_TCAMm_field32_get(unit, &tcam_entry, VALIDf)) {
   1197         return BCM_E_INTERNAL;
   1198     }
   1199 
   1200     /* Fill in the bcm_ipmc_range_t structure */
   1201     bcm_ipmc_range_t_init(range);
   1202     range->flags |= BCM_IPMC_RANGE_PIM_BIDIR;
   1203     if (soc_IP_MULTICAST_TCAMm_field32_get(unit, &tcam_entry, MODEf)) {
   1204         /* IPv6 entry */
   1205         range->flags |= BCM_IPMC_RANGE_IP6;
   1206         soc_mem_ip6_addr_get(unit, IP_MULTICAST_TCAMm, &tcam_entry,
   1207                 GROUP_ADDRf, range->mc_ip6_addr, 0);
   1208         soc_mem_ip6_addr_get(unit, IP_MULTICAST_TCAMm, &tcam_entry,
   1209                 GROUP_ADDR_MASKf, range->mc_ip6_addr_mask, 0);
   1210     } else {
   1211         /* IPv4 entry */
   1212         soc_IP_MULTICAST_TCAMm_field_get(unit, &tcam_entry, GROUP_ADDRf,
   1213                 group_addr);
   1214         soc_IP_MULTICAST_TCAMm_field_get(unit, &tcam_entry, GROUP_ADDR_MASKf,
   1215                 group_addr_mask);
   1216         range->mc_ip_addr = group_addr[0];
   1217         range->mc_ip_addr_mask = group_addr_mask[0];
   1218     }
   1219     range->vrf = soc_IP_MULTICAST_TCAMm_field32_get(unit, &tcam_entry,
   1220             VRFf);
   1221     range->vrf_mask = soc_IP_MULTICAST_TCAMm_field32_get(unit, &tcam_entry,
   1222             VRF_MASKf);
   1223 
   1224     return rv;
   1225 }
   1226 
   1227 /*
   1228  * Function:
   1229  *      bcm_td2_ipmc_range_size_get
   1230  * Purpose:
   1231  *      Get the number of PIM-BIDIR IPMC address ranges supported by the device.
   1232  * Parameters:
   1233  *      unit - StrataSwitch unit #
   1234  *      size - (OUT) Number of ranges 
   1235  * Returns:
   1236  *      BCM_E_xxx
   1237  */
   1238 int 
   1239 bcm_td2_ipmc_range_size_get(
   1240     int unit, 
   1241     int *size)
   1242 {
   1243     int rv = BCM_E_NONE;
   1244 
   1245     if (NULL == _bcm_td2_pim_bidir_info[unit]) {
   1246         return BCM_E_INIT;
   1247     }
   1248 
   1249     /* Input check */
   1250     if (NULL == size) {
   1251         return BCM_E_PARAM;
   1252     }
   1253 
   1254     *size = soc_mem_index_count(unit, IP_MULTICAST_TCAMm);
   1255 
   1256     return rv;
   1257 }
   1258 
   1259 /*
   1260  * Function:
   1261  *      _bcm_td2_ipmc_stat_get_table_info
   1262  * Description:
   1263  *      Provides relevant flex table information(table-name,index with
   1264  *      direction)  for given IPMC group
   1265  *
   1266  * Parameters:
   1267  *      unit             - (IN) unit number
   1268  *      port             - (IN) GPORT ID
   1269  *      num_of_tables    - (OUT) Number of flex counter tables
   1270  *      table_info       - (OUT) Flex counter tables information
   1271  *
   1272  * Return Value:
   1273  *      BCM_E_XXX
   1274  * Notes:
   1275  */
   1276 STATIC bcm_error_t
   1277 _bcm_td2_ipmc_stat_get_table_info(
   1278                    int                        unit,
   1279                    bcm_ipmc_addr_t            *info,
   1280                    uint32                     *num_of_tables,
   1281                    bcm_stat_flex_table_info_t *table_info)
   1282 {
   1283     int rv;
   1284     soc_mem_t mem;          
   1285     _bcm_l3_cfg_t l3cfg;     
   1286 
   1287     if (NULL == info) {
   1288         return (BCM_E_PARAM);
   1289     }
   1290 
   1291     mem = INVALIDm;
   1292   
   1293     sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t));
   1294     l3cfg.l3c_flags = BCM_L3_IPMC;
   1295     if (info->flags & BCM_IPMC_IP6) {
   1296         l3cfg.l3c_flags |= BCM_L3_IP6;
   1297     }
   1298     l3cfg.l3c_ing_intf = info->ing_intf;
   1299     l3cfg.l3c_vid = info->vid;     
   1300     l3cfg.l3c_vrf = info->vrf;
   1301 
   1302     if (l3cfg.l3c_flags & BCM_L3_IP6) {
   1303         sal_memcpy(l3cfg.l3c_ip6, info->mc_ip6_addr, BCM_IP6_ADDRLEN);
   1304         sal_memcpy(l3cfg.l3c_sip6, info->s_ip6_addr, BCM_IP6_ADDRLEN);
   1305     } else {
   1306         l3cfg.l3c_ip_addr = info->mc_ip_addr;
   1307         l3cfg.l3c_src_ip_addr = info->s_ip_addr;        
   1308     }
   1309 
   1310     rv = _bcm_td2_l3_ipmc_get(unit, &l3cfg);        
   1311       
   1312     if (BCM_SUCCESS(rv)) { /* Entry found */
   1313         if (soc_mem_is_valid(unit, L3_ENTRY_DOUBLEm)) {
   1314             mem = (l3cfg.l3c_flags & BCM_L3_IP6) ? L3_ENTRY_QUADm :
   1315                                                    L3_ENTRY_DOUBLEm;
   1316         } else {
   1317             mem = (l3cfg.l3c_flags & BCM_L3_IP6) ? L3_ENTRY_IPV6_MULTICASTm :
   1318                                                    L3_ENTRY_IPV4_MULTICASTm;
   1319         }
   1320 
   1321         table_info[*num_of_tables].table = mem;
   1322         table_info[*num_of_tables].index = l3cfg.l3c_hw_index;
   1323         table_info[*num_of_tables].direction = bcmStatFlexDirectionIngress;
   1324         (*num_of_tables)++;
   1325     }
   1326     
   1327     return rv;
   1328 }
   1329 
   1330 
   1331 /*
   1332  * Function:
   1333  *      _bcm_td2_ipmc_stat_attach
   1334  * Description:
   1335  *      Attach counters entries to the given IPMC group
   1336  *
   1337  * Parameters:
   1338  *      unit             - (IN) unit number
   1339  *      info             - (IN) IPMC group information 
   1340  *      stat_counter_id  - (IN) Stat Counter ID.
   1341  *
   1342  * Return Value:
   1343  *      BCM_E_XXX
   1344  */
   1345 bcm_error_t
   1346 _bcm_td2_ipmc_stat_attach(
   1347             int unit,
   1348             bcm_ipmc_addr_t *info,
   1349             uint32 stat_counter_id)
   1350 {
   1351     soc_mem_t                 table[4]={0};
   1352     uint32                    flex_table_index=0;
   1353     bcm_stat_flex_direction_t direction=bcmStatFlexDirectionIngress;
   1354     uint32                    pool_number=0;
   1355     uint32                    base_index=0;
   1356     bcm_stat_flex_mode_t      offset_mode=0;
   1357     bcm_stat_object_t         object=bcmStatObjectIngPort;
   1358     bcm_stat_group_mode_t     group_mode= bcmStatGroupModeSingle;
   1359     uint32                    count=0;
   1360     uint32                     actual_num_tables=0;
   1361     uint32                     num_of_tables=0;
   1362     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   1363 
   1364     _bcm_esw_stat_get_counter_id_info(
   1365                   unit, stat_counter_id,
   1366                   &group_mode,&object,&offset_mode,&pool_number,&base_index);
   1367 
   1368     BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_object(unit,object,&direction));
   1369     BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_group(unit,group_mode));
   1370 
   1371     BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_get_table_info(
   1372                         unit,object,4,&actual_num_tables,&table[0],&direction));
   1373 
   1374     BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_stat_get_table_info(
   1375                    unit, info,&num_of_tables,&table_info[0]));
   1376     for (count=0; count < num_of_tables ; count++) {
   1377          for (flex_table_index=0; 
   1378               flex_table_index < actual_num_tables ; 
   1379               flex_table_index++) {
   1380               if ((table_info[count].direction == direction) &&
   1381                   (table_info[count].table == table[flex_table_index]) ) {
   1382                   if (direction == bcmStatFlexDirectionIngress) {
   1383                       return _bcm_esw_stat_flex_attach_ingress_table_counters(
   1384                              unit,
   1385                              table_info[count].table,
   1386                              table_info[count].index,
   1387                              offset_mode,
   1388                              base_index,
   1389                              pool_number);
   1390                   } else {
   1391                       return _bcm_esw_stat_flex_attach_egress_table_counters(
   1392                              unit,
   1393                              table_info[count].table,
   1394                              table_info[count].index,
   1395                              0,
   1396                              offset_mode,
   1397                              base_index,
   1398                              pool_number);
   1399                   }
   1400               }
   1401          }
   1402     }
   1403     return BCM_E_NOT_FOUND;
   1404 }
   1405 
   1406 /*
   1407  * Function:
   1408  *      _bcm_td2_ipmc_stat_detach
   1409  * Description:
   1410  *      Detach counters entries to the given IPMC group
   1411  *
   1412  * Parameters:
   1413  *      unit             - (IN) unit number
   1414  *      info		 - (IN) L3 host description
   1415  *
   1416  * Return Value:
   1417  *      BCM_E_XXX
   1418  * Notes:
   1419  */
   1420 bcm_error_t
   1421 _bcm_td2_ipmc_stat_detach(
   1422             int unit,
   1423             bcm_ipmc_addr_t *info)
   1424 {
   1425     uint32                     count=0;
   1426     uint32                     num_of_tables=0;
   1427     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   1428     bcm_error_t                rv = BCM_E_NONE;
   1429     bcm_error_t                err_code[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION] = {BCM_E_NONE};
   1430 
   1431     BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_stat_get_table_info(
   1432                    unit, info,&num_of_tables,&table_info[0]));
   1433 
   1434     for (count=0; count < num_of_tables ; count++) {
   1435       if (table_info[count].direction == bcmStatFlexDirectionIngress) {
   1436            rv = _bcm_esw_stat_flex_detach_ingress_table_counters(
   1437                          unit,
   1438                          table_info[count].table,
   1439                          table_info[count].index);
   1440            if (BCM_E_NONE != rv && 
   1441                 BCM_E_NONE == err_code[bcmStatFlexDirectionIngress]) {
   1442                 err_code[bcmStatFlexDirectionIngress] = rv;
   1443            }
   1444       } else {
   1445            rv = _bcm_esw_stat_flex_detach_egress_table_counters(
   1446                           unit,
   1447                           0,
   1448                           table_info[count].table,
   1449                           table_info[count].index);
   1450            if (BCM_E_NONE != rv &&
   1451                 BCM_E_NONE == err_code[bcmStatFlexDirectionEgress]) {
   1452                 err_code[bcmStatFlexDirectionEgress] = rv;
   1453            }
   1454       }
   1455     }
   1456     
   1457     BCM_STAT_FLEX_DETACH_RETURN(err_code)
   1458 }
   1459 
   1460 /*
   1461  * Function:
   1462  *      _bcm_td2_ipmc_stat_counter_get
   1463  * Description:
   1464  *      Get counter statistic values for specific IPMC group
   1465  *      if sync_mode is set, sync the sw accumulated count
   1466  *      with hw count value first, else return sw count.  
   1467  *
   1468  * Parameters:
   1469  *      unit             - (IN) unit number
   1470  *      sync_mode        - (IN) hwcount is to be synced to sw count 
   1471  *      info             - (IN) IPMC group information
   1472  *      stat             - (IN) Type of the counter to retrieve
   1473  *                              I.e. ingress/egress byte/packet)
   1474  *      num_entries      - (IN) Number of counter Entries
   1475  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   1476  *      counter_values   - (OUT) Pointer to counter values
   1477  *
   1478  * Return Value:
   1479  *      BCM_E_XXX
   1480  * Notes:
   1481  */
   1482 bcm_error_t 
   1483 _bcm_td2_ipmc_stat_counter_get(
   1484             int unit,
   1485             int sync_mode,
   1486             bcm_ipmc_addr_t *info,
   1487             bcm_ipmc_stat_t stat,
   1488             uint32 num_entries,
   1489             uint32 *counter_indexes,
   1490             bcm_stat_value_t *counter_values)
   1491 {
   1492     uint32                          table_count=0;
   1493     uint32                          index_count=0;
   1494     uint32                          num_of_tables=0;
   1495     bcm_stat_flex_direction_t       direction=bcmStatFlexDirectionIngress;
   1496     uint32                          byte_flag=0;
   1497     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   1498 
   1499     if ((stat == bcmIpmcInPackets) ||
   1500         (stat == bcmIpmcInBytes)) {
   1501          direction = bcmStatFlexDirectionIngress;
   1502     } else {
   1503          /* direction = bcmStatFlexDirectionEgress; */
   1504          return BCM_E_PARAM;
   1505     }
   1506     if (stat == bcmIpmcInPackets) {
   1507         byte_flag=0;
   1508     } else {
   1509         byte_flag=1; 
   1510     }
   1511 
   1512     BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_stat_get_table_info(
   1513                    unit, info,&num_of_tables,&table_info[0]));
   1514 
   1515     for (table_count=0; table_count < num_of_tables ; table_count++) {
   1516       if (table_info[table_count].direction == direction) {
   1517           for (index_count=0; index_count < num_entries ; index_count++) {
   1518                /*ctr_offset_info.offset_index = counter_indexes[index_count];*/
   1519             BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_get(
   1520                          unit, sync_mode,
   1521                          table_info[table_count].index,
   1522                          table_info[table_count].table,
   1523                          0,
   1524                          byte_flag,
   1525                          counter_indexes[index_count],
   1526                          &counter_values[index_count]));
   1527           }
   1528       }
   1529     }
   1530     return BCM_E_NONE;
   1531 }
   1532 
   1533 /*
   1534  * Function:
   1535  *      _bcm_td2_ipmc_stat_counter_set
   1536  * Description:
   1537  *      Set counter statistic values for specific IPMC group
   1538  *
   1539  * Parameters:
   1540  *      unit             - (IN) unit number
   1541  *      info             - (IN) IPMC group information
   1542  *      stat             - (IN) Type of the counter to retrieve
   1543  *                              I.e. ingress/egress byte/packet)
   1544  *      num_entries      - (IN) Number of counter Entries
   1545  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   1546  *      counter_values   - (IN) Pointer to counter values
   1547  *
   1548  * Return Value:
   1549  *      BCM_E_XXX
   1550  * Notes:
   1551  */
   1552 bcm_error_t 
   1553 _bcm_td2_ipmc_stat_counter_set(
   1554             int unit,
   1555             bcm_ipmc_addr_t *info,
   1556             bcm_ipmc_stat_t stat,
   1557             uint32 num_entries,
   1558             uint32 *counter_indexes,
   1559             bcm_stat_value_t *counter_values)
   1560 {
   1561     uint32                          table_count=0;
   1562     uint32                          index_count=0;
   1563     uint32                          num_of_tables=0;
   1564     bcm_stat_flex_direction_t       direction=bcmStatFlexDirectionIngress;
   1565     uint32                          byte_flag=0;
   1566     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   1567     
   1568     if ((stat == bcmIpmcInPackets) ||
   1569         (stat == bcmIpmcInBytes)) {
   1570          direction = bcmStatFlexDirectionIngress;
   1571     } else {
   1572          /* direction = bcmStatFlexDirectionEgress; */
   1573          return BCM_E_PARAM;
   1574     }
   1575     if (stat == bcmIpmcInPackets) {
   1576         byte_flag=0;
   1577     } else {
   1578         byte_flag=1; 
   1579     }
   1580 
   1581     BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_stat_get_table_info(
   1582                    unit, info,&num_of_tables,&table_info[0]));
   1583 
   1584     for (table_count=0; table_count < num_of_tables ; table_count++) {
   1585       if (table_info[table_count].direction == direction) {
   1586           for (index_count=0; index_count < num_entries ; index_count++) {
   1587             BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_set(
   1588                                 unit,
   1589                                 table_info[table_count].index,
   1590                                 table_info[table_count].table,
   1591                                 0,
   1592                                 byte_flag,
   1593                                 counter_indexes[index_count],
   1594                                 &counter_values[index_count]));
   1595           }
   1596       }
   1597     }
   1598     return BCM_E_NONE;
   1599 }
   1600 
   1601 /*
   1602  * Function:
   1603  *      _bcm_td2_ipmc_stat_multi_get
   1604  *
   1605  * Description:
   1606  *  Get Multiple IPMC group counter value for specified IPMC group index for multiple stat
   1607  *  types
   1608  *
   1609  * Parameters:
   1610  *      unit             - (IN) unit number
   1611  *      info	 - (IN) IPMC group Info
   1612  *      nstat            - (IN) Number of elements in stat array
   1613  *      stat_arr         - (IN) Collected statistics descriptors array
   1614  *      value_arr        - (OUT) Collected counters values
   1615  *
   1616  * Return Value:
   1617  *      BCM_E_XXX
   1618  * Notes:
   1619  */
   1620  bcm_error_t  _bcm_td2_ipmc_stat_multi_get(
   1621                             int                 unit, 
   1622                             bcm_ipmc_addr_t	    *info,
   1623                             int                 nstat, 
   1624                             bcm_ipmc_stat_t     *stat_arr,
   1625                             uint64              *value_arr)
   1626 {
   1627     int              rv = BCM_E_NONE;
   1628     int              idx;
   1629     uint32           counter_indexes = 0;
   1630     bcm_stat_value_t counter_values = {0};
   1631     int              sync_mode = 0; 
   1632 
   1633     /* Iterate of all stats array to retrieve flex counter values */
   1634     for (idx = 0; idx < nstat ;idx++) {
   1635          BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_stat_counter_get( 
   1636                              unit, sync_mode, info, stat_arr[idx], 
   1637                              1, &counter_indexes, &counter_values));
   1638          if ((stat_arr[idx] == bcmIpmcInPackets)) {
   1639              COMPILER_64_SET(value_arr[idx],
   1640                              COMPILER_64_HI(counter_values.packets64),
   1641                              COMPILER_64_LO(counter_values.packets64));
   1642          } else {
   1643              COMPILER_64_SET(value_arr[idx],
   1644                              COMPILER_64_HI(counter_values.bytes),
   1645                              COMPILER_64_LO(counter_values.bytes));
   1646          }
   1647     }
   1648     return rv;
   1649 }
   1650 
   1651 /*
   1652  * Function:
   1653  *      _bcm_td2_ipmc_stat_multi_get32
   1654  *
   1655  * Description:
   1656  *  Get 32bit IPMC group counter value for specified IPMC group index for multiple stat
   1657  *  types
   1658  *
   1659  * Parameters:
   1660  *      unit             - (IN) unit number
   1661  *      info	 - (IN) IPMC group Info
   1662  *      nstat            - (IN) Number of elements in stat array
   1663  *      stat_arr         - (IN) Collected statistics descriptors array
   1664  *      value_arr        - (OUT) Collected counters values
   1665  *
   1666  * Return Value:
   1667  *      BCM_E_XXX
   1668  * Notes:
   1669  */
   1670 bcm_error_t  _bcm_td2_ipmc_stat_multi_get32(
   1671                             int                 unit, 
   1672                             bcm_ipmc_addr_t	    *info,
   1673                             int                 nstat, 
   1674                             bcm_ipmc_stat_t     *stat_arr,
   1675                             uint32              *value_arr)
   1676 {
   1677     int              rv = BCM_E_NONE;
   1678     int              idx;
   1679     uint32           counter_indexes = 0;
   1680     bcm_stat_value_t counter_values = {0};
   1681     int              sync_mode = 0; 
   1682 
   1683     /* Iterate of all stats array to retrieve flex counter values */
   1684     for (idx = 0; idx < nstat ;idx++) {
   1685          BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_stat_counter_get( 
   1686                              unit, sync_mode, info, stat_arr[idx], 
   1687                              1, &counter_indexes, &counter_values));
   1688          if ((stat_arr[idx] == bcmIpmcInPackets)) {
   1689                 value_arr[idx] = counter_values.packets;
   1690          } else {
   1691              value_arr[idx] = COMPILER_64_LO(counter_values.bytes);
   1692          }
   1693     }
   1694     return rv;
   1695 }
   1696 
   1697 /*
   1698  * Function:
   1699  *     _bcm_td2_ipmc_stat_multi_set
   1700  *
   1701  * Description:
   1702  *  Set IPMC group counter value for specified IPMC group index for multiple stat
   1703  *  types
   1704  *
   1705  * Parameters:
   1706  *      unit             - (IN) unit number
   1707  *      info	- (IN) IPMC group Info
   1708  *      stat             - (IN) IPMC group counter stat types
   1709  *      num_entries      - (IN) Number of counter Entries
   1710  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   1711  *      counter_values   - (OUT) Pointer to counter values
   1712  *
   1713  * Return Value:
   1714  *      BCM_E_XXX
   1715  * Notes:
   1716  */
   1717 bcm_error_t  _bcm_td2_ipmc_stat_multi_set(
   1718                             int                 unit, 
   1719                             bcm_ipmc_addr_t	    *info,
   1720                             int                 nstat, 
   1721                             bcm_ipmc_stat_t     *stat_arr,
   1722                             uint64              *value_arr)
   1723 {
   1724     int              rv = BCM_E_NONE;
   1725     int              idx;
   1726     uint32           counter_indexes = 0;
   1727     bcm_stat_value_t counter_values = {0};
   1728 
   1729     /* Iterate f all stats array to retrieve flex counter values */
   1730     for (idx = 0; idx < nstat ;idx++) {
   1731          if ((stat_arr[idx] == bcmIpmcInPackets)) {
   1732               counter_values.packets = COMPILER_64_LO(value_arr[idx]);
   1733          } else {
   1734               COMPILER_64_SET(counter_values.bytes,
   1735                               COMPILER_64_HI(value_arr[idx]),
   1736                               COMPILER_64_LO(value_arr[idx]));
   1737          }
   1738           BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_stat_counter_set( 
   1739                              unit, info, stat_arr[idx], 
   1740                              1, &counter_indexes, &counter_values));
   1741     }
   1742     return rv;
   1743 
   1744 }
   1745 
   1746 /*
   1747  * Function:
   1748  *      _bcm_td2_ipmc_stat_multi_set32
   1749  *
   1750  * Description:
   1751  *  Set 32bit IPMC group counter value for specified IPMC group index for multiple stat
   1752  *  types
   1753  *
   1754  * Parameters:
   1755  *      unit             - (IN) unit number
   1756  *      info			 - (IN) IPMC group Info
   1757  *      stat             - (IN) IPMC group counter stat types
   1758  *      num_entries      - (IN) Number of counter Entries
   1759  *      counter_indexes  - (IN) Pointer to Counter indexes entries
   1760  *      counter_values   - (OUT) Pointer to counter values
   1761  *
   1762  * Return Value:
   1763  *      BCM_E_XXX
   1764  * Notes:
   1765  */
   1766 
   1767  bcm_error_t  _bcm_td2_ipmc_stat_multi_set32(
   1768                             int                 unit, 
   1769                             bcm_ipmc_addr_t	    *info,
   1770                             int                 nstat, 
   1771                             bcm_ipmc_stat_t     *stat_arr,
   1772                             uint32              *value_arr)
   1773 {
   1774     int              rv = BCM_E_NONE;
   1775     int              idx;
   1776     uint32           counter_indexes = 0;
   1777     bcm_stat_value_t counter_values = {0};
   1778 
   1779     /* Iterate of all stats array to retrieve flex counter values */
   1780     for (idx = 0; idx < nstat ;idx++) {
   1781          if ((stat_arr[idx] == bcmIpmcInPackets)) {
   1782              counter_values.packets = value_arr[idx];
   1783          } else {
   1784              COMPILER_64_SET(counter_values.bytes,0,value_arr[idx]);
   1785          }
   1786 
   1787          BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_stat_counter_set( 
   1788                              unit, info, stat_arr[idx], 
   1789                              1, &counter_indexes, &counter_values));
   1790     }
   1791     return rv;
   1792 }
   1793 
   1794 /*
   1795  * Function:
   1796  *      _bcm_td2_ipmc_stat_id_get
   1797  * Description:
   1798  *      Get stat counter id associated with given IPMC group
   1799  *
   1800  * Parameters:
   1801  *      unit             - (IN) unit number
   1802  *      info             - (IN) IPMC group information
   1803  *      stat             - (IN) Type of the counter to retrieve
   1804  *                              I.e. ingress/egress byte/packet)
   1805  *      Stat_counter_id  - (OUT) Stat Counter ID
   1806  * Return Value:
   1807  *      BCM_E_XXX
   1808  * Notes:
   1809  */
   1810 bcm_error_t 
   1811 _bcm_td2_ipmc_stat_id_get(
   1812             int unit,
   1813             bcm_ipmc_addr_t *info,
   1814             bcm_ipmc_stat_t stat,
   1815             uint32 *stat_counter_id)
   1816 {
   1817     bcm_stat_flex_direction_t  direction=bcmStatFlexDirectionIngress;
   1818     uint32                     num_of_tables=0;
   1819     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   1820     uint32                     index=0;
   1821     uint32                     num_stat_counter_ids=0;
   1822 
   1823     if ((stat == bcmIpmcInPackets) ||
   1824         (stat == bcmIpmcInBytes)) {
   1825          direction = bcmStatFlexDirectionIngress;
   1826     } else {
   1827          /* direction = bcmStatFlexDirectionEgress; */
   1828          return BCM_E_PARAM;
   1829     }
   1830 
   1831     BCM_IF_ERROR_RETURN(_bcm_td2_ipmc_stat_get_table_info(
   1832                         unit,info,&num_of_tables,&table_info[0]));
   1833     for (index=0; index < num_of_tables ; index++) {
   1834          if (table_info[index].direction == direction)
   1835              return _bcm_esw_stat_flex_get_counter_id(
   1836                                   unit, 1, &table_info[index],
   1837                                   &num_stat_counter_ids,stat_counter_id);
   1838     }
   1839     return BCM_E_NOT_FOUND;
   1840 }
   1841 
   1842 #ifdef BCM_WARM_BOOT_SUPPORT
   1843 
   1844 /*
   1845  * Function:
   1846  *      bcm_td2_ipmc_pim_bidir_scache_size_get
   1847  * Purpose:
   1848  *      Get the required scache size for PIM-BIDIR feature.
   1849  * Parameters:
   1850  *      unit - StrataSwitch unit #
   1851  *      size - (OUT) Number of bytes
   1852  * Returns:
   1853  *      BCM_E_xxx
   1854  */
   1855 int 
   1856 bcm_td2_ipmc_pim_bidir_scache_size_get(
   1857     int unit, 
   1858     uint32 *size)
   1859 {
   1860     int num_rp;
   1861 
   1862     *size = 0;
   1863     num_rp = soc_mem_field_length(unit, ING_ACTIVE_L3_IIF_PROFILEm,
   1864             RPA_ID_PROFILEf);
   1865     *size += SHR_BITALLOCSIZE(num_rp);
   1866 
   1867     return BCM_E_NONE;
   1868 }
   1869 
   1870 /*
   1871  * Function:
   1872  *      bcm_td2_ipmc_pim_bidir_sync
   1873  * Purpose:
   1874  *      Record PIM-BIDIR persistent info into the scache.
   1875  * Parameters:
   1876  *      unit - StrataSwitch unit #
   1877  *      scache_ptr - (IN/OUT) Scache pointer
   1878  * Returns:
   1879  *      BCM_E_xxx
   1880  */
   1881 int 
   1882 bcm_td2_ipmc_pim_bidir_sync(
   1883     int unit, 
   1884     uint8 **scache_ptr)
   1885 {
   1886     int num_rp, i;
   1887     SHR_BITDCL *rp_bitmap = NULL;
   1888 
   1889     if (_bcm_td2_pim_bidir_info[unit] == NULL) {
   1890         return BCM_E_INIT;
   1891     }
   1892     /* Create a bitmap of valid rendezvous points */
   1893     num_rp = soc_mem_field_length(unit, ING_ACTIVE_L3_IIF_PROFILEm,
   1894             RPA_ID_PROFILEf);
   1895     rp_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_rp), "RP bitmap");
   1896     if (NULL == rp_bitmap) {
   1897         return BCM_E_MEMORY;
   1898     }
   1899     sal_memset(rp_bitmap, 0, SHR_BITALLOCSIZE(num_rp));
   1900     for (i = 0; i < num_rp; i++) {
   1901         if (IPMC_RP_INFO(unit, i)->valid) {
   1902             SHR_BITSET(rp_bitmap, i);
   1903         }
   1904     }
   1905 
   1906     /* Store the bitmap of valid rendezvous points into scache */
   1907     sal_memcpy((*scache_ptr), rp_bitmap, SHR_BITALLOCSIZE(num_rp));
   1908     (*scache_ptr) += SHR_BITALLOCSIZE(num_rp);
   1909 
   1910     sal_free(rp_bitmap);
   1911     return BCM_E_NONE;
   1912 }
   1913 
   1914 /*
   1915  * Function:
   1916  *      bcm_td2_ipmc_pim_bidir_scache_recover
   1917  * Purpose:
   1918  *      Recover PIM-BIDIR info from scache.
   1919  * Parameters:
   1920  *      unit - (IN) SOC unit number.
   1921  *      scache_ptr - (IN/OUT) Scache pointer
   1922  * Returns:
   1923  *      BCM_E_XXX
   1924  */
   1925 int
   1926 bcm_td2_ipmc_pim_bidir_scache_recover(int unit, uint8 **scache_ptr) 
   1927 {
   1928     int num_rp, i;
   1929     SHR_BITDCL *rp_bitmap = NULL;
   1930 
   1931     /* Recover a bitmap of valid rendezvous points */
   1932     num_rp = soc_mem_field_length(unit, ING_ACTIVE_L3_IIF_PROFILEm,
   1933             RPA_ID_PROFILEf);
   1934     rp_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_rp), "RP bitmap");
   1935     if (NULL == rp_bitmap) {
   1936         return BCM_E_MEMORY;
   1937     }
   1938     sal_memcpy(rp_bitmap, (*scache_ptr), SHR_BITALLOCSIZE(num_rp));
   1939     for (i = 0; i < num_rp; i++) {
   1940         if (SHR_BITGET(rp_bitmap, i)) {
   1941             IPMC_RP_INFO(unit, i)->valid = 1;
   1942         }
   1943     }
   1944     (*scache_ptr) += SHR_BITALLOCSIZE(num_rp);
   1945 
   1946     sal_free(rp_bitmap);
   1947     return BCM_E_NONE;
   1948 }
   1949 
   1950 /*
   1951  * Function:
   1952  *      _bcm_td2_ipmc_pim_bidir_recover
   1953  * Purpose:
   1954  *      Recover PIM-BIDIR info from hardware.
   1955  * Parameters:
   1956  *      unit - StrataSwitch unit #
   1957  * Returns:
   1958  *      BCM_E_xxx
   1959  */
   1960 STATIC int 
   1961 _bcm_td2_ipmc_pim_bidir_recover(int unit)
   1962 {
   1963     int rv = BCM_E_NONE;
   1964     int buf_size;
   1965     uint8 *l3_iif_buf = NULL;
   1966     int i;
   1967     iif_entry_t *l3_iif_entry_ptr = NULL;
   1968     int profile_index;
   1969     ing_active_l3_iif_profile_entry_t profile_entry;
   1970     int rp_bitmap_length;
   1971     SHR_BITDCL *rp_bitmap = NULL;
   1972     int rp_id;
   1973     _bcm_td2_l3_iif_t *current_ptr;
   1974     uint8 *tcam_buf = NULL;
   1975     ip_multicast_tcam_entry_t *tcam_entry_ptr = NULL;
   1976 
   1977     /* Read L3 IIF table */
   1978     buf_size = sizeof(iif_entry_t) * soc_mem_index_count(unit, L3_IIFm);
   1979     l3_iif_buf = soc_cm_salloc(unit, buf_size, "L3 IIF buffer");
   1980     if (NULL == l3_iif_buf) {
   1981         rv = BCM_E_MEMORY;
   1982         goto clean_up;
   1983     }
   1984     rv = soc_mem_read_range(unit, L3_IIFm, MEM_BLOCK_ANY,
   1985             soc_mem_index_min(unit, L3_IIFm),
   1986             soc_mem_index_max(unit, L3_IIFm), l3_iif_buf);
   1987     if (SOC_FAILURE(rv)) {
   1988         goto clean_up;
   1989     }
   1990 
   1991     /* Traverse each entry of L3 IIF table */
   1992     for (i = soc_mem_index_min(unit, L3_IIFm);
   1993             i <= soc_mem_index_max(unit, L3_IIFm); i++) {
   1994         l3_iif_entry_ptr = soc_mem_table_idx_to_pointer(unit, L3_IIFm,
   1995                 iif_entry_t *, l3_iif_buf, i);
   1996 
   1997         /* Recover active L3 IIF profile reference count */
   1998         profile_index = soc_L3_IIFm_field32_get(unit, l3_iif_entry_ptr,
   1999                 ACTIVE_L3_IIF_PROFILE_INDEXf); 
   2000         SOC_PROFILE_MEM_REFERENCE(unit, IPMC_ACTIVE_L3_IIF_PROFILE(unit),
   2001                 profile_index, 1);
   2002         SOC_PROFILE_MEM_ENTRIES_PER_SET(unit, IPMC_ACTIVE_L3_IIF_PROFILE(unit),
   2003                 profile_index, 1);
   2004 
   2005         /* Get a bitmap of the rendezvous points L3 IIF belongs to */
   2006         rv = READ_ING_ACTIVE_L3_IIF_PROFILEm(unit, MEM_BLOCK_ANY,
   2007                 profile_index, &profile_entry);
   2008         if (SOC_FAILURE(rv)) {
   2009             goto clean_up;
   2010         }
   2011         rp_bitmap_length = soc_mem_field_length(unit,
   2012                 ING_ACTIVE_L3_IIF_PROFILEm, RPA_ID_PROFILEf);
   2013         if (NULL == rp_bitmap) {
   2014             rp_bitmap = sal_alloc(SHR_BITALLOCSIZE(rp_bitmap_length),
   2015                     "RP bitmap");
   2016             if (NULL == rp_bitmap) {
   2017                 rv = BCM_E_MEMORY;
   2018                 goto clean_up;
   2019             }
   2020         }
   2021         soc_ING_ACTIVE_L3_IIF_PROFILEm_field_get(unit, &profile_entry,
   2022                 RPA_ID_PROFILEf, rp_bitmap);
   2023 
   2024         /* For each rendezvous point the L3 IIF belongs to,
   2025          * insert the L3 IIF into the rendezvous point's linked list
   2026          * of L3 IIFs.
   2027          */
   2028         for (rp_id = 0; rp_id < rp_bitmap_length; rp_id++) {
   2029             if (SHR_BITGET(rp_bitmap, rp_id)) {
   2030                 IPMC_RP_INFO(unit, rp_id)->valid = 1;
   2031                 current_ptr = sal_alloc(sizeof(_bcm_td2_l3_iif_t),
   2032                         "Active L3 IIF");
   2033                 if (NULL == current_ptr) {
   2034                     rv = BCM_E_MEMORY;
   2035                     goto clean_up;
   2036                 }
   2037                 current_ptr->l3_iif = i;
   2038                 current_ptr->next = IPMC_RP_INFO(unit, rp_id)->l3_iif_list;
   2039                 IPMC_RP_INFO(unit, rp_id)->l3_iif_list = current_ptr;
   2040             }
   2041         }
   2042     }
   2043 
   2044     /* Recover bitmap of valid IPMC TCAM entries */
   2045     buf_size = sizeof(ip_multicast_tcam_entry_t) *
   2046         soc_mem_index_count(unit, IP_MULTICAST_TCAMm);
   2047     tcam_buf = soc_cm_salloc(unit, buf_size, "IP Multicast TCAM buffer");
   2048     if (NULL == tcam_buf) {
   2049         rv = BCM_E_MEMORY;
   2050         goto clean_up;
   2051     }
   2052     rv = soc_mem_read_range(unit, IP_MULTICAST_TCAMm, MEM_BLOCK_ANY,
   2053             soc_mem_index_min(unit, IP_MULTICAST_TCAMm),
   2054             soc_mem_index_max(unit, IP_MULTICAST_TCAMm), tcam_buf);
   2055     if (SOC_FAILURE(rv)) {
   2056         goto clean_up;
   2057     }
   2058     for (i = soc_mem_index_min(unit, IP_MULTICAST_TCAMm);
   2059             i <= soc_mem_index_max(unit, IP_MULTICAST_TCAMm); i++) {
   2060         tcam_entry_ptr = soc_mem_table_idx_to_pointer(unit, IP_MULTICAST_TCAMm,
   2061                 ip_multicast_tcam_entry_t *, tcam_buf, i);
   2062         if (soc_IP_MULTICAST_TCAMm_field32_get(unit, tcam_entry_ptr, VALIDf)) {
   2063             SHR_BITSET(IPMC_TCAM_BITMAP(unit), i);
   2064         }
   2065     }
   2066 
   2067 clean_up:
   2068     if (NULL != l3_iif_buf) {
   2069         soc_cm_sfree(unit, l3_iif_buf);
   2070     }
   2071     if (NULL != rp_bitmap) {
   2072         sal_free(rp_bitmap);
   2073     }
   2074     if (NULL != tcam_buf) {
   2075         soc_cm_sfree(unit, tcam_buf);
   2076     }
   2077     return rv;
   2078 }
   2079 
   2080 /*
   2081  * Function:
   2082  *      bcm_td2_ipmc_rp_ref_count_recover
   2083  * Purpose:
   2084  *      Increment reference count of rendezvous point. If the rendezvous point
   2085  *      is invalid, set it to valid.
   2086  * Parameters:
   2087  *      unit - StrataSwitch unit #
   2088  *      rp_id - Rendezvous point ID
   2089  * Returns:
   2090  *      BCM_E_xxx
   2091  * Notes:
   2092  *      During warm boot recovery, the IPMC address table is traversed to
   2093  *      recover how many IPMC address entries are referencing the rendezvous
   2094  *      points. This function is called to update the reference count.
   2095  *      The traversal of IPCM address table occurs before recovery of
   2096  *      rendezvous point info from scache. Hence, when this function is
   2097  *      called, it's possible that the rendezvous point is not yet marked
   2098  *      valid.
   2099  */
   2100 int 
   2101 bcm_td2_ipmc_rp_ref_count_recover(
   2102     int unit, 
   2103     int rp_id) 
   2104 {
   2105     int rv = BCM_E_NONE;
   2106 
   2107     if (NULL == _bcm_td2_pim_bidir_info[unit]) {
   2108         return BCM_E_INIT;
   2109     }
   2110 
   2111     if ((rp_id < 0) || (rp_id >= IPMC_NUM_RP(unit))) {
   2112         return BCM_E_PARAM;
   2113     }
   2114 
   2115     if (!IPMC_RP_INFO(unit, rp_id)->valid) {
   2116         IPMC_RP_INFO(unit, rp_id)->valid = 1;
   2117     }
   2118 
   2119     IPMC_RP_INFO(unit, rp_id)->ref_count++;
   2120 
   2121     return rv;
   2122 }
   2123 
   2124 #endif /* BCM_WARM_BOOT_SUPPORT */
   2125 
   2126 #ifndef BCM_SW_STATE_DUMP_DISABLE
   2127 /*
   2128  * Function:
   2129  *     _bcm_td2_ipmc_pim_bidir_sw_dump
   2130  * Purpose:
   2131  *     Displays PIM-BIDIR information maintained by software.
   2132  * Parameters:
   2133  *     unit - Device unit number
   2134  * Returns:
   2135  *     None
   2136  */
   2137 void
   2138 _bcm_td2_ipmc_pim_bidir_sw_dump(int unit)
   2139 {
   2140     int rv;
   2141     int i, j;
   2142     int num_profiles, ref_count;
   2143 
   2144     LOG_CLI((BSL_META_U(unit,
   2145                         "    PIM-BIDIR Rendezvous Points Size: %d\n"),
   2146              IPMC_NUM_RP(unit)));
   2147 
   2148     LOG_CLI((BSL_META_U(unit,
   2149                         "    Allocated Rendezvous Points (ID:reference count):")));
   2150     for (i = 0, j = 0; i < IPMC_NUM_RP(unit); i++) {
   2151         if (!IPMC_RP_INFO(unit, i)->valid) {
   2152             continue;
   2153         }
   2154         if (!(j % 10)) {
   2155             LOG_CLI((BSL_META_U(unit,
   2156                                 "\n    ")));
   2157         }
   2158         LOG_CLI((BSL_META_U(unit,
   2159                             "  %2d:%-6d"), i, IPMC_RP_INFO(unit, i)->ref_count));
   2160         j++;
   2161     }
   2162     LOG_CLI((BSL_META_U(unit,
   2163                         "\n")));
   2164 
   2165     LOG_CLI((BSL_META_U(unit,
   2166                         "    Active L3 IIF profile (index:reference count):")));
   2167     num_profiles = soc_mem_index_count(unit, ING_ACTIVE_L3_IIF_PROFILEm);
   2168     for (i = 0, j = 0; i < num_profiles; i++) {
   2169         rv = soc_profile_mem_ref_count_get(unit,
   2170                 IPMC_ACTIVE_L3_IIF_PROFILE(unit), i, &ref_count);
   2171         if (SOC_FAILURE(rv)) {
   2172             continue;
   2173         }
   2174         if (0 == ref_count) {
   2175             continue;
   2176         }
   2177         if (!(j % 10)) {
   2178             LOG_CLI((BSL_META_U(unit,
   2179                                 "\n    ")));
   2180         }
   2181         LOG_CLI((BSL_META_U(unit,
   2182                             "  %4d:%-4d"), i, ref_count));
   2183         j++;
   2184     }
   2185     LOG_CLI((BSL_META_U(unit,
   2186                         "\n")));
   2187 
   2188     return;
   2189 }
   2190 
   2191 #endif /* BCM_SW_STATE_DUMP_DISABLE */
   2192 
   2193 /*
   2194  * Function:
   2195  *     _bcm_td2_ipv6_reserved_multicast_addr_set
   2196  * Description:
   2197  *     Set ipv6 reserved multicast address and mask.
   2198  *
   2199  * Parameters:
   2200  *      unit             - (IN) unit number
   2201  *      ip6_addr         - (IN) ipv6 address
   2202  *      ip6_mask         - (IN) ipv6 addres mask
   2203  *
   2204  * Return Value:
   2205  *      BCM_E_XXX
   2206  * Notes:
   2207  */
   2208 int
   2209 _bcm_td2_ipv6_reserved_multicast_addr_set(int unit,
   2210                                           bcm_ip6_t ip6_addr,
   2211                                           bcm_ip6_t ip6_mask)
   2212 {
   2213 
   2214     soc_mem_t mem;
   2215     uint32    ip6_fields[4];
   2216     uint32    entry_buf[SOC_MAX_MEM_FIELD_WORDS];
   2217 
   2218     mem = ING_IPV6_MC_RESERVED_ADDRESSm;
   2219     if (soc_mem_is_valid(unit, PARSER1_ING_IPV6_MC_RESERVED_ADDRESSm)) {
   2220         mem = PARSER1_ING_IPV6_MC_RESERVED_ADDRESSm;
   2221     }
   2222     /* clear entry memory */
   2223     sal_memset(entry_buf, 0, sizeof(entry_buf));
   2224     /* encode v6 address into ip6_fields */
   2225     SAL_IP6_ADDR_TO_UINT32(ip6_addr, ip6_fields);
   2226     /* set address in entry */
   2227     soc_mem_field_set(unit, mem, entry_buf, ADDRESSf, &(ip6_fields[0]));
   2228     /* encode v6 mask into ip6_fields */
   2229     SAL_IP6_ADDR_TO_UINT32(ip6_mask, ip6_fields);
   2230     /* set the mask in entry */
   2231     soc_mem_field_set(unit, mem, entry_buf, MASKf, &(ip6_fields[0]));
   2232     /* write entry to hardware */
   2233     BCM_IF_ERROR_RETURN(soc_mem_write(unit, mem, MEM_BLOCK_ALL, 0,
   2234                                       entry_buf));
   2235     return BCM_E_NONE;
   2236 }
   2237 
   2238 /*
   2239  * Function:
   2240  *     _bcm_td2_ipv6_reserved_multicast_addr_get
   2241  * Description:
   2242  *     get the ipv6 reserved multicast address and mask
   2243  *
   2244  * Parameters:
   2245  *      unit             - (IN) unit number
   2246  *      ip6_addr         - (OUT) ipv6 address
   2247  *      ip6_mask         - (OUT) ipv6 addres mask
   2248  *
   2249  * Return Value:
   2250  *      BCM_E_XXX
   2251  * Notes:
   2252  */
   2253 int
   2254 _bcm_td2_ipv6_reserved_multicast_addr_get(int unit,
   2255                                           bcm_ip6_t *ip6_addr,
   2256                                           bcm_ip6_t *ip6_mask)
   2257 {
   2258     soc_mem_t mem;
   2259     uint32    ip6_fields[4];
   2260     uint32    entry_buf[SOC_MAX_MEM_FIELD_WORDS];
   2261 
   2262     /* sanity checks first */
   2263     if (!ip6_addr) {
   2264         return BCM_E_PARAM;
   2265     }
   2266 
   2267     if (!ip6_mask) {
   2268         return BCM_E_PARAM;
   2269     }
   2270 
   2271     mem = ING_IPV6_MC_RESERVED_ADDRESSm;
   2272     if (soc_mem_is_valid(unit, PARSER1_ING_IPV6_MC_RESERVED_ADDRESSm)) {
   2273         mem = PARSER1_ING_IPV6_MC_RESERVED_ADDRESSm;
   2274     }
   2275     /* clear entry memory */
   2276     sal_memset(entry_buf, 0, sizeof(entry_buf));
   2277     /* read entry from hardware */
   2278     BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, MEM_BLOCK_ALL, 0, entry_buf));
   2279     /* deduce the address from entry */
   2280     soc_mem_field_get(unit, mem, entry_buf, ADDRESSf, &(ip6_fields[0]));
   2281     /* set the address in user buf */
   2282     SAL_IP6_ADDR_FROM_UINT32(*ip6_addr, ip6_fields);
   2283 
   2284     /* deduce the mask from entry */
   2285     soc_mem_field_get(unit, mem, entry_buf, MASKf, &(ip6_fields[0]));
   2286     /* set the mask in user buf */
   2287     SAL_IP6_ADDR_FROM_UINT32(*ip6_mask, ip6_fields);
   2288 
   2289     return BCM_E_NONE;
   2290 }
   2291 
   2292 #endif /* BCM_TRIDENT2_SUPPORT && INCLUDE_L3 */