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

niv.c (231906B)


      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:    niv.c
      8  * Purpose: Implements NIV APIs for Trident.
      9  */
     10 
     11 #include <shared/bsl.h>
     12 
     13 #include <soc/defs.h>
     14 #include <sal/core/libc.h>
     15 #if defined(BCM_TRIDENT_SUPPORT) && defined(INCLUDE_L3)
     16 
     17 #include <soc/drv.h>
     18 #include <soc/scache.h>
     19 #include <soc/hash.h>
     20 #include <soc/l2x.h>
     21 #if defined(BCM_TRIDENT3_SUPPORT)
     22 #include <soc/trident3.h>
     23 #endif
     24 
     25 #include <bcm/error.h>
     26 
     27 #include <bcm_int/esw_dispatch.h>
     28 #include <bcm_int/api_xlate_port.h>
     29 #include <bcm_int/common/multicast.h>
     30 #include <bcm_int/esw/stack.h>
     31 #include <bcm_int/esw/virtual.h>
     32 #include <bcm_int/esw/port.h>
     33 #include <bcm_int/esw/switch.h>
     34 #include <bcm_int/esw/trunk.h>
     35 #include <bcm_int/esw/firebolt.h>
     36 #include <bcm_int/esw/trx.h>
     37 #include <bcm_int/esw/triumph2.h>
     38 #include <bcm_int/esw/trident.h>
     39 #include <bcm_int/esw/triumph3.h>
     40 #include <bcm_int/esw/tomahawk.h>
     41 #include <bcm_int/esw/niv.h>
     42 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
     43 #include <bcm_int/esw/trident2plus.h>
     44 #include <bcm_int/esw/xgs5.h>
     45 #endif /* BCM_TRIDENT2PLUS_SUPPORT*/
     46 
     47 #include <soc/katana2.h>
     48 #if defined(BCM_SABER2_SUPPORT)
     49 #include <soc/saber2.h>
     50 #endif /* BCM_SABER2_SUPPORT */
     51 
     52 #define _NIV_ENTRY_TYPEf(u, mem) (soc_mem_field_valid(u, mem, DATA_TYPEf) ? \
     53                                   DATA_TYPEf : ENTRY_TYPEf)
     54 /*
     55  * Software book keeping for NIV related information
     56  */
     57 typedef struct _bcm_trident_niv_egress_s {
     58     uint32 flags;
     59     bcm_gport_t port;
     60     uint16 virtual_interface_id;
     61     bcm_vlan_t match_vlan;
     62     uint16 service_tpid;
     63     bcm_vlan_t service_vlan;
     64     uint8 service_pri;
     65     uint8 service_cfi;
     66     int service_qos_map_id;
     67     int next_hop_index;
     68     bcm_if_t intf;  
     69     uint32 multicast_flags;
     70     struct _bcm_trident_niv_egress_s *next; /* Pointer to next NIV egress
     71                                                object */
     72 } _bcm_trident_niv_egress_t;
     73 
     74 typedef struct _bcm_trident_niv_nh_info_s {
     75     bcm_port_t   port;
     76     int          nh_ref_cnt;
     77     struct       _bcm_trident_niv_nh_info_s *next;
     78 } _bcm_trident_niv_nh_info_t;
     79 
     80 typedef struct _bcm_trident_niv_port_info_s {
     81     uint32 flags;
     82     bcm_gport_t port;
     83     bcm_pbmp_t tp_pbmp; /* trunk port members pbmp */
     84     uint16 virtual_interface_id;
     85     bcm_vlan_t match_vlan;
     86     _bcm_trident_niv_egress_t *egress_list; /* Linked list of NIV egress
     87                                                objects */
     88     _bcm_trident_niv_nh_info_t *mc_nh_info;
     89                                /* nh info for multicast egress objects. */
     90 } _bcm_trident_niv_port_info_t;
     91 
     92 #define  TD_NIV_PORT_HASH_BKT_SIZE           32
     93 typedef struct _bcm_trident_niv_bookkeeping_s {
     94     _bcm_trident_niv_port_info_t *port_info; /* VP state */
     95     int invalid_next_hop_index;
     96 } _bcm_trident_niv_bookkeeping_t;
     97 
     98 STATIC _bcm_trident_niv_bookkeeping_t _bcm_trident_niv_bk_info[BCM_MAX_NUM_UNITS];
     99 
    100 #define NIV_INFO(unit) (&_bcm_trident_niv_bk_info[unit])
    101 #define NIV_PORT_INFO(unit, vp) (&NIV_INFO(unit)->port_info[vp])
    102 #define NIV_PORT_HASH_BKT(unit, vp, idx) \
    103             (&(NIV_PORT_INFO(unit, vp)->egress_list[idx]))
    104 #define NIV_PORT_MC_NH_INFO(unit, vp) (NIV_PORT_INFO(unit, vp)->mc_nh_info)
    105 
    106 /* Structure to facilitate passing of SD-tag parameters */
    107 typedef struct _bcm_trident_niv_sd_tag_s {
    108     uint32 flags;
    109     uint16 service_tpid;
    110     bcm_vlan_t service_vlan;
    111     uint8 service_pri;
    112     uint8 service_cfi;
    113     int service_qos_map_id;
    114 } _bcm_trident_niv_sd_tag_t;
    115 
    116 STATIC int
    117 _bcm_trident_niv_egress_hash_calc(int unit, void *hash_key, uint16 *hash);
    118 STATIC int
    119 _bcm_trident_niv_egress_pbmp_add(int unit, int vp, bcm_pbmp_t pbmp);
    120 
    121 /*
    122  * Function:
    123  *      _bcm_trident_niv_port_cnt_update
    124  * Purpose:
    125  *      Update port's VP count.
    126  * Parameters:
    127  *      unit  - (IN) SOC unit number. 
    128  *      gport - (IN) GPORT ID.
    129  *      vp    - (IN) Virtual port number.
    130  *      incr  - (IN) If TRUE, increment VP count, else decrease VP count.
    131  * Returns:
    132  *      BCM_X_XXX
    133  */
    134 STATIC int
    135 _bcm_trident_niv_port_cnt_update(int unit, bcm_gport_t gport,
    136         int vp, int incr, int ingress)
    137 {
    138     int mod_out, port_out, tgid_out, id_out;
    139     bcm_port_t local_member_array[SOC_MAX_NUM_PORTS];
    140     int local_member_count;
    141     int idx;
    142     int mod_local;
    143     _bcm_port_info_t *port_info;
    144     uint32 port_flags;
    145 #if defined(BCM_HGPROXY_COE_SUPPORT)
    146     int is_local_subport;
    147 #endif
    148 
    149     BCM_IF_ERROR_RETURN
    150         (_bcm_esw_gport_resolve(unit, gport, &mod_out, 
    151                                 &port_out, &tgid_out, &id_out));
    152     if (-1 != id_out) {
    153         return BCM_E_PARAM;
    154     }
    155 
    156     /* Update the physical port's SW state. If associated with a trunk,
    157      * update each local physical port's SW state.
    158      */
    159 
    160     if (BCM_TRUNK_INVALID != tgid_out) {
    161 
    162         BCM_IF_ERROR_RETURN(_bcm_esw_trunk_local_members_get(unit, tgid_out, 
    163                     SOC_MAX_NUM_PORTS, local_member_array, &local_member_count));
    164 
    165         if (ingress) {
    166             bcm_pbmp_t pbmp;
    167 
    168             BCM_PBMP_CLEAR(pbmp);
    169 
    170             for (idx = 0; idx < local_member_count; idx++) {
    171                 BCM_PBMP_PORT_ADD(pbmp, local_member_array[idx]);
    172             }
    173             
    174             if (incr) {
    175                 BCM_PBMP_ASSIGN(NIV_PORT_INFO(unit, vp)->tp_pbmp, pbmp);
    176             }
    177             
    178             BCM_PBMP_ITER(NIV_PORT_INFO(unit, vp)->tp_pbmp, port_out) {
    179                 _bcm_port_info_access(unit, port_out, &port_info);
    180                 if (incr) {
    181                     port_info->vp_count++;
    182                 } else {
    183                     port_info->vp_count--;
    184                 }
    185                 BCM_IF_ERROR_RETURN(
    186                     bcm_esw_port_vlan_member_get(unit, port_out, &port_flags));
    187                 BCM_IF_ERROR_RETURN(
    188                     bcm_esw_port_vlan_member_set(unit, port_out, port_flags));
    189             }
    190             
    191             if (!incr) {
    192                 BCM_PBMP_ASSIGN(NIV_PORT_INFO(unit, vp)->tp_pbmp, pbmp);
    193             }
    194         } else {
    195             for (idx = 0; idx < local_member_count; idx++) {
    196                 _bcm_port_info_access(unit, local_member_array[idx], &port_info);
    197                 if (incr) {
    198                     port_info->vp_count++;
    199                 } else {
    200                     port_info->vp_count--;
    201                 }
    202                 BCM_IF_ERROR_RETURN(
    203                     bcm_esw_port_vlan_member_get(
    204                         unit, local_member_array[idx], &port_flags));
    205                 BCM_IF_ERROR_RETURN(
    206                     bcm_esw_port_vlan_member_set(
    207                         unit, local_member_array[idx], port_flags));
    208             }
    209         }
    210     } else {
    211 #if defined(BCM_HGPROXY_COE_SUPPORT)
    212         BCM_IF_ERROR_RETURN(
    213             _bcm_esw_port_is_local_subport(
    214                 unit, gport, mod_out, port_out, &is_local_subport, &port_out));
    215         if (is_local_subport) {
    216             mod_local = TRUE;
    217         } else
    218 #endif
    219         {
    220             BCM_IF_ERROR_RETURN(
    221                 _bcm_esw_modid_is_local(unit, mod_out, &mod_local));
    222         }
    223         if (mod_local) {
    224             if (soc_feature(unit, soc_feature_sysport_remap)) { 
    225                 BCM_XLATE_SYSPORT_S2P(unit, &port_out); 
    226             }
    227             _bcm_port_info_access(unit, port_out, &port_info);
    228             if (incr) {
    229                 port_info->vp_count++;
    230             } else {
    231                 port_info->vp_count--;
    232             }
    233             BCM_IF_ERROR_RETURN(
    234                     bcm_esw_port_vlan_member_get(unit, port_out, &port_flags));
    235             BCM_IF_ERROR_RETURN(
    236                     bcm_esw_port_vlan_member_set(unit, port_out, port_flags));
    237         }
    238     }
    239 
    240     return BCM_E_NONE;
    241 }
    242 
    243 STATIC int
    244 _bcm_trident_niv_tpid_enb_get(int unit, uint32 *svp_ent, int vp, int *tpid_enb)
    245 {
    246     soc_mem_t mem = SOURCE_VPm;
    247 
    248     if (soc_mem_field_valid(unit, SVP_ATTRS_1m, TPID_ENABLEf)) {
    249         mem = SVP_ATTRS_1m;
    250     }
    251 
    252     if (svp_ent != NULL) {
    253         *tpid_enb = soc_mem_field32_get(unit, mem, svp_ent, TPID_ENABLEf);
    254     } else {
    255         uint32 ent[SOC_MAX_MEM_FIELD_WORDS];
    256         BCM_IF_ERROR_RETURN(soc_mem_read(unit, mem, SOC_BLOCK_ANY, vp, ent));
    257         *tpid_enb = soc_mem_field32_get(unit, mem, ent, TPID_ENABLEf);
    258     }
    259     return BCM_E_NONE;
    260 }
    261 
    262 STATIC int
    263 _bcm_trident_niv_tpid_enb_set(int unit, uint32 *svp_ent, int vp, int tpid_enb)
    264 {
    265     soc_mem_t mem = SOURCE_VPm;
    266 
    267     if (soc_mem_field_valid(unit, SVP_ATTRS_1m, TPID_ENABLEf)) {
    268         mem = SVP_ATTRS_1m;
    269     }
    270 
    271     if (svp_ent != NULL) {
    272         soc_mem_field32_set(unit, mem, svp_ent, TPID_ENABLEf, tpid_enb);
    273     } else {
    274         BCM_IF_ERROR_RETURN(soc_mem_field32_modify(unit, mem, vp, TPID_ENABLEf,
    275                                                    tpid_enb));
    276     }
    277     return BCM_E_NONE;
    278 }
    279 
    280 
    281 #ifdef BCM_WARM_BOOT_SUPPORT
    282 
    283 #define BCM_WB_VERSION_1_0     SOC_SCACHE_VERSION(1,0)
    284 #define BCM_WB_VERSION_1_1     SOC_SCACHE_VERSION(1,1)
    285 #define BCM_WB_VERSION_1_2     SOC_SCACHE_VERSION(1,2)
    286 #define BCM_WB_VERSION_1_3     SOC_SCACHE_VERSION(1,3)
    287 #define BCM_WB_DEFAULT_VERSION BCM_WB_VERSION_1_3
    288 
    289 /* 
    290  * Function:
    291  *      _bcm_trident_niv_egress_hash_recover
    292  * Purpose:
    293  *      Recover the vp based hash table according to hardware information.
    294  * Parameters:
    295  *      unit - (IN) SOC unit Number
    296  *      vp   - (IN) Virtual port number. 
    297  *      node - (IN) niv egress hardware information.
    298  * Returns:
    299  *      BCM_E_XXX
    300  */
    301 STATIC int
    302 _bcm_trident_niv_egress_hash_recover(
    303     int unit, int vp, _bcm_trident_niv_egress_t *node)
    304 {
    305     int              bkt_idx, alloc_size;
    306     uint16           hash_val;
    307     bcm_niv_egress_t niv_egress;
    308     _bcm_trident_niv_egress_t *temp_ptr = NULL;
    309 
    310     bcm_niv_egress_t_init(&niv_egress);
    311     niv_egress.flags                = node->flags;
    312     niv_egress.port                 = node->port;
    313     niv_egress.intf                 = node->intf;
    314     niv_egress.service_tpid         = node->service_tpid;
    315     niv_egress.service_vlan         = node->service_vlan;
    316     niv_egress.service_pri          = node->service_pri;
    317     niv_egress.service_cfi          = node->service_cfi;
    318     niv_egress.service_qos_map_id   = node->service_qos_map_id;
    319     niv_egress.virtual_interface_id = node->virtual_interface_id;
    320     BCM_IF_ERROR_RETURN(
    321         _bcm_trident_niv_egress_hash_calc(unit, (void *)&niv_egress,
    322                                           &hash_val));
    323     bkt_idx  = hash_val % TD_NIV_PORT_HASH_BKT_SIZE;
    324     if ((NIV_PORT_INFO(unit, vp)->egress_list == NULL)) {
    325         alloc_size = sizeof(_bcm_trident_niv_egress_t) *
    326                      TD_NIV_PORT_HASH_BKT_SIZE;
    327         temp_ptr = sal_alloc(alloc_size, "NIV egress object");
    328         if (NULL == temp_ptr) {
    329             return BCM_E_MEMORY;
    330         }
    331         sal_memset(temp_ptr, 0, alloc_size);
    332         NIV_PORT_INFO(unit, vp)->egress_list = temp_ptr;
    333     }
    334     node->next = NIV_PORT_HASH_BKT(unit, vp, bkt_idx)->next;
    335     NIV_PORT_HASH_BKT(unit, vp, bkt_idx)->next = node;
    336 
    337     return BCM_E_NONE;
    338 }
    339 
    340 /*
    341  * Function:
    342  *      bcm_trident_niv_required_scache_size_get
    343  * Purpose:
    344  *      Get required NIV module scache size for Level 2 Warm Boot
    345  * Parameters:
    346  *      unit - StrataSwitch unit number.
    347  *      size - (OUT) Required scache size.
    348  * Returns:
    349  *      BCM_E_XXX
    350  */
    351 int
    352 bcm_trident_niv_required_scache_size_get(int unit, uint32 *size)
    353 {
    354     int num_vp;
    355     int num_nh;
    356     int num_ports;
    357 
    358     *size = 0;
    359 
    360     /* Add size required to store the bitmap of NIV VPs that
    361      * were created without match criteria.
    362      */
    363     num_vp = soc_mem_index_count(unit, SOURCE_VPm);
    364     *size += SHR_BITALLOCSIZE(num_vp);
    365 
    366     /* Add size required to store the bitmap of next hops that
    367      * are associated with NIV egress objects.
    368      */
    369     num_nh = soc_mem_index_count(unit, EGR_L3_NEXT_HOPm);
    370     *size += SHR_BITALLOCSIZE(num_nh);
    371 
    372     /* Add size required to store an array of physical port bitmaps.
    373      * The size of the array equals to the number of next hops.
    374      * A next hop entry may be shared by multiple NIV egress objects that
    375      * have identical attributes except for the physical port. Hence,
    376      * the physical port of each NIV egress object cannot be recovered
    377      * from hardware and needs to be stored in the next hop's physical
    378      * port bitmap.
    379      */
    380     num_ports = soc_mem_field_length(unit, L3_IPMCm, L3_BITMAPf);
    381     *size += (SHR_BITALLOCSIZE(num_ports) * num_nh);
    382 
    383     /* Add size required to store match_vlan. There can be at most
    384      * one match_vlan per NIV virtual port.
    385      */
    386     *size += (sizeof(bcm_vlan_t) * num_vp);
    387 
    388     /*
    389      * Add size required to store the bitmap of NIV VPs
    390      * which are added with BCM_NIV_PORT_MATCH_DO_NOT_ADD.
    391      */
    392     *size += SHR_BITALLOCSIZE(num_vp);
    393 
    394     /* Add size required to store the bitmap of next hops which
    395      * are associated with BCM_NIV_EGRESS_MULTICAST.
    396      */
    397     *size += SHR_BITALLOCSIZE(num_nh);
    398 
    399     return BCM_E_NONE;
    400 }
    401 
    402 /*
    403  * Function:
    404  *      bcm_trident_niv_sync
    405  * Purpose:
    406  *      Record persistent info into the scache.
    407  * Parameters:
    408  *      unit - StrataSwitch unit #
    409  *      scache_ptr - (IN/OUT) Scache pointer
    410  * Returns:
    411  *      BCM_E_xxx
    412  */
    413 int 
    414 bcm_trident_niv_sync(
    415     int unit, 
    416     uint8 **scache_ptr)
    417 {
    418     int rv = BCM_E_NONE;
    419     int num_vp, num_nh, num_ports;
    420     SHR_BITDCL *match_none_vp_bitmap = NULL;
    421     SHR_BITDCL *match_do_not_add_vp_bitmap = NULL;
    422     SHR_BITDCL *nh_bitmap = NULL;
    423     SHR_BITDCL *mc_nh_bitmap = NULL;
    424     SHR_BITDCL **pbmp_ptr_array = NULL;
    425     bcm_vlan_t *match_vlan_array = NULL;
    426     int i;
    427     _bcm_trident_niv_egress_t *curr_ptr;
    428     int nh_index;
    429     bcm_module_t mod_out;
    430     bcm_port_t port_out;
    431     bcm_trunk_t tgid_out;
    432     int id_out;
    433     bcm_port_t local_member_array[SOC_MAX_NUM_PORTS];
    434     int local_member_count;
    435     int mod_local;
    436     int bkt_idx, bkt_size;
    437     int vp_mc = 0;
    438 #if defined(BCM_SABER2_SUPPORT)
    439     uint32 source_vp_sb2_5626x = 0xFED5ABC7;
    440 #endif /* BCM_SABER2_SUPPORT */
    441 
    442     num_vp = soc_mem_index_count(unit, SOURCE_VPm);
    443     num_nh = soc_mem_index_count(unit, EGR_L3_NEXT_HOPm);
    444     num_ports = soc_mem_field_length(unit, L3_IPMCm, L3_BITMAPf);
    445 
    446     /* Allocate a bitmap of NIV VPs that were created without match criteria */
    447     match_none_vp_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_vp),
    448             "Bitmap of NIV VPs without match criteria");
    449     if (NULL == match_none_vp_bitmap) {
    450         rv = BCM_E_MEMORY;
    451         goto cleanup;
    452     }
    453     sal_memset(match_none_vp_bitmap, 0, SHR_BITALLOCSIZE(num_vp));
    454 
    455     /* Allocate a bitmap of next hops associated with NIV egress objects */
    456     nh_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_nh), "Bitmap of NHs");
    457     if (NULL == nh_bitmap) {
    458         rv = BCM_E_MEMORY;
    459         goto cleanup;
    460     }
    461     sal_memset(nh_bitmap, 0, SHR_BITALLOCSIZE(num_nh));
    462 
    463     /* Allocate an array of pointers to port bitmaps */
    464     pbmp_ptr_array = sal_alloc(sizeof(SHR_BITDCL *) * num_nh,
    465             "Array of pointers to pbmp");
    466     if (NULL == pbmp_ptr_array) {
    467         rv = BCM_E_MEMORY;
    468         goto cleanup;
    469     }
    470     sal_memset(pbmp_ptr_array, 0, sizeof(SHR_BITDCL *) * num_nh);
    471 
    472     /* Allocate an array of match_vlan */
    473     match_vlan_array = sal_alloc(sizeof(bcm_vlan_t) * num_vp,
    474             "Array of match_vlan");
    475     if (NULL == match_vlan_array) {
    476         rv = BCM_E_MEMORY;
    477         goto cleanup;
    478     }
    479     sal_memset(match_vlan_array, 0, sizeof(bcm_vlan_t) * num_vp);
    480 
    481     /*
    482      * Allocate a bitmap of NIV VPs which are added
    483      * with BCM_NIV_PORT_MATCH_DO_NOT_ADD.
    484      */
    485     match_do_not_add_vp_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_vp),
    486             "Bitmap of NIV VPs");
    487     if (NULL == match_do_not_add_vp_bitmap) {
    488         rv = BCM_E_MEMORY;
    489         goto cleanup;
    490     }
    491     sal_memset(match_do_not_add_vp_bitmap, 0, SHR_BITALLOCSIZE(num_vp));
    492 
    493     /* Allocate a bitmap of next hops associated with multicast NIV egress objects */
    494     mc_nh_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_nh), "Bitmap of multicast NHs");
    495     if (NULL == mc_nh_bitmap) {
    496         rv = BCM_E_MEMORY;
    497         goto cleanup;
    498     }
    499     sal_memset(mc_nh_bitmap, 0, SHR_BITALLOCSIZE(num_nh));
    500 
    501     /* Traverse NIV VPs */
    502     for (i = 0; i < num_vp; i++) {
    503         if (NIV_PORT_INFO(unit, i)->flags & BCM_NIV_PORT_MATCH_NONE) {
    504             SHR_BITSET(match_none_vp_bitmap, i);
    505             /* Traverse this NIV VP's list of NIV egress objects */
    506             vp_mc = 0;
    507             if (NIV_PORT_MC_NH_INFO(unit, i) != NULL) {
    508                 /* The shared vp associates with mulicast egress objects. */
    509                 if (NIV_PORT_INFO(unit, i)->egress_list == NULL) {
    510                     rv = BCM_E_INTERNAL;
    511                     goto cleanup;
    512                 }
    513                 vp_mc = 1;
    514             }
    515             bkt_size = vp_mc ? TD_NIV_PORT_HASH_BKT_SIZE : 1;
    516             for (bkt_idx = 0; bkt_idx < bkt_size; bkt_idx++) {
    517                 if (vp_mc) {
    518                     curr_ptr = NIV_PORT_HASH_BKT(unit, i, bkt_idx)->next;
    519                 } else {
    520                     curr_ptr = NIV_PORT_INFO(unit, i)->egress_list;
    521                 }
    522 
    523                 while (NULL != curr_ptr) {
    524                     if (curr_ptr->match_vlan) {
    525                         /* Match_vlan can be nonzero only for unicast NIV egress
    526                          * objects, and there can be at most one unicast NIV
    527                          * egress object in the NIV port's egress_list. These
    528                          * constraints are enforced by bcm_trident_niv_egress_add.
    529                          */
    530                         match_vlan_array[i] = curr_ptr->match_vlan;
    531                     }
    532 
    533                     nh_index = curr_ptr->next_hop_index;
    534                     SHR_BITSET(nh_bitmap, nh_index);
    535 
    536                     if (curr_ptr->flags & BCM_NIV_EGRESS_MULTICAST) {
    537                         SHR_BITSET(mc_nh_bitmap, nh_index);
    538                     }
    539 
    540                     /* If not already done, allocate a port bitmap for this
    541                      * next hop index.
    542                      */
    543                     if (NULL == pbmp_ptr_array[nh_index]) {
    544                         pbmp_ptr_array[nh_index] =
    545                             sal_alloc(SHR_BITALLOCSIZE(num_ports), "NH pbmp");
    546                         sal_memset(pbmp_ptr_array[nh_index], 0,
    547                                 SHR_BITALLOCSIZE(num_ports));
    548                     }
    549 
    550                     /* Set the bit in the port bitmap corresponding to the
    551                      * physical port this NIV egress object resides on.
    552                      */
    553                     rv = _bcm_esw_gport_resolve(unit, curr_ptr->port,
    554                                 &mod_out, &port_out, &tgid_out, &id_out);
    555                     if (BCM_FAILURE(rv)) {
    556                         goto cleanup;
    557                     }
    558                     if (BCM_TRUNK_INVALID != tgid_out) {
    559                         rv = _bcm_esw_trunk_local_members_get(unit,
    560                                     tgid_out, SOC_MAX_NUM_PORTS, local_member_array,
    561                                     &local_member_count);
    562                         if (BCM_FAILURE(rv)) {
    563                             goto cleanup;
    564                         }
    565                         /* Only one member needs to be added for warm boot recovery
    566                          * of the trunk group ID.
    567                          */
    568                         if (local_member_count > 0) {
    569                             SHR_BITSET(pbmp_ptr_array[nh_index], local_member_array[0]);
    570                         }
    571                     } else {
    572                         rv = _bcm_esw_modid_is_local(unit, mod_out, &mod_local);
    573                         if (BCM_FAILURE(rv)) {
    574                             goto cleanup;
    575                         }
    576                         if (mod_local) {
    577                             SHR_BITSET(pbmp_ptr_array[nh_index], port_out);
    578                         } else {
    579                             rv = BCM_E_INTERNAL;
    580                             goto cleanup;
    581                         }
    582                     }
    583 
    584                     /* Advance to next egress object */
    585                     curr_ptr = curr_ptr->next;
    586                 }
    587             }
    588         } else { /* BCM_NIV_PORT_MATCH_NONE is not set */
    589             if (NIV_PORT_INFO(unit, i)->match_vlan) {
    590                 match_vlan_array[i] = NIV_PORT_INFO(unit, i)->match_vlan;
    591             }
    592         }
    593         if (NIV_PORT_INFO(unit, i)->flags & BCM_NIV_PORT_MATCH_DO_NOT_ADD) {
    594             SHR_BITSET(match_do_not_add_vp_bitmap, i);
    595         }
    596     }
    597 
    598     /* Maximum virtual port supported on saber2 5626x devices are 4K
    599      * This fix is related to scaling down of vpn from 8K to 4K
    600      */
    601 #if defined(BCM_SABER2_SUPPORT)
    602     if (soc_sb2_5626x_devtype(unit)) {
    603         sal_memcpy(*scache_ptr, &source_vp_sb2_5626x, sizeof(source_vp_sb2_5626x));
    604         *scache_ptr += sizeof(source_vp_sb2_5626x);
    605     }
    606 #endif /* BCM_SABER2_SUPPORT */
    607 
    608     /* Store in scache the bitmap of NIV VPs that were created without
    609      * match criteria.
    610      */
    611     sal_memcpy(*scache_ptr, match_none_vp_bitmap, SHR_BITALLOCSIZE(num_vp));
    612     *scache_ptr += SHR_BITALLOCSIZE(num_vp);
    613 
    614     /* Store in scache the bitmap of next hops associated with
    615      * NIV egress objects.
    616      */
    617     sal_memcpy(*scache_ptr, nh_bitmap, SHR_BITALLOCSIZE(num_nh));
    618     *scache_ptr += SHR_BITALLOCSIZE(num_nh);
    619 
    620     /* Store in scache the physical port bitmap of the next hops 
    621      * associated with NIV egress objects.
    622      */
    623     for (i = 0; i < num_nh; i++) {
    624         if (SHR_BITGET(nh_bitmap, i)) {
    625             sal_memcpy(*scache_ptr, pbmp_ptr_array[i],
    626                     SHR_BITALLOCSIZE(num_ports));
    627             *scache_ptr += SHR_BITALLOCSIZE(num_ports);
    628         }
    629     }
    630 
    631     /* Store in scache the array of match_vlan */
    632     sal_memcpy(*scache_ptr, match_vlan_array, sizeof(bcm_vlan_t) * num_vp);
    633     *scache_ptr += (sizeof(bcm_vlan_t) * num_vp);
    634 
    635 
    636     /*
    637      * Store in scache the bitmap of NIV VPs which are added
    638      * with BCM_NIV_PORT_MATCH_DO_NOT_ADD.
    639      */
    640     sal_memcpy(*scache_ptr, match_do_not_add_vp_bitmap,
    641                SHR_BITALLOCSIZE(num_vp));
    642     *scache_ptr += SHR_BITALLOCSIZE(num_vp);
    643 
    644     /*
    645      * Store in scache the bitmap of next hops which are associated
    646      * with BCM_NIV_EGRESS_MULTICAST.
    647      */
    648     sal_memcpy(*scache_ptr, mc_nh_bitmap, SHR_BITALLOCSIZE(num_nh));
    649     *scache_ptr += SHR_BITALLOCSIZE(num_nh);
    650 
    651 cleanup:
    652     if (NULL != match_none_vp_bitmap) {
    653         sal_free(match_none_vp_bitmap);
    654     }
    655     if (NULL != nh_bitmap) {
    656         sal_free(nh_bitmap);
    657     }
    658     if (NULL != pbmp_ptr_array) {
    659         for (i = 0; i < num_nh; i++) {
    660             if (NULL != pbmp_ptr_array[i]) {
    661                 /* pbmp_ptr_array[i] is not null when nh_bitmap[bit i] is set */
    662                 sal_free(pbmp_ptr_array[i]);
    663             }
    664         }
    665         sal_free(pbmp_ptr_array);
    666     }
    667     if (NULL != match_vlan_array) {
    668         sal_free(match_vlan_array);
    669     }
    670     if (NULL != match_do_not_add_vp_bitmap) {
    671         sal_free(match_do_not_add_vp_bitmap);
    672     }
    673     if (NULL != mc_nh_bitmap) {
    674         sal_free(mc_nh_bitmap);
    675     }
    676 
    677     return rv;
    678 }
    679 
    680 /*
    681  * Function:
    682  *      _bcm_trident_niv_sd_tag_recover
    683  * Purpose:
    684  *      Recover SD-tag fields from a egress next hop entry.
    685  * Parameters:
    686  *      unit - Device Number
    687  *      egr_nh - Egress next hop entry
    688  *      sd_tag - (OUT) SD-tag fields
    689  * Returns:
    690  *      BCM_E_XXX
    691  */
    692 STATIC int 
    693 _bcm_trident_niv_sd_tag_recover(int unit, egr_l3_next_hop_entry_t *egr_nh,
    694         _bcm_trident_niv_sd_tag_t *sd_tag)
    695 {
    696     int sd_tag_action_if_not_present;
    697     int sd_tag_add;
    698     int sd_tag_action_if_present;
    699     int sd_tag_replace_vlan;
    700     int sd_tag_replace_pri;
    701     int sd_tag_replace_tpid;
    702     int sd_tag_delete;
    703     int tpid_index;
    704     int pri_select;
    705     int mapping_ptr;
    706     int qos_map_type;
    707 
    708     sal_memset(sd_tag, 0, sizeof(_bcm_trident_niv_sd_tag_t));
    709 
    710     /* GET SD-tag action if packet doesn't have a SD-tag */
    711     sd_tag_action_if_not_present = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
    712             egr_nh, SD_TAG__SD_TAG_ACTION_IF_NOT_PRESENTf);
    713     if (1 == sd_tag_action_if_not_present) {
    714         sd_tag_add = TRUE;
    715     } else {
    716         sd_tag_add = FALSE;
    717     }
    718 
    719     /* GET SD-tag action if packet already has a SD-tag */
    720     sd_tag_action_if_present = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
    721             egr_nh, SD_TAG__SD_TAG_ACTION_IF_PRESENTf);
    722     sd_tag_replace_vlan = FALSE;
    723     sd_tag_replace_pri = FALSE;
    724     sd_tag_replace_tpid = FALSE;
    725     sd_tag_delete = FALSE;
    726     switch (sd_tag_action_if_present) {
    727         case 1: /* REPLACE_VID_TPID */
    728             sd_tag_replace_vlan = TRUE;
    729             sd_tag_replace_tpid = TRUE;
    730             break;
    731         case 2: /* REPLACE_VID_ONLY */
    732             sd_tag_replace_vlan = TRUE;
    733             break;
    734         case 3: /* DELETE SD-TAG */
    735             sd_tag_delete = TRUE;
    736             break;
    737         case 4: /* REPLACE_VID_PRI_TPID */
    738             sd_tag_replace_vlan = TRUE;
    739             sd_tag_replace_pri = TRUE;
    740             sd_tag_replace_tpid = TRUE;
    741             break;
    742         case 5: /* REPLACE_VID_PRI_ONLY */
    743             sd_tag_replace_vlan = TRUE;
    744             sd_tag_replace_pri = TRUE;
    745             break;
    746         case 6: /* REPLACE_PRI_ONLY */
    747             sd_tag_replace_pri = TRUE;
    748             break;
    749         case 7: /* REPLACE_TPID_ONLY */
    750             sd_tag_replace_tpid = TRUE;
    751             break;
    752         default:
    753             break;
    754     }
    755 
    756     /* Recover BCM_NIV_EGRESS_SERVICE_xxx flags */
    757     if (sd_tag_add) {
    758         sd_tag->flags |= BCM_NIV_EGRESS_SERVICE_VLAN_ADD;
    759     }
    760     if (sd_tag_delete) {
    761         sd_tag->flags |= BCM_NIV_EGRESS_SERVICE_VLAN_DELETE;
    762     }
    763     if (sd_tag_replace_vlan) {
    764         sd_tag->flags |= BCM_NIV_EGRESS_SERVICE_VLAN_REPLACE;
    765     }
    766     if (sd_tag_replace_pri) {
    767         sd_tag->flags |= BCM_NIV_EGRESS_SERVICE_PRI_REPLACE;
    768     }
    769     if (sd_tag_replace_tpid) {
    770         sd_tag->flags |= BCM_NIV_EGRESS_SERVICE_TPID_REPLACE;
    771     }
    772 
    773     /* Recover SD-tag TPID */
    774     if (sd_tag_add || sd_tag_replace_tpid) {
    775         tpid_index = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
    776                 egr_nh, SD_TAG__SD_TAG_TPID_INDEXf);
    777         BCM_IF_ERROR_RETURN(_bcm_fb2_outer_tpid_tab_ref_count_add(unit,
    778                     tpid_index, 1));
    779         BCM_IF_ERROR_RETURN(_bcm_fb2_outer_tpid_entry_get(unit,
    780                     &sd_tag->service_tpid, tpid_index));
    781     }
    782 
    783     /* Recover SD-tag VLAN ID */
    784     if (sd_tag_add || sd_tag_replace_vlan) {
    785         sd_tag->service_vlan = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
    786                 egr_nh, SD_TAG__SD_TAG_VIDf);
    787     }
    788 
    789     /* Recover SD-tag Priority, CFI, and Qos Map ID */
    790     pri_select = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
    791             egr_nh, SD_TAG__SD_TAG_DOT1P_PRI_SELECTf);
    792     if (pri_select) {
    793         mapping_ptr = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
    794                 egr_nh, SD_TAG__SD_TAG_DOT1P_MAPPING_PTRf);
    795         qos_map_type = 2; /* _BCM_QOS_MAP_TYPE_EGR_MPLS_MAPS */
    796         BCM_IF_ERROR_RETURN(_bcm_tr2_qos_idx2id(unit, mapping_ptr,
    797                     qos_map_type, &sd_tag->service_qos_map_id));
    798     } else {
    799         sd_tag->service_pri = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
    800                 egr_nh, SD_TAG__NEW_PRIf);
    801         sd_tag->service_cfi = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
    802                 egr_nh, SD_TAG__NEW_CFIf);
    803     }
    804 
    805     return BCM_E_NONE;
    806 }
    807 
    808 /*
    809  * Function:
    810  *      bcm_trident_niv_reinit
    811  * Purpose:
    812  *      Warm boot recovery for the NIV software module
    813  * Parameters:
    814  *      unit - Device Number
    815  *      defaul_ver - Warm boot default version
    816  * Returns:
    817  *      BCM_E_XXX
    818  */
    819 int 
    820 bcm_trident_niv_reinit(int unit)
    821 {
    822     int rv = BCM_E_NONE;
    823     int num_vp, num_nh, num_ports;
    824     SHR_BITDCL *match_none_vp_bitmap = NULL;
    825     SHR_BITDCL *match_do_not_add_vp_bitmap = NULL;
    826     SHR_BITDCL *niv_vp_bitmap = NULL;
    827     SHR_BITDCL *nh_bitmap = NULL;
    828     SHR_BITDCL *mc_nh_bitmap = NULL;
    829     SHR_BITDCL **pbmp_ptr_array = NULL;
    830     bcm_vlan_t *match_vlan_array = NULL;
    831     soc_scache_handle_t scache_handle;
    832     uint8 *scache_ptr;
    833     uint16 recovered_ver;
    834     int stable_size;
    835     uint32 additional_scache_size = 0;
    836     uint8 *ing_nh_buf = NULL;
    837     ing_l3_next_hop_entry_t *ing_nh_entry;
    838     uint8 *egr_nh_buf = NULL;
    839     egr_l3_next_hop_entry_t *egr_nh_entry;
    840     int i, index_min, index_max;
    841     uint32 entry_type = 0, vp = 0, trunk_bit;
    842     uint32 vif = 0, p_bit = 0,l_bit = 0;
    843     _bcm_trident_niv_sd_tag_t niv_sd_tag;
    844     bcm_trunk_t tgid;
    845     bcm_module_t modid, mod_out;
    846     bcm_port_t port_num, port_out;
    847     int num_valid_ports;
    848     int j;
    849     _bcm_trident_niv_egress_t *curr_ptr = NULL;
    850     bcm_gport_t gport;
    851     uint8 *svp_buf = NULL;
    852     int tpid_enable;
    853     int  vp_mc, mc_flags;
    854     bcm_pbmp_t pbmp;
    855     _bcm_vp_info_t vp_info;
    856     int        old_num_vp = 0;
    857 #if defined(BCM_SABER2_SUPPORT)
    858     uint32     source_vp_sb2_5626x = 0;
    859 #endif /* BCM_SABER2_SUPPORT */
    860 
    861     _bcm_vp_info_init(&vp_info);
    862     vp_info.vp_type = _bcmVpTypeNiv;
    863 
    864     num_vp = soc_mem_index_count(unit, SOURCE_VPm);
    865     num_nh = soc_mem_index_count(unit, EGR_L3_NEXT_HOPm);
    866     num_ports = soc_mem_field_length(unit, L3_IPMCm, L3_BITMAPf);
    867 
    868     /* Allocate a bitmap of NIV VPs that were created without match criteria */
    869     match_none_vp_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_vp),
    870             "Bitmap of NIV VPs without match criteria");
    871     if (NULL == match_none_vp_bitmap) {
    872         rv = BCM_E_MEMORY;
    873         goto cleanup;
    874     }
    875     sal_memset(match_none_vp_bitmap, 0, SHR_BITALLOCSIZE(num_vp));
    876 
    877     /* Allocate a bitmap of NIV VPs */
    878     niv_vp_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_vp), "Bitmap of NIV VPs");
    879     if (NULL == niv_vp_bitmap) {
    880         rv = BCM_E_MEMORY;
    881         goto cleanup;
    882     }
    883     sal_memset(niv_vp_bitmap, 0, SHR_BITALLOCSIZE(num_vp));
    884 
    885     /* Allocate a bitmap of next hops associated with NIV egress objects */
    886     nh_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_nh), "Bitmap of NHs");
    887     if (NULL == nh_bitmap) {
    888         rv = BCM_E_MEMORY;
    889         goto cleanup;
    890     }
    891     sal_memset(nh_bitmap, 0, SHR_BITALLOCSIZE(num_nh));
    892 
    893     /* Allocate an array of pointers to port bitmaps */
    894     pbmp_ptr_array = sal_alloc(sizeof(SHR_BITDCL *) * num_nh,
    895             "Array of pointers to pbmp");
    896     if (NULL == pbmp_ptr_array) {
    897         rv = BCM_E_MEMORY;
    898         goto cleanup;
    899     }
    900     sal_memset(pbmp_ptr_array, 0, sizeof(SHR_BITDCL *) * num_nh);
    901 
    902     /* Allocate an array of match_vlan */
    903     match_vlan_array = sal_alloc(sizeof(bcm_vlan_t) * num_vp,
    904             "Array of match_vlan");
    905     if (NULL == match_vlan_array) {
    906         rv = BCM_E_MEMORY;
    907         goto cleanup;
    908     }
    909     sal_memset(match_vlan_array, 0, sizeof(bcm_vlan_t) * num_vp);
    910 
    911     /*
    912      * Allocate a bitmap of NIV VPs which are added
    913      * with BCM_NIV_PORT_MATCH_DO_NOT_ADD.
    914      */
    915     match_do_not_add_vp_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_vp),
    916             "Bitmap of NIV VPs");
    917     if (NULL == match_do_not_add_vp_bitmap) {
    918         rv = BCM_E_MEMORY;
    919         goto cleanup;
    920     }
    921     sal_memset(match_do_not_add_vp_bitmap, 0, SHR_BITALLOCSIZE(num_vp));
    922 
    923     /* Allocate a bitmap of next hops associated with multicast NIV egress objects */
    924     mc_nh_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_nh), "Bitmap of multicast NHs");
    925     if (NULL == mc_nh_bitmap) {
    926         rv = BCM_E_MEMORY;
    927         goto cleanup;
    928     }
    929     sal_memset(mc_nh_bitmap, 0, SHR_BITALLOCSIZE(num_nh));
    930 
    931     rv = soc_stable_size_get(unit, &stable_size);
    932     if (SOC_FAILURE(rv)) {
    933         goto cleanup;
    934     }
    935 
    936     /* Read scache */
    937     SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_NIV, 0);
    938     rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE,
    939             0, &scache_ptr, BCM_WB_DEFAULT_VERSION, &recovered_ver);
    940 
    941     if (BCM_E_NOT_FOUND == rv) {
    942 
    943         if ((stable_size == 0) || SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) {
    944             rv = BCM_E_NONE;
    945         } else {
    946             /* Get scache size required for default version */
    947             rv = bcm_trident_niv_required_scache_size_get(unit,
    948                      &additional_scache_size);
    949             if (BCM_FAILURE(rv)) {
    950                 goto cleanup;
    951             }
    952     
    953             /* Upgrading from SDK release that does not have warmboot state */
    954             rv = _bcm_esw_scache_ptr_get(unit, scache_handle, TRUE,
    955                     additional_scache_size, &scache_ptr,
    956                     BCM_WB_DEFAULT_VERSION, NULL);
    957             if (BCM_FAILURE(rv)) {
    958                 goto cleanup;
    959             }
    960         }
    961 
    962     } else if (BCM_FAILURE(rv)) {
    963         goto cleanup;
    964     } else {
    965         /* Maximum virtual port supported on saber2 5626x devices are 4K
    966          * This fix is related to scaling down of vpn from 8K to 4K
    967          */
    968 #if defined(BCM_SABER2_SUPPORT)
    969         if (soc_sb2_5626x_devtype(unit)) {
    970             sal_memcpy(&source_vp_sb2_5626x, scache_ptr,
    971                     sizeof(source_vp_sb2_5626x));
    972             if (source_vp_sb2_5626x == 0xFED5ABC7) {
    973                 scache_ptr += sizeof(source_vp_sb2_5626x);
    974             } else {
    975                 old_num_vp = 1;
    976             }
    977         }
    978 #endif /* BCM_SABER2_SUPPORT */
    979         /* Recover the bitmap of NIV VPs that were created without
    980          * match criteria.
    981          */
    982         sal_memcpy(match_none_vp_bitmap, scache_ptr, SHR_BITALLOCSIZE(num_vp));
    983         if (old_num_vp) {
    984             scache_ptr += SHR_BITALLOCSIZE(num_vp * 2);
    985         } else {
    986             scache_ptr += SHR_BITALLOCSIZE(num_vp);
    987         }
    988 
    989         /* Recover the bitmap of next hops associated with
    990          * NIV egress objects.
    991          */
    992         sal_memcpy(nh_bitmap, scache_ptr, SHR_BITALLOCSIZE(num_nh));
    993         scache_ptr += SHR_BITALLOCSIZE(num_nh);
    994 
    995        /* Recover the physical port bitmap of the next hops associated
    996         * with NIV egress objects.
    997         */
    998         for (i = 0; i < num_nh; i++) {
    999             if (SHR_BITGET(nh_bitmap, i)) {
   1000                 pbmp_ptr_array[i] = sal_alloc(SHR_BITALLOCSIZE(num_ports),
   1001                         "NH pbmp");
   1002                 sal_memcpy(pbmp_ptr_array[i], scache_ptr,
   1003                         SHR_BITALLOCSIZE(num_ports));
   1004                 scache_ptr += SHR_BITALLOCSIZE(num_ports);
   1005             }
   1006         }
   1007         
   1008         /* Recover the array of match_vlan */
   1009         if (recovered_ver >= BCM_WB_VERSION_1_1) {
   1010             sal_memcpy(match_vlan_array, scache_ptr, sizeof(bcm_vlan_t) * num_vp);
   1011             if (old_num_vp) {
   1012                 scache_ptr += (sizeof(bcm_vlan_t) * num_vp * 2);
   1013             } else {
   1014                 scache_ptr += (sizeof(bcm_vlan_t) * num_vp);
   1015             }
   1016         } else {
   1017             if (old_num_vp) {
   1018                 additional_scache_size += (sizeof(bcm_vlan_t) * num_vp * 2);
   1019             } else {
   1020                 additional_scache_size += (sizeof(bcm_vlan_t) * num_vp);
   1021             }
   1022         }
   1023 
   1024         /*
   1025          * Recover the bitmap of NIV VPs which are added
   1026          * with BCM_NIV_PORT_MATCH_DO_NOT_ADD.
   1027          */
   1028         if (recovered_ver >= BCM_WB_VERSION_1_2) {
   1029             sal_memcpy(match_do_not_add_vp_bitmap, 
   1030                        scache_ptr, SHR_BITALLOCSIZE(num_vp));
   1031             if (old_num_vp) {
   1032                 scache_ptr += SHR_BITALLOCSIZE(num_vp * 2);
   1033             } else {
   1034                 scache_ptr += SHR_BITALLOCSIZE(num_vp);
   1035             }
   1036         } else {
   1037             if (old_num_vp) {
   1038                 additional_scache_size += SHR_BITALLOCSIZE(num_vp * 2);
   1039             } else {
   1040                 additional_scache_size += SHR_BITALLOCSIZE(num_vp);
   1041             }
   1042         }
   1043 
   1044       /* Recover the bitmap of next hops associated with
   1045        * multicast NIV egress objects.
   1046        */
   1047        if (recovered_ver >= BCM_WB_VERSION_1_3) {
   1048             sal_memcpy(mc_nh_bitmap, scache_ptr, SHR_BITALLOCSIZE(num_nh));
   1049             scache_ptr += SHR_BITALLOCSIZE(num_nh);
   1050         } else {
   1051             additional_scache_size += SHR_BITALLOCSIZE(num_nh);
   1052         }
   1053 
   1054         if (additional_scache_size > 0) {
   1055             rv = soc_scache_realloc(unit, scache_handle,additional_scache_size);
   1056             if(BCM_FAILURE(rv)) {
   1057                goto cleanup;
   1058             }
   1059         }
   1060     }
   1061 
   1062     /*
   1063      * Recover the BCM_NIV_PORT_MATCH_NONE from match_none_vp_bitmap,
   1064      * and recover the BCM_NIV_PORT_MATCH_DO_NOT_ADD from
   1065      * match_do_not_add_vp_bitmap
   1066      */
   1067     for (i = 0; i < num_vp; i++) {
   1068         if (SHR_BITGET(match_none_vp_bitmap, i)) {
   1069             NIV_PORT_INFO(unit, i)->flags |= BCM_NIV_PORT_MATCH_NONE;
   1070         }
   1071         if (SHR_BITGET(match_do_not_add_vp_bitmap, i)) {
   1072             NIV_PORT_INFO(unit, i)->flags |= BCM_NIV_PORT_MATCH_DO_NOT_ADD;
   1073         }
   1074     }
   1075 
   1076     /* Copy match_none_vp_bitmap to niv_vp_bitmap */
   1077     sal_memcpy(niv_vp_bitmap, match_none_vp_bitmap, SHR_BITALLOCSIZE(num_vp));
   1078 
   1079     /* Recover NIV ports and NIV egress objects from next hop tables */
   1080 
   1081     ing_nh_buf = soc_cm_salloc(unit,
   1082             SOC_MEM_TABLE_BYTES(unit, ING_L3_NEXT_HOPm),
   1083             "Ing Next Hop buffer");
   1084     if (NULL == ing_nh_buf) {
   1085         rv = BCM_E_MEMORY;
   1086         goto cleanup;
   1087     }
   1088     index_min = soc_mem_index_min(unit, ING_L3_NEXT_HOPm);
   1089     index_max = soc_mem_index_max(unit, ING_L3_NEXT_HOPm);
   1090     rv = soc_mem_read_range(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   1091             index_min, index_max, ing_nh_buf);
   1092     if (SOC_FAILURE(rv)) {
   1093         goto cleanup;
   1094     }
   1095     egr_nh_buf = soc_cm_salloc(unit,
   1096             SOC_MEM_TABLE_BYTES(unit, EGR_L3_NEXT_HOPm),
   1097             "Egr Next Hop buffer");
   1098     if (NULL == egr_nh_buf) {
   1099         rv = BCM_E_MEMORY;
   1100         goto cleanup;
   1101     }
   1102     index_min = soc_mem_index_min(unit, EGR_L3_NEXT_HOPm);
   1103     index_max = soc_mem_index_max(unit, EGR_L3_NEXT_HOPm);
   1104     rv = soc_mem_read_range(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   1105             index_min, index_max, egr_nh_buf);
   1106     if (SOC_FAILURE(rv)) {
   1107         goto cleanup;
   1108     }
   1109 
   1110     for (i = index_min; i <= index_max; i++) {
   1111         egr_nh_entry = soc_mem_table_idx_to_pointer
   1112             (unit, EGR_L3_NEXT_HOPm, egr_l3_next_hop_entry_t *, 
   1113              egr_nh_buf, i);
   1114 
   1115         /* Check entry type */
   1116         entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1117                         _NIV_ENTRY_TYPEf(unit, EGR_L3_NEXT_HOPm));
   1118         if ((entry_type != 2) && (entry_type != 7)) {
   1119             /* Not NIV virtual port entry type */
   1120             continue;
   1121         }
   1122 
   1123         if (entry_type == 7) {
   1124             if (!soc_feature(unit, soc_feature_virtual_port_routing)) {
   1125                 continue;
   1126             }
   1127         }
   1128 
   1129         /* Check that VN-tag action is ADD */
   1130         if (entry_type == 2) {            
   1131             if (VNTAG_ADD != soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1132                         SD_TAG__VNTAG_ACTIONSf)) {
   1133                 continue;
   1134             }
   1135         } else if (entry_type == 7) {
   1136             if (VNTAG_ADD != soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1137                         L3MC__VNTAG_ACTIONSf)) {
   1138                 continue;
   1139             }
   1140         }
   1141         
   1142         if (entry_type == 2) {            
   1143             /* Recover VP */
   1144             vp = soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1145                     SD_TAG__DVPf);
   1146         } else if (entry_type == 7) {
   1147             /* L3MC*/ 
   1148             vp = soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1149                     L3MC__DVPf);
   1150         }
   1151         
   1152         if ((stable_size == 0) || SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) {
   1153             rv = _bcm_vp_used_set(unit, vp, vp_info);
   1154             if (BCM_FAILURE(rv)) {
   1155                 goto cleanup;
   1156             }
   1157         } else {
   1158             if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   1159                 /* VP bitmap is recovered by virtual_init */
   1160                 continue;
   1161             }
   1162         }
   1163 
   1164         /* Add VP to NIV VP bitmap */
   1165         SHR_BITSET(niv_vp_bitmap, vp);
   1166 
   1167         /* Read virtual interface ID, multicast flag, and SD-tag or L3mc*/
   1168         if (entry_type == 2) {
   1169             vif = soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1170                     SD_TAG__VNTAG_DST_VIFf);
   1171             p_bit = soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1172                     SD_TAG__VNTAG_Pf); 
   1173             rv = _bcm_trident_niv_sd_tag_recover(unit, egr_nh_entry, &niv_sd_tag);
   1174             if (BCM_FAILURE(rv)) {
   1175                 goto cleanup;
   1176             }            
   1177         } else if (entry_type == 7) {
   1178             /* L3MC*/
   1179             vif = soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1180                     L3MC__VNTAG_DST_VIFf);
   1181             p_bit = soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1182                     L3MC__VNTAG_Pf);
   1183             l_bit = soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1184                     L3MC__VNTAG_FORCE_Lf); 
   1185         }
   1186 
   1187         if (!(NIV_PORT_INFO(unit, vp)->flags & BCM_NIV_PORT_MATCH_NONE)) {
   1188 
   1189             if (entry_type == 2) {
   1190                 /* Recover multicast flag */
   1191                 if (p_bit) {
   1192                     NIV_PORT_INFO(unit, vp)->flags |= BCM_NIV_PORT_MULTICAST;
   1193                 }
   1194 
   1195                 /* Recover physical trunk or port from ingress next hop table */
   1196                 ing_nh_entry = soc_mem_table_idx_to_pointer
   1197                     (unit, ING_L3_NEXT_HOPm, ing_l3_next_hop_entry_t *, 
   1198                      ing_nh_buf, i);
   1199                 if (soc_feature(unit, soc_feature_generic_dest)) {
   1200                     uint32 dt, dv;
   1201                     dv = soc_mem_field32_dest_get(unit, ING_L3_NEXT_HOPm,
   1202                             ing_nh_entry, DESTINATIONf, &dt);
   1203                     if (dt == SOC_MEM_FIF_DEST_LAG) {
   1204                         /* Trunk group */
   1205                         tgid = dv & SOC_MEM_FIF_DGPP_TGID_MASK;
   1206                         BCM_GPORT_TRUNK_SET(NIV_PORT_INFO(unit, vp)->port, tgid);
   1207                     } else {
   1208                         port_num = dv & SOC_MEM_FIF_DGPP_PORT_MASK;
   1209                         modid = (dv & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >>
   1210                                  SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS;
   1211                         rv = _bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
   1212                                 modid, port_num, &mod_out, &port_out);
   1213                         if (BCM_FAILURE(rv)) {
   1214                             goto cleanup;
   1215                         }
   1216                         BCM_GPORT_MODPORT_SET(NIV_PORT_INFO(unit, vp)->port,
   1217                                               mod_out, port_out);
   1218                     }
   1219                 } else {
   1220                     trunk_bit = soc_ING_L3_NEXT_HOPm_field32_get(unit,
   1221                                     ing_nh_entry, Tf);
   1222                     if (trunk_bit) {
   1223                         tgid = soc_ING_L3_NEXT_HOPm_field32_get(unit,
   1224                                     ing_nh_entry, TGIDf);
   1225                         BCM_GPORT_TRUNK_SET(NIV_PORT_INFO(unit, vp)->port, tgid);
   1226                     } else {
   1227                         modid = soc_ING_L3_NEXT_HOPm_field32_get(unit,
   1228                                     ing_nh_entry, MODULE_IDf);
   1229                         port_num = soc_ING_L3_NEXT_HOPm_field32_get(unit,
   1230                                     ing_nh_entry, PORT_NUMf);
   1231                         rv = _bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
   1232                                 modid, port_num, &mod_out, &port_out);
   1233                         if (BCM_FAILURE(rv)) {
   1234                             goto cleanup;
   1235                         }
   1236                         BCM_GPORT_MODPORT_SET(NIV_PORT_INFO(unit, vp)->port,
   1237                                               mod_out, port_out);
   1238                     }
   1239                 }
   1240 
   1241                 /* Recover virtual interface ID */
   1242                 NIV_PORT_INFO(unit, vp)->virtual_interface_id = vif;
   1243 
   1244                 /* The match_vlan can be recovered from either match_vlan_array
   1245                  * or EGR_L3_NEXT_HOP.SD_TAG_VID field. The latter approach
   1246                  * is taken since older SDKs stored match_vlan in EGR_L3_NEXT_HOP
   1247                  * entry, not in scache.
   1248                  */
   1249                 NIV_PORT_INFO(unit, vp)->match_vlan =
   1250                     soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1251                             SD_TAG__SD_TAG_VIDf);
   1252 
   1253                 if (stable_size == 0) {
   1254                     /* In the Port module, a port's VP count is not recovered in 
   1255                      * level 1 Warm Boot.
   1256                      */
   1257                     rv = _bcm_trident_niv_port_cnt_update(unit,
   1258                             NIV_PORT_INFO(unit, vp)->port, vp, TRUE, TRUE);
   1259                     if (BCM_FAILURE(rv)) {
   1260                         goto cleanup;
   1261                     }
   1262                 }
   1263             }
   1264         } else { /* The NIV port was created without match criteria */
   1265             vp_mc = 0;
   1266             BCM_PBMP_CLEAR(pbmp);
   1267             if (entry_type == 2) {
   1268                 num_valid_ports = 0;
   1269                 for (j = 0; j < num_ports; j++) {
   1270                     if ((pbmp_ptr_array[i] != NULL) ?
   1271                         (SHR_BITGET(pbmp_ptr_array[i], j)) : 0) {
   1272                         /* Insert a new NIV egress object into VP's egress list */
   1273                         curr_ptr = sal_alloc(sizeof(_bcm_trident_niv_egress_t),
   1274                                 "NIV egress object");
   1275                         if (NULL == curr_ptr) {
   1276                             rv = BCM_E_MEMORY;
   1277                             goto cleanup;
   1278                         }
   1279                         sal_memset(curr_ptr, 0, sizeof(_bcm_trident_niv_egress_t));
   1280 
   1281                         if (p_bit) {
   1282                             curr_ptr->flags |= BCM_NIV_EGRESS_MULTICAST;
   1283                         } else if (SHR_BITGET(mc_nh_bitmap, i)) {
   1284                             curr_ptr->flags |= BCM_NIV_EGRESS_MULTICAST;
   1285                             /*
   1286                              * The P-bit could have been cleared when egress objects
   1287                              * are added with BCM_NIV_EGRESS_P_BIT_CLEAR flag.
   1288                              */
   1289                             curr_ptr->flags |= BCM_NIV_EGRESS_P_BIT_CLEAR;
   1290                         }
   1291 
   1292                         rv = bcm_esw_port_gport_get(unit, j, &gport);
   1293                         if (BCM_FAILURE(rv)) {
   1294                             sal_free(curr_ptr);
   1295                             goto cleanup;
   1296                         }
   1297                         rv = bcm_esw_trunk_find(unit, BCM_MODID_INVALID, gport, &tgid);
   1298                         if (BCM_SUCCESS(rv)) {
   1299                             BCM_GPORT_TRUNK_SET(curr_ptr->port, tgid);
   1300                         } else if (rv == BCM_E_NOT_FOUND) {
   1301                             rv = BCM_E_NONE;
   1302                             curr_ptr->port = gport;
   1303                         } else {
   1304                             sal_free(curr_ptr);
   1305                             goto cleanup;
   1306                         }
   1307                         curr_ptr->virtual_interface_id = vif;
   1308                         if (recovered_ver >= BCM_WB_VERSION_1_1) {
   1309                             curr_ptr->match_vlan = match_vlan_array[vp];
   1310                         } else {
   1311                             curr_ptr->match_vlan =
   1312                                 soc_EGR_L3_NEXT_HOPm_field32_get(unit,
   1313                                     egr_nh_entry, SD_TAG__SD_TAG_VIDf);
   1314                         }                        
   1315                         curr_ptr->flags |= niv_sd_tag.flags;
   1316                         curr_ptr->service_tpid = niv_sd_tag.service_tpid;
   1317                         curr_ptr->service_vlan = niv_sd_tag.service_vlan;
   1318                         curr_ptr->service_pri = niv_sd_tag.service_pri;
   1319                         curr_ptr->service_cfi = niv_sd_tag.service_cfi;
   1320                         curr_ptr->service_qos_map_id = niv_sd_tag.service_qos_map_id;
   1321                         curr_ptr->next_hop_index = i;
   1322                         curr_ptr->next = NIV_PORT_INFO(unit, vp)->egress_list;
   1323                         if (curr_ptr->flags & BCM_NIV_EGRESS_MULTICAST) {
   1324                             vp_mc = 1;
   1325                             rv = _bcm_trident_niv_egress_hash_recover(
   1326                                      unit, vp, curr_ptr);
   1327                             if (BCM_FAILURE(rv)) {
   1328                                 sal_free(curr_ptr);
   1329                                 goto cleanup;
   1330                             }
   1331                             BCM_PBMP_PORT_ADD(pbmp, j);
   1332                         } else {
   1333                             NIV_PORT_INFO(unit, vp)->egress_list = curr_ptr;
   1334                         }
   1335 
   1336                         /* Increment the number of ports in port bitmap */
   1337                         num_valid_ports++;
   1338                     }
   1339                 }
   1340 
   1341                 /* During warm boot, L3 module had already incremented reference
   1342                  * count for non-null next hop entries. Hence, the next hop's
   1343                  * reference count should be incremented further by num_valid_ports
   1344                  * minus one.
   1345                  */
   1346                 for (j = 0; j < num_valid_ports - 1; j++) {
   1347                     _bcm_xgs3_nh_ref_cnt_incr(unit, i);
   1348                 }
   1349             } else if (entry_type == 7) {
   1350                 num_valid_ports = 0;
   1351                 vp_mc = 1;
   1352                 for (j = 0; j < num_ports; j++) {
   1353                     if ((pbmp_ptr_array[i] != NULL) ?
   1354                         (!SHR_BITGET(pbmp_ptr_array[i], j)) : 1) {
   1355                         continue;                            
   1356                     }
   1357                     /* Insert a new NIV egress object into VP's egress list */
   1358                     curr_ptr = sal_alloc(sizeof(_bcm_trident_niv_egress_t),
   1359                             "NIV egress object");
   1360                     if (NULL == curr_ptr) {
   1361                         rv = BCM_E_MEMORY;
   1362                         goto cleanup;
   1363                     }
   1364                     sal_memset(curr_ptr, 0, sizeof(_bcm_trident_niv_egress_t));
   1365 
   1366                     if (p_bit) {
   1367                         curr_ptr->flags |= BCM_NIV_EGRESS_MULTICAST;
   1368                     } else if (SHR_BITGET(mc_nh_bitmap, i)) {
   1369                         curr_ptr->flags |= BCM_NIV_EGRESS_MULTICAST;
   1370                         /*
   1371                          * The P-bit could have been cleared when egress objects
   1372                          * are added with BCM_NIV_EGRESS_P_BIT_CLEAR flag.
   1373                          */
   1374                         curr_ptr->flags |= BCM_NIV_EGRESS_P_BIT_CLEAR;
   1375                     }
   1376 
   1377                     if (l_bit) {
   1378                         curr_ptr->flags |= BCM_NIV_VNTAG_L_BIT_FORCE_1;
   1379                     }
   1380                     /*entry_type == 7, L3MC */
   1381                     curr_ptr->flags |= BCM_NIV_EGRESS_L3;
   1382 
   1383                     rv = bcm_esw_port_gport_get(unit, j, &gport);
   1384                     if (BCM_FAILURE(rv)) {
   1385                         sal_free(curr_ptr);
   1386                         goto cleanup;
   1387                     }
   1388                     rv = bcm_esw_trunk_find(unit, BCM_MODID_INVALID, gport, &tgid);
   1389                     if (BCM_SUCCESS(rv)) {
   1390                         BCM_GPORT_TRUNK_SET(curr_ptr->port, tgid);
   1391                     } else if (rv == BCM_E_NOT_FOUND) {
   1392                         rv = BCM_E_NONE;
   1393                         curr_ptr->port = gport;
   1394                     } else {
   1395                         sal_free(curr_ptr);
   1396                         goto cleanup;
   1397                     }
   1398                     curr_ptr->virtual_interface_id = vif;
   1399                     curr_ptr->next_hop_index = i;
   1400                     curr_ptr->intf = soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1401                         L3MC__INTF_NUMf);
   1402                     
   1403                     mc_flags = 0;
   1404                     if(soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1405                         L3MC__L2_MC_DA_DISABLEf)) {
   1406                         mc_flags |= BCM_L3_MULTICAST_L2_DEST_PRESERVE; 
   1407                     }                            
   1408                     if(soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1409                         L3MC__L2_MC_SA_DISABLEf)) {
   1410                         mc_flags |= BCM_L3_MULTICAST_L2_SRC_PRESERVE; 
   1411                     }                            
   1412                     if(soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1413                         L3MC__L2_MC_VLAN_DISABLEf)) {
   1414                         mc_flags |= BCM_L3_MULTICAST_L2_VLAN_PRESERVE; 
   1415                     }                            
   1416                     if(soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1417                         L3MC__L3_MC_TTL_DISABLEf)) {
   1418                         mc_flags |= BCM_L3_MULTICAST_TTL_PRESERVE; 
   1419                     }                            
   1420                     if(soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1421                         L3MC__L3_MC_DA_DISABLEf)) {
   1422                         mc_flags |= BCM_L3_MULTICAST_DEST_PRESERVE; 
   1423                     }                            
   1424                     if(soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1425                         L3MC__L3_MC_SA_DISABLEf)) {
   1426                         mc_flags |= BCM_L3_MULTICAST_SRC_PRESERVE; 
   1427                     }                            
   1428                     if(soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1429                         L3MC__L3_MC_VLAN_DISABLEf)) {
   1430                         mc_flags |= BCM_L3_MULTICAST_VLAN_PRESERVE; 
   1431                     }                            
   1432                     if(soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1433                         L3MC__L3_DROPf)) {
   1434                         mc_flags |= BCM_L3_MULTICAST_L3_DROP; 
   1435                     }                            
   1436                     if(soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry,
   1437                         L3MC__L2_DROPf)) {
   1438                         mc_flags |= BCM_L3_MULTICAST_L2_DROP; 
   1439                     }
   1440                     curr_ptr->multicast_flags |= mc_flags;
   1441                     rv = _bcm_trident_niv_egress_hash_recover(
   1442                              unit, vp, curr_ptr);
   1443                     if (BCM_FAILURE(rv)) {
   1444                         sal_free(curr_ptr);
   1445                         goto cleanup;
   1446                     }      
   1447                     /* Increment the number of ports in port bitmap */
   1448                     num_valid_ports++;
   1449                     BCM_PBMP_PORT_ADD(pbmp, j);
   1450                 }
   1451             
   1452                 /* During warm boot, L3 module had already incremented reference
   1453                  * count for non-null next hop entries. Hence, the next hop's
   1454                  * reference count should be incremented further by num_valid_ports
   1455                  * minus one.
   1456                  */
   1457                 for (j = 0; j < num_valid_ports - 1; j++) {
   1458                     _bcm_xgs3_nh_ref_cnt_incr(unit, i);
   1459                 }
   1460             }   
   1461 
   1462             if (vp_mc) {
   1463                 rv = _bcm_trident_niv_egress_pbmp_add(unit, vp, pbmp);
   1464                 if (BCM_FAILURE(rv)) {
   1465                     sal_free(curr_ptr);
   1466                     goto cleanup;
   1467                 }
   1468             }
   1469         }
   1470     }
   1471 
   1472 
   1473     /* Recover SD-tag TPID reference count from SOURCE_VP table */
   1474     if (entry_type == 2) {
   1475         soc_mem_t svpm = SOURCE_VPm;
   1476         void *svp_entry;
   1477         if (soc_mem_is_valid(unit, SVP_ATTRS_1m)) {
   1478             svpm = SVP_ATTRS_1m;
   1479         }
   1480         svp_buf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, svpm),
   1481                 "SOURCE_VP buffer");
   1482         if (NULL == svp_buf) {
   1483             rv = BCM_E_MEMORY;
   1484             goto cleanup;
   1485         }
   1486         index_min = soc_mem_index_min(unit, svpm);
   1487         index_max = soc_mem_index_max(unit, svpm);
   1488         rv = soc_mem_read_range(unit, svpm, MEM_BLOCK_ANY,
   1489                 index_min, index_max, svp_buf);
   1490         if (SOC_FAILURE(rv)) {
   1491             goto cleanup;
   1492         }
   1493         for (i = index_min; i <= index_max; i++) {
   1494             if (svpm == SOURCE_VPm) {
   1495                 svp_entry = soc_mem_table_idx_to_pointer
   1496                     (unit, svpm, source_vp_entry_t *, svp_buf, i);
   1497             } else {
   1498                 svp_entry = soc_mem_table_idx_to_pointer
   1499                     (unit, svpm, svp_attrs_1_entry_t *, svp_buf, i);
   1500             }
   1501             (void) _bcm_trident_niv_tpid_enb_get(unit, svp_entry, i,
   1502                                                  &tpid_enable);
   1503             if (tpid_enable) {
   1504                 for (j = 0; j < soc_mem_field_length(unit, svpm, TPID_ENABLEf);
   1505                         j++) {
   1506                     if (tpid_enable & (1 << j)) {
   1507                         rv = _bcm_fb2_outer_tpid_tab_ref_count_add(unit, j, 1);
   1508                         if (SOC_FAILURE(rv)) {
   1509                             goto cleanup;
   1510                         }
   1511                     }
   1512                 }
   1513             }
   1514         }
   1515     }
   1516     
   1517 cleanup:
   1518     if (match_none_vp_bitmap) {
   1519         sal_free(match_none_vp_bitmap);
   1520     }
   1521     if (match_do_not_add_vp_bitmap) {
   1522         sal_free(match_do_not_add_vp_bitmap);
   1523     }
   1524     if (niv_vp_bitmap) {
   1525         sal_free(niv_vp_bitmap);
   1526     }
   1527     if (nh_bitmap) {
   1528         sal_free(nh_bitmap);
   1529     }
   1530     if (mc_nh_bitmap) {
   1531         sal_free(mc_nh_bitmap);
   1532     }
   1533     if (pbmp_ptr_array) {
   1534         for (i = 0; i < num_nh; i++) {
   1535             if (pbmp_ptr_array[i]) {
   1536                 sal_free(pbmp_ptr_array[i]);
   1537             }
   1538         }
   1539         sal_free(pbmp_ptr_array);
   1540     }
   1541     if (match_vlan_array) {
   1542         sal_free(match_vlan_array);
   1543     }
   1544     if (ing_nh_buf) {
   1545         soc_cm_sfree(unit, ing_nh_buf);
   1546     }
   1547     if (egr_nh_buf) {
   1548         soc_cm_sfree(unit, egr_nh_buf);
   1549     }
   1550     if (svp_buf) {
   1551         soc_cm_sfree(unit, svp_buf);
   1552     }
   1553 
   1554     return rv;
   1555 }
   1556 
   1557 #endif /* BCM_WARM_BOOT_SUPPORT */
   1558 
   1559 /*
   1560  * Function:
   1561  *      _bcm_trident_niv_free_resources
   1562  * Purpose:
   1563  *      Free all allocated tables and memory
   1564  * Parameters:
   1565  *      unit - SOC unit number
   1566  * Returns:
   1567  *      Nothing
   1568  */
   1569 STATIC void
   1570 _bcm_trident_niv_free_resources(int unit)
   1571 {
   1572     int i;
   1573     _bcm_trident_niv_egress_t *curr_ptr;
   1574     _bcm_trident_niv_egress_t *next_ptr;
   1575 
   1576     if (NIV_INFO(unit)->port_info) {
   1577         for (i = 0; i < soc_mem_index_count(unit, SOURCE_VPm); i++) {
   1578             curr_ptr = NIV_PORT_INFO(unit, i)->egress_list;
   1579             while (NULL != curr_ptr) {
   1580                 next_ptr = curr_ptr->next;
   1581                 sal_free(curr_ptr);
   1582                 curr_ptr = next_ptr;
   1583             }
   1584             NIV_PORT_INFO(unit, i)->egress_list = NULL;
   1585         }
   1586         sal_free(NIV_INFO(unit)->port_info);
   1587         NIV_INFO(unit)->port_info = NULL;
   1588     }
   1589 }
   1590 
   1591 /*
   1592  * Function:
   1593  *      bcm_trident_niv_init
   1594  * Purpose:
   1595  *      Initialize the NIV module.
   1596  * Parameters:
   1597  *      unit - SOC unit number.
   1598  * Returns:
   1599  *      BCM_E_XXX
   1600  */
   1601 int
   1602 bcm_trident_niv_init(int unit)
   1603 {
   1604     int num_vp;
   1605     int rv = BCM_E_NONE;
   1606 
   1607     sal_memset(NIV_INFO(unit), 0,
   1608             sizeof(_bcm_trident_niv_bookkeeping_t));
   1609 
   1610     num_vp = soc_mem_index_count(unit, SOURCE_VPm);
   1611     if (NULL == NIV_INFO(unit)->port_info) {
   1612         NIV_INFO(unit)->port_info =
   1613             sal_alloc(sizeof(_bcm_trident_niv_port_info_t) * num_vp, "niv_port_info");
   1614         if (NULL == NIV_INFO(unit)->port_info) {
   1615             _bcm_trident_niv_free_resources(unit);
   1616             return BCM_E_MEMORY;
   1617         }
   1618     }
   1619     sal_memset(NIV_INFO(unit)->port_info, 0,
   1620             sizeof(_bcm_trident_niv_port_info_t) * num_vp);
   1621 
   1622     /* When creating a NIV virtual port without any match criteria,
   1623      * the ING_DVP_TABLE.NEXT_HOP_INDEX is configured with an invalid
   1624      * next hop index, which is assigned to be the black hole next hop index.
   1625      */
   1626     NIV_INFO(unit)->invalid_next_hop_index = BCM_XGS3_L3_BLACK_HOLE_NH_IDX(unit);
   1627 
   1628 #ifdef BCM_TRIDENT3_SUPPORT
   1629     if (SOC_IS_TRIDENT3X(unit)) {
   1630         soc_td3_rx_etype_niv[unit] = 0;
   1631     }
   1632 #endif
   1633 
   1634     return rv;
   1635 }
   1636 
   1637 /*
   1638  * Function:
   1639  *      bcm_trident_niv_detach
   1640  * Purpose:
   1641  *      Detach the NIV module.
   1642  * Parameters:
   1643  *      unit - SOC unit number.
   1644  * Returns:
   1645  *      BCM_E_XXX
   1646  */
   1647 int
   1648 bcm_trident_niv_cleanup(int unit)
   1649 {
   1650     _bcm_trident_niv_free_resources(unit);
   1651 
   1652 #ifdef BCM_TRIDENT3_SUPPORT
   1653     if (SOC_IS_TRIDENT3X(unit)) {
   1654         soc_td3_rx_etype_niv[unit] = 0;
   1655     }
   1656 #endif
   1657 
   1658     return BCM_E_NONE;
   1659 }
   1660 
   1661 /*
   1662  * Function:
   1663  *      _bcm_trident_niv_nh_info_set
   1664  * Purpose:
   1665  *      Configure next hop tables.
   1666  * Parameters:
   1667  *      unit       - (IN) SOC unit number. 
   1668  *      nh_index   - (IN) Next hop index. 
   1669  *      multicast  - (IN) NIV multicast flag.
   1670  *      port       - (IN) Physical GPORT ID. 
   1671  *      virtual_interface_id - (IN) Virtual interface ID. 
   1672  *      match_vlan - (IN) Outer VLAN ID to match. 
   1673  *      sd_tag     - (IN) SD-tag attributes. 
   1674  *      vp         - (IN) Virtual port number. 
   1675  *      allow_loop   - (IN) NIV allow loop flag
   1676  * Returns:
   1677  *      BCM_X_XXX
   1678  */
   1679 STATIC int
   1680 _bcm_trident_niv_nh_info_set(int unit, int nh_index, int multicast,
   1681         bcm_gport_t port, uint16 vintf_id, bcm_vlan_t match_vlan,
   1682         _bcm_trident_niv_sd_tag_t *sd_tag, int vp, int allow_loop)
   1683 {
   1684     egr_l3_next_hop_entry_t egr_nh;
   1685     bcm_module_t mod_out;
   1686     bcm_port_t port_out;
   1687     bcm_trunk_t trunk_id;
   1688     int id;
   1689     int ing_nh_port;
   1690     int ing_nh_module;
   1691     int ing_nh_trunk;
   1692     ing_l3_next_hop_entry_t ing_nh;
   1693     initial_ing_l3_next_hop_entry_t initial_ing_nh;
   1694     int sd_tag_add = 0;
   1695     int sd_tag_delete = 0;
   1696     int sd_tag_replace_vlan = 0;
   1697     int sd_tag_replace_pri = 0;
   1698     int sd_tag_replace_tpid = 0;
   1699     int tpid_index;
   1700     int mapping_ptr;
   1701     soc_mem_t mem = EGR_L3_NEXT_HOPm;
   1702 
   1703     if ((nh_index > soc_mem_index_max(unit, mem)) ||
   1704         (nh_index < soc_mem_index_min(unit, mem))) {
   1705         return BCM_E_PARAM;
   1706     }
   1707 
   1708     /* Set up EGR_L3_NEXT_HOP entry */
   1709     sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t));
   1710     soc_mem_field32_set(unit, mem, &egr_nh,
   1711             _NIV_ENTRY_TYPEf(unit, mem), 2); /* SD-tag entry type */
   1712     soc_mem_field32_set(unit, mem, &egr_nh, SD_TAG__DVPf, vp);
   1713     /* PPD2 header */
   1714     soc_mem_field32_set(unit, mem, &egr_nh, SD_TAG__HG_HDR_SELf, 1);
   1715     soc_mem_field32_set(unit, mem, &egr_nh, SD_TAG__VNTAG_DST_VIFf, vintf_id);
   1716     soc_mem_field32_set(unit, mem, &egr_nh, SD_TAG__VNTAG_FORCE_Lf, allow_loop);
   1717     soc_mem_field32_set(unit, mem, &egr_nh, SD_TAG__VNTAG_Pf, multicast);
   1718     soc_mem_field32_set(unit, mem, &egr_nh, SD_TAG__VNTAG_ACTIONSf, 1);
   1719 
   1720     /* Set SD-tag related fields */
   1721     if (NULL != sd_tag) {
   1722         sd_tag_add = sd_tag->flags & BCM_NIV_EGRESS_SERVICE_VLAN_ADD;
   1723         sd_tag_delete = sd_tag->flags & BCM_NIV_EGRESS_SERVICE_VLAN_DELETE;
   1724         sd_tag_replace_vlan = sd_tag->flags & BCM_NIV_EGRESS_SERVICE_VLAN_REPLACE;
   1725         sd_tag_replace_pri = sd_tag->flags & BCM_NIV_EGRESS_SERVICE_PRI_REPLACE;
   1726         sd_tag_replace_tpid = sd_tag->flags & BCM_NIV_EGRESS_SERVICE_TPID_REPLACE;
   1727 
   1728         /* Set SD-tag action for packets without an SD-tag */
   1729         if (sd_tag_add) {
   1730             soc_mem_field32_set(unit, mem, &egr_nh,
   1731                     SD_TAG__SD_TAG_ACTION_IF_NOT_PRESENTf, 1);
   1732         }
   1733 
   1734         /* Set SD-tag action for packets with an SD-tag */
   1735         if (sd_tag_delete) {
   1736             if (sd_tag_replace_vlan || sd_tag_replace_pri || sd_tag_replace_tpid) {
   1737                 return BCM_E_PARAM;
   1738             }
   1739             soc_mem_field32_set(unit, mem, &egr_nh,
   1740                     SD_TAG__SD_TAG_ACTION_IF_PRESENTf, 3); /* DELETE SD-TAG */
   1741         } else {
   1742             if (!sd_tag_replace_vlan && !sd_tag_replace_pri && !sd_tag_replace_tpid) {
   1743                 soc_mem_field32_set(unit, mem, &egr_nh,
   1744                         SD_TAG__SD_TAG_ACTION_IF_PRESENTf, 0); /* NOOP */
   1745             } else if (sd_tag_replace_vlan && !sd_tag_replace_pri && sd_tag_replace_tpid) {
   1746                 soc_mem_field32_set(unit, mem, &egr_nh,
   1747                         SD_TAG__SD_TAG_ACTION_IF_PRESENTf, 1); /* REPLACE_VID_TPID */
   1748             } else if (sd_tag_replace_vlan && !sd_tag_replace_pri && !sd_tag_replace_tpid) {
   1749                 soc_mem_field32_set(unit, mem, &egr_nh,
   1750                         SD_TAG__SD_TAG_ACTION_IF_PRESENTf, 2); /* REPLACE_VID_ONLY */
   1751             } else if (sd_tag_replace_vlan && sd_tag_replace_pri && sd_tag_replace_tpid) {
   1752                 soc_mem_field32_set(unit, mem, &egr_nh,
   1753                         SD_TAG__SD_TAG_ACTION_IF_PRESENTf, 4); /* REPLACE_VID_PRI_TPID */
   1754             } else if (sd_tag_replace_vlan && sd_tag_replace_pri && !sd_tag_replace_tpid) {
   1755                 soc_mem_field32_set(unit, mem, &egr_nh,
   1756                         SD_TAG__SD_TAG_ACTION_IF_PRESENTf, 5); /* REPLACE_VID_PRI_ONLY */
   1757             } else if (!sd_tag_replace_vlan && sd_tag_replace_pri && !sd_tag_replace_tpid) {
   1758                 soc_mem_field32_set(unit, mem, &egr_nh,
   1759                         SD_TAG__SD_TAG_ACTION_IF_PRESENTf, 6); /* REPLACE_PRI_ONLY */
   1760             } else if (!sd_tag_replace_vlan && !sd_tag_replace_pri && sd_tag_replace_tpid) {
   1761                 if (SOC_IS_TRIDENT(unit)) {
   1762                     /* REPLACE_TPID_ONLY action is not available on Trident.
   1763                      * It's available on Triumph3 and Trident2.
   1764                      */
   1765                     return BCM_E_PARAM;
   1766                 }
   1767                 soc_mem_field32_set(unit, mem, &egr_nh,
   1768                         SD_TAG__SD_TAG_ACTION_IF_PRESENTf, 7); /* REPLACE_TPID_ONLY */
   1769             } else {
   1770                 return BCM_E_PARAM;
   1771             }
   1772         }
   1773 
   1774         /* Set SD-tag TPID */
   1775         if (sd_tag->service_tpid) {
   1776             if (sd_tag_add || sd_tag_replace_tpid) {
   1777                 BCM_IF_ERROR_RETURN(_bcm_fb2_outer_tpid_entry_add(unit,
   1778                             sd_tag->service_tpid, &tpid_index));
   1779                 soc_mem_field32_set(unit, mem, &egr_nh,
   1780                         SD_TAG__SD_TAG_TPID_INDEXf, tpid_index);
   1781             } else {
   1782                 return BCM_E_PARAM;
   1783             }
   1784         } else {
   1785             if (sd_tag_add || sd_tag_replace_tpid) {
   1786                 return BCM_E_PARAM;
   1787             }
   1788         }
   1789 
   1790         /* Set SD-tag VLAN ID */
   1791         if (sd_tag->service_vlan) {
   1792             if (sd_tag_add || sd_tag_replace_vlan) {
   1793                 soc_mem_field32_set(unit, mem, &egr_nh, SD_TAG__SD_TAG_VIDf,
   1794                                     sd_tag->service_vlan);
   1795             } else {
   1796                 return BCM_E_PARAM;
   1797             }
   1798         } else {
   1799             if (sd_tag_add || sd_tag_replace_vlan) {
   1800                 return BCM_E_PARAM;
   1801             }
   1802         }
   1803 
   1804         /* Set SD-tag Priority */
   1805         if (sd_tag->service_qos_map_id) {
   1806             if (sd_tag_add || sd_tag_replace_pri) {
   1807                 soc_mem_field32_set(unit, mem, &egr_nh,
   1808                         SD_TAG__SD_TAG_DOT1P_PRI_SELECTf, 1);
   1809                 BCM_IF_ERROR_RETURN(_bcm_tr2_qos_id2idx(unit,
   1810                             sd_tag->service_qos_map_id, &mapping_ptr));
   1811                 soc_mem_field32_set(unit, mem, &egr_nh,
   1812                         SD_TAG__SD_TAG_DOT1P_MAPPING_PTRf, mapping_ptr);
   1813             } else {
   1814                 return BCM_E_PARAM;
   1815             }
   1816         } else {
   1817             if (sd_tag_add || sd_tag_replace_pri) {
   1818                 soc_mem_field32_set(unit, mem, &egr_nh,
   1819                         SD_TAG__SD_TAG_DOT1P_PRI_SELECTf, 0);
   1820                 soc_mem_field32_set(unit, mem, &egr_nh,
   1821                         SD_TAG__NEW_PRIf, sd_tag->service_pri);
   1822                 soc_mem_field32_set(unit, mem, &egr_nh,
   1823                         SD_TAG__NEW_CFIf, sd_tag->service_cfi);
   1824             }
   1825         }
   1826     }
   1827 
   1828     /* Prior to the introduction of NIV SD-tag API enhancements,
   1829      * the match_vlan was stored in EGR_L3_NEXT_HOP.SD_TAG_VID field
   1830      * for warm boot recovery. With the NIV SD-tag API enhancements,
   1831      * the match_vlan is now stored in scache. But for warm boot
   1832      * downgrade, the match_vlan still needs to be stored in SD_TAG_VID field
   1833      * when there is no SD-tag action.
   1834      */ 
   1835     if (!sd_tag_add && !sd_tag_delete && !sd_tag_replace_vlan &&
   1836             !sd_tag_replace_pri && !sd_tag_replace_tpid) {
   1837         soc_mem_field32_set(unit, mem, &egr_nh, SD_TAG__SD_TAG_VIDf, match_vlan);
   1838     }
   1839 
   1840     /* Resolve gport */
   1841     BCM_IF_ERROR_RETURN(
   1842         _bcm_esw_gport_resolve(unit, port, &mod_out, &port_out,
   1843                                &trunk_id, &id));
   1844 
   1845 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   1846     if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm,
   1847                             SD_TAG__HG_MC_DST_PORT_NUMf)) {
   1848         if ((!BCM_GPORT_IS_TRUNK(port)) &&
   1849             (_bcm_xgs5_subport_coe_mod_port_local(unit, mod_out, port_out))) {
   1850             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   1851                                 SD_TAG__HG_MC_DST_PORT_NUMf, port_out);
   1852             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   1853                                 SD_TAG__HG_MC_DST_MODIDf, mod_out);
   1854         }
   1855     }
   1856 #endif /* BCM_TRIDENT2PLUS_SUPPORT */
   1857     /* Write EGR_L3_NEXT_HOP entry */
   1858     SOC_IF_ERROR_RETURN(
   1859         soc_mem_write(unit, mem, MEM_BLOCK_ALL, nh_index, &egr_nh));
   1860 
   1861     mem = ING_L3_NEXT_HOPm;
   1862     /* Resolve gport */
   1863     BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, port, &mod_out, 
   1864                 &port_out, &trunk_id, &id));
   1865     ing_nh_port = -1;
   1866     ing_nh_module = -1;
   1867     ing_nh_trunk = -1;
   1868     if (BCM_GPORT_IS_TRUNK(port)) {
   1869         ing_nh_module = -1;
   1870         ing_nh_port = -1;
   1871         ing_nh_trunk = trunk_id;
   1872     } else {
   1873         ing_nh_module = mod_out;
   1874         ing_nh_port = port_out;
   1875         ing_nh_trunk = -1;
   1876     }
   1877 
   1878     /* Write ING_L3_NEXT_HOP entry */
   1879     sal_memset(&ing_nh, 0, sizeof(ing_l3_next_hop_entry_t));
   1880     if (soc_feature(unit, soc_feature_generic_dest)) {
   1881         if (ing_nh_trunk == -1) {
   1882             soc_mem_field32_dest_set(unit, mem, &ing_nh,
   1883                 DESTINATIONf, SOC_MEM_FIF_DEST_DGPP,
   1884                 ing_nh_module << SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS | ing_nh_port);
   1885         } else {
   1886             soc_mem_field32_dest_set(unit, mem, &ing_nh,
   1887                 DESTINATIONf, SOC_MEM_FIF_DEST_LAG, ing_nh_trunk);
   1888         }
   1889     } else {
   1890         if (ing_nh_trunk == -1) {
   1891             soc_mem_field32_set(unit, mem, &ing_nh, PORT_NUMf, ing_nh_port);
   1892             soc_mem_field32_set(unit, mem, &ing_nh, MODULE_IDf, ing_nh_module);
   1893         } else {
   1894             soc_mem_field32_set(unit, mem, &ing_nh, Tf, 1);
   1895             soc_mem_field32_set(unit, mem, &ing_nh, TGIDf, ing_nh_trunk);
   1896         }
   1897     }
   1898     /* L2 DVP */
   1899     soc_mem_field32_set(unit, mem, &ing_nh, _NIV_ENTRY_TYPEf(unit, mem), 0x2);
   1900 
   1901 #ifdef BCM_TRIUMPH3_SUPPORT
   1902     if (soc_mem_field_valid(unit, mem, DVP_ATTRIBUTE_1_INDEXf)) {
   1903         uint32 mtu_profile_index;
   1904 
   1905         BCM_IF_ERROR_RETURN
   1906             (_bcm_tr3_mtu_profile_index_get(unit, 0x3fff, &mtu_profile_index));
   1907         soc_mem_field32_set(unit, mem, &ing_nh,
   1908                 DVP_ATTRIBUTE_1_INDEXf, mtu_profile_index);
   1909     } else
   1910 #endif /* BCM_TRIUMPH3_SUPPORT */
   1911     {
   1912     if (soc_mem_field_valid(unit, mem, MTU_SIZEf)) {
   1913             soc_mem_field32_set(unit, mem, &ing_nh,
   1914                 MTU_SIZEf, 0x3fff);    
   1915         }
   1916     }
   1917 
   1918     SOC_IF_ERROR_RETURN(
   1919         soc_mem_write(unit, mem, MEM_BLOCK_ALL, nh_index, &ing_nh));
   1920 
   1921     mem = INITIAL_ING_L3_NEXT_HOPm;
   1922     /* Write INITIAL_ING_L3_NEXT_HOP entry */
   1923     sal_memset(&initial_ing_nh, 0, sizeof(initial_ing_l3_next_hop_entry_t));
   1924     if (soc_feature(unit, soc_feature_generic_dest)) {
   1925         if (ing_nh_trunk == -1) {
   1926             soc_mem_field32_dest_set(unit, mem, &initial_ing_nh,
   1927                 DESTINATIONf, SOC_MEM_FIF_DEST_DGPP,
   1928                 ing_nh_module << SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS | ing_nh_port);
   1929         } else {
   1930             soc_mem_field32_dest_set(unit, mem, &initial_ing_nh,
   1931                 DESTINATIONf, SOC_MEM_FIF_DEST_LAG, ing_nh_trunk);
   1932         }
   1933     } else {
   1934         if (ing_nh_trunk == -1) {
   1935             soc_mem_field32_set(unit, mem,
   1936                     &initial_ing_nh, PORT_NUMf, ing_nh_port);
   1937             soc_mem_field32_set(unit, mem,
   1938                     &initial_ing_nh, MODULE_IDf, ing_nh_module);
   1939         } else {
   1940             soc_mem_field32_set(unit, mem, &initial_ing_nh, Tf, 1);
   1941             soc_mem_field32_set(unit, mem, &initial_ing_nh, TGIDf, ing_nh_trunk);
   1942         }
   1943     }
   1944     SOC_IF_ERROR_RETURN(
   1945         soc_mem_write(unit, mem, MEM_BLOCK_ALL, nh_index, &initial_ing_nh));
   1946 
   1947     return BCM_E_NONE;
   1948 }
   1949 
   1950 #ifdef BCM_TRIDENT2_SUPPORT
   1951 /*
   1952  * Function:
   1953  *      _bcm_trident_niv_l3mc_nh_info_set
   1954  * Purpose:
   1955  *      Configure next hop tables for L3MC.
   1956  * Parameters:
   1957  *      unit       - (IN) SOC unit number. 
   1958  *      nh_index   - (IN) Next hop index. 
   1959  *      multicast  - (IN) NIV multicast flag.
   1960  *      port       - (IN) Physical GPORT ID. 
   1961  *      virtual_interface_id - (IN) Virtual interface ID. 
   1962  *      match_vlan - (IN) Outer VLAN ID to match. 
   1963  *      sd_tag     - (IN) SD-tag attributes. 
   1964  *      vp         - (IN) Virtual port number. 
   1965  *      allow_loop   - (IN) NIV allow loop flag
   1966  * Returns:
   1967  *      BCM_X_XXX
   1968  */
   1969 STATIC int
   1970 _bcm_trident_niv_l3mc_nh_info_set(int unit, int nh_index, uint32 flags, 
   1971         uint32 multicast_flags, bcm_gport_t port, bcm_if_t intf, 
   1972         uint16 vintf_id, int vp, int allow_loop)
   1973 {
   1974     egr_l3_next_hop_entry_t egr_nh;
   1975     bcm_module_t mod_out;
   1976     bcm_port_t port_out;
   1977     bcm_trunk_t trunk_id;
   1978     int id;
   1979     int ing_nh_port;
   1980     int ing_nh_module;
   1981     int ing_nh_trunk;
   1982     ing_l3_next_hop_entry_t ing_nh;
   1983     initial_ing_l3_next_hop_entry_t initial_ing_nh;
   1984     int i;
   1985     int flag_set;
   1986     soc_mem_t mem = EGR_L3_NEXT_HOPm;
   1987     uint32 flag_array[] = {
   1988         BCM_L3_MULTICAST_L2_DEST_PRESERVE,
   1989         BCM_L3_MULTICAST_L2_SRC_PRESERVE,
   1990         BCM_L3_MULTICAST_L2_VLAN_PRESERVE,
   1991         BCM_L3_MULTICAST_TTL_PRESERVE,
   1992         BCM_L3_MULTICAST_DEST_PRESERVE,
   1993         BCM_L3_MULTICAST_SRC_PRESERVE,
   1994         BCM_L3_MULTICAST_VLAN_PRESERVE,
   1995         BCM_L3_MULTICAST_L3_DROP,
   1996         BCM_L3_MULTICAST_L2_DROP
   1997     };
   1998     soc_field_t field_array[] = {
   1999         L3MC__L2_MC_DA_DISABLEf,
   2000         L3MC__L2_MC_SA_DISABLEf,
   2001         L3MC__L2_MC_VLAN_DISABLEf,
   2002         L3MC__L3_MC_TTL_DISABLEf,
   2003         L3MC__L3_MC_DA_DISABLEf,
   2004         L3MC__L3_MC_SA_DISABLEf,
   2005         L3MC__L3_MC_VLAN_DISABLEf,
   2006         L3MC__L3_DROPf,
   2007         L3MC__L2_DROPf
   2008     };
   2009 
   2010     if ((nh_index > soc_mem_index_max(unit, mem)) ||
   2011         (nh_index < soc_mem_index_min(unit, mem))) {
   2012         return BCM_E_PARAM;
   2013     }
   2014 
   2015     sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t));
   2016 
   2017     /* L3MC view */
   2018     soc_mem_field32_set(unit, mem, &egr_nh, _NIV_ENTRY_TYPEf(unit, mem), 7);
   2019     soc_mem_field32_set(unit, mem, &egr_nh, L3MC__INTF_NUMf, intf);
   2020 
   2021     for (i = 0; i < COUNTOF(flag_array); i++) {
   2022         if (multicast_flags & flag_array[i]) {
   2023             flag_set = 1;
   2024         } else {
   2025             flag_set = 0;
   2026         }
   2027         if (soc_mem_field_valid(unit, mem, field_array[i])) {
   2028             soc_mem_field32_set(unit, mem, &egr_nh,
   2029                     field_array[i], flag_set);
   2030         } else {
   2031             if (flag_set) {
   2032                 return BCM_E_PARAM;
   2033             }
   2034         }
   2035     }
   2036     /* Set up EGR_L3_NEXT_HOP entry */
   2037     /*soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   2038             L3MC__L3MC_USE_CONFIGURED_MACf, 0);*/
   2039 
   2040 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   2041     if (soc_feature(unit, soc_feature_egr_l3_next_hop_next_ptr)) {
   2042         soc_mem_field32_set(unit, mem, &egr_nh, L3MC__NEXT_PTR_TYPEf, 1);
   2043     } else
   2044 #endif
   2045     {
   2046         soc_mem_field32_set(unit, mem, &egr_nh, L3MC__DVP_VALIDf, 1);
   2047     }
   2048     /* Add or replace VNTAG */
   2049     soc_mem_field32_set(unit, mem, &egr_nh, L3MC__VNTAG_ACTIONSf, 1);
   2050     soc_mem_field32_set(unit, mem, &egr_nh, L3MC__VNTAG_DST_VIFf, vintf_id);
   2051     soc_mem_field32_set(unit, mem, &egr_nh, L3MC__VNTAG_FORCE_Lf, allow_loop);
   2052     soc_mem_field32_set(unit, mem, &egr_nh, L3MC__VNTAG_Pf,
   2053                         (flags & BCM_NIV_EGRESS_P_BIT_CLEAR) ? 0 : 1);
   2054     /* PPD2 header */
   2055     soc_mem_field32_set(unit, mem, &egr_nh, L3MC__HG_HDR_SELf, 1);
   2056 
   2057     /* Indicate this egress object is on shared VP */
   2058     if (SOC_IS_TRIDENT3X(unit)) {
   2059         int fld_len = soc_mem_field_length(unit, mem, L3MC__RESERVED_1f);
   2060         soc_mem_field32_set(unit, mem, &egr_nh, L3MC__NEXT_PTRf, vp);
   2061         if (fld_len > 0) {
   2062             soc_mem_field32_set(unit, mem, &egr_nh,
   2063                                 L3MC__RESERVED_1f, 1 << (fld_len - 1));
   2064         }
   2065     } else {
   2066         soc_mem_field32_set(unit, mem, &egr_nh, L3MC__RSVD_DVPf, 1);
   2067         soc_mem_field32_set(unit, mem, &egr_nh, L3MC__DVPf, vp);
   2068     }
   2069 
   2070     /* Resolve gport */
   2071     BCM_IF_ERROR_RETURN(
   2072         _bcm_esw_gport_resolve(unit, port, &mod_out, &port_out,
   2073                                &trunk_id, &id));
   2074 
   2075 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   2076     if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm,
   2077                             L3MC__HG_MC_DST_PORT_NUMf)) {
   2078         if ((!BCM_GPORT_IS_TRUNK(port)) &&
   2079             (_bcm_xgs5_subport_coe_mod_port_local(unit, mod_out, port_out))) {
   2080             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   2081                                 L3MC__HG_MC_DST_PORT_NUMf, port_out);
   2082             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   2083                                 L3MC__HG_MC_DST_MODIDf, mod_out);
   2084         }
   2085     }
   2086 #endif /* BCM_TRIDENT2PLUS_SUPPORT */
   2087     /* Write EGR_L3_NEXT_HOP entry */
   2088     SOC_IF_ERROR_RETURN(soc_mem_write(unit, mem,
   2089                 MEM_BLOCK_ALL, nh_index, &egr_nh));
   2090 
   2091     mem = ING_L3_NEXT_HOPm;
   2092     /* Resolve gport */
   2093     BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, port, &mod_out, 
   2094                 &port_out, &trunk_id, &id));
   2095     ing_nh_port = -1;
   2096     ing_nh_module = -1;
   2097     ing_nh_trunk = -1;
   2098     if (BCM_GPORT_IS_TRUNK(port)) {
   2099         ing_nh_module = -1;
   2100         ing_nh_port = -1;
   2101         ing_nh_trunk = trunk_id;
   2102     } else {
   2103         ing_nh_module = mod_out;
   2104         ing_nh_port = port_out;
   2105         ing_nh_trunk = -1;
   2106     }
   2107 
   2108     /* Write ING_L3_NEXT_HOP entry. It is not necessary and to be removed */
   2109     sal_memset(&ing_nh, 0, sizeof(ing_l3_next_hop_entry_t));
   2110     if (soc_feature(unit, soc_feature_generic_dest)) {
   2111         if (ing_nh_trunk == -1) {
   2112             soc_mem_field32_dest_set(unit, mem, &ing_nh,
   2113                 DESTINATIONf, SOC_MEM_FIF_DEST_DGPP,
   2114                 ing_nh_module << SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS | ing_nh_port);
   2115         } else {
   2116             soc_mem_field32_dest_set(unit, mem, &ing_nh,
   2117                 DESTINATIONf, SOC_MEM_FIF_DEST_LAG, ing_nh_trunk);
   2118         }
   2119     } else {
   2120         if (ing_nh_trunk == -1) {
   2121             soc_mem_field32_set(unit, mem, &ing_nh, PORT_NUMf, ing_nh_port);
   2122             soc_mem_field32_set(unit, mem, &ing_nh, MODULE_IDf, ing_nh_module);
   2123         } else {
   2124             soc_mem_field32_set(unit, mem, &ing_nh, Tf, 1);
   2125             soc_mem_field32_set(unit, mem, &ing_nh, TGIDf, ing_nh_trunk);
   2126         }
   2127     }
   2128 
   2129     SOC_IF_ERROR_RETURN(
   2130         soc_mem_write(unit, mem, MEM_BLOCK_ALL, nh_index, &ing_nh));
   2131     
   2132     mem = INITIAL_ING_L3_NEXT_HOPm;
   2133     /* Write INITIAL_ING_L3_NEXT_HOP entry */
   2134     sal_memset(&initial_ing_nh, 0, sizeof(initial_ing_l3_next_hop_entry_t));
   2135     if (soc_feature(unit, soc_feature_generic_dest)) {
   2136         if (ing_nh_trunk == -1) {
   2137             soc_mem_field32_dest_set(unit, mem, &initial_ing_nh,
   2138                 DESTINATIONf, SOC_MEM_FIF_DEST_DGPP,
   2139                 ing_nh_module << SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS | ing_nh_port);
   2140         } else {
   2141             soc_mem_field32_dest_set(unit, mem, &initial_ing_nh,
   2142                 DESTINATIONf, SOC_MEM_FIF_DEST_LAG, ing_nh_trunk);
   2143         }
   2144     } else {
   2145         if (ing_nh_trunk == -1) {
   2146             soc_mem_field32_set(unit, mem,
   2147                     &initial_ing_nh, PORT_NUMf, ing_nh_port);
   2148             soc_mem_field32_set(unit, mem,
   2149                     &initial_ing_nh, MODULE_IDf, ing_nh_module);
   2150         } else {
   2151             soc_mem_field32_set(unit, mem, &initial_ing_nh, Tf, 1);
   2152             soc_mem_field32_set(unit, mem, &initial_ing_nh, TGIDf, ing_nh_trunk);
   2153         }
   2154     }
   2155     SOC_IF_ERROR_RETURN(
   2156         soc_mem_write(unit, mem, MEM_BLOCK_ALL, nh_index, &initial_ing_nh));
   2157 
   2158     return BCM_E_NONE;
   2159 }
   2160 #endif
   2161 
   2162 /*
   2163  * Function:
   2164  *      _bcm_trident_niv_nh_info_delete
   2165  * Purpose:
   2166  *      Decrement next hop's reference count. If count reaches zero, free the
   2167  *      next hop index and clear next hop table entries.
   2168  * Parameters:
   2169  *      unit     - (IN) SOC unit number. 
   2170  *      nh_index - (IN) Next hop index. 
   2171  * Returns:
   2172  *      BCM_X_XXX
   2173  */
   2174 STATIC int
   2175 _bcm_trident_niv_nh_info_delete(int unit, int nh_index)
   2176 {
   2177     egr_l3_next_hop_entry_t egr_nh;
   2178     int ref_count;
   2179     int sd_tag_action_if_not_present;
   2180     int sd_tag_action_if_present;
   2181     int sd_tag_add;
   2182     int sd_tag_replace_tpid;
   2183     int tpid_index;
   2184     uint32 entry_type = 0;
   2185     soc_field_t etfld;
   2186 
   2187     /* Read egress next hop entry before it's potentially deleted by
   2188      * bcm_xgs3_nh_del.
   2189      */
   2190     BCM_IF_ERROR_RETURN
   2191         (READ_EGR_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY, nh_index, &egr_nh));
   2192 
   2193     /* Decrement the next-hop's reference count. If count reaches zero,
   2194      * free the next hop index and clear ING_L3_NEXT_HOP,
   2195      * INITIAL_ING_L3_NEXT_HOP, and EGR_L3_NEXT_HOP entries.
   2196      */
   2197     BCM_IF_ERROR_RETURN(bcm_xgs3_nh_del(unit, 0, nh_index));
   2198 
   2199     /* Check next hop's reference count. If the count is zero,
   2200      * the egress next hop entry was cleared by bcm_xgs3_nh_del.
   2201      * In this case, the EGR_L3_NEXT_HOP.SD_TAG_TPID_INDEX's
   2202      * reference count needs to be decremented.
   2203      */
   2204     BCM_IF_ERROR_RETURN(bcm_xgs3_nh_ref_count_get(unit, nh_index, &ref_count));
   2205     /* Check entry type */
   2206     etfld = SOC_IS_TRIDENT3X(unit) ? DATA_TYPEf : ENTRY_TYPEf;
   2207     entry_type = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, etfld);
   2208     if (ref_count == 0 && entry_type == 2) {
   2209         sd_tag_action_if_not_present = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
   2210                 &egr_nh, SD_TAG__SD_TAG_ACTION_IF_NOT_PRESENTf);
   2211         if (1 == sd_tag_action_if_not_present) {
   2212             sd_tag_add = TRUE;
   2213         } else {
   2214             sd_tag_add = FALSE;
   2215         }
   2216 
   2217         sd_tag_action_if_present = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
   2218                 &egr_nh, SD_TAG__SD_TAG_ACTION_IF_PRESENTf);
   2219         if ((1 == sd_tag_action_if_present) ||
   2220                 (4 == sd_tag_action_if_present) ||
   2221                 (7 == sd_tag_action_if_present)) {
   2222             sd_tag_replace_tpid = TRUE;
   2223         } else {
   2224             sd_tag_replace_tpid = FALSE;
   2225         }
   2226 
   2227         if (sd_tag_add || sd_tag_replace_tpid) {
   2228             tpid_index = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm,
   2229                     &egr_nh, SD_TAG__SD_TAG_TPID_INDEXf);
   2230             BCM_IF_ERROR_RETURN
   2231                 (_bcm_fb2_outer_tpid_entry_delete(unit, tpid_index));
   2232         }
   2233     }
   2234 
   2235     return BCM_E_NONE;
   2236 }
   2237 
   2238 /*
   2239  * Function:
   2240  *      _bcm_trident_niv_match_info_get
   2241  * Purpose:
   2242  *      Get match criteria for NIV VP.
   2243  * Parameters:
   2244  *      unit                 - (IN) SOC unit number.
   2245  *      vp                   - (IN) Virtual port number.
   2246  *      port                 - (OUT) Physical GPORT ID. 
   2247  *      match_vlan           - (OUT) Outer VLAN ID to match. 
   2248  *      virtual_interface_id - (OUT) Virtual Interface ID. 
   2249  * Returns:
   2250  *      BCM_X_XXX
   2251  */
   2252 STATIC void
   2253 _bcm_trident_niv_match_info_get(
   2254     int unit, int vp, bcm_gport_t *port,
   2255     bcm_vlan_t *match_vlan, uint16 *vintf_id)
   2256 {
   2257     if ((NIV_PORT_INFO(unit, vp)->flags & BCM_NIV_PORT_MATCH_NONE) &&
   2258         (NIV_PORT_INFO(unit, vp)->egress_list != NULL) &&
   2259         !(NIV_PORT_INFO(unit, vp)->egress_list->flags & BCM_NIV_EGRESS_MULTICAST)) {
   2260         if (port) {
   2261             *port = NIV_PORT_INFO(unit, vp)->egress_list->port;
   2262         }
   2263         
   2264         if (match_vlan) {
   2265             *match_vlan = NIV_PORT_INFO(unit, vp)->egress_list->match_vlan;
   2266         }
   2267 
   2268         if (vintf_id) {
   2269             *vintf_id =
   2270                 NIV_PORT_INFO(unit, vp)->egress_list->virtual_interface_id;
   2271         }
   2272     } else {
   2273         if (port) {
   2274             *port = NIV_PORT_INFO(unit, vp)->port;
   2275         }
   2276 
   2277         if (match_vlan) {
   2278             *match_vlan = NIV_PORT_INFO(unit, vp)->match_vlan;
   2279         }
   2280 
   2281         if (vintf_id) {
   2282             *vintf_id =
   2283                 NIV_PORT_INFO(unit, vp)->virtual_interface_id;
   2284         }
   2285     }
   2286 
   2287     return;
   2288 }
   2289 
   2290 /*
   2291  * Function:
   2292  *      _bcm_trident_niv_match_add
   2293  * Purpose:
   2294  *      Add match criteria for NIV VP.
   2295  * Parameters:
   2296  *      unit - (IN) SOC unit number. 
   2297  *      port - (IN) Physical GPORT ID. 
   2298  *      virtual_interface_id - (IN) Virtual Interface ID. 
   2299  *      match_vlan - (IN) Outer VLAN ID to match. 
   2300  *      vp - (IN) Virtual port number.
   2301  * Returns:
   2302  *      BCM_X_XXX
   2303  */
   2304 int
   2305 _bcm_trident_niv_match_add(int unit, bcm_gport_t port,
   2306         uint16 virtual_interface_id, bcm_vlan_t match_vlan, int vp)
   2307 {
   2308     uint32                vent[SOC_MAX_MEM_FIELD_WORDS];
   2309     uint32                old_vent[SOC_MAX_MEM_FIELD_WORDS];
   2310     int                   key_type;
   2311     bcm_module_t          mod_out;
   2312     bcm_port_t            port_out;
   2313     bcm_trunk_t           trunk_out;
   2314     int                   tmp_id;
   2315     bcm_vlan_action_set_t action;
   2316     uint32                profile_idx;
   2317     int                   rv;
   2318     bcm_trunk_t           trunk_id;
   2319     int                   idx;
   2320     int                   mod_local = FALSE;
   2321     int                   num_local_ports;
   2322     bcm_port_t            local_ports[SOC_MAX_NUM_PORTS];
   2323     int                   local_member_count;
   2324     bcm_port_t            local_member_array[SOC_MAX_NUM_PORTS];
   2325     int                   port_key_type_vif_vlan, port_key_type_vif;
   2326     int                   port_key_type_a, port_key_type_b;
   2327     int                   use_port_a, use_port_b;
   2328     int                   vt_enable;
   2329     soc_mem_t             vxmem = VLAN_XLATEm;
   2330 
   2331     if (soc_mem_is_valid(unit, VLAN_XLATE_1_DOUBLEm)) {
   2332         vxmem = VLAN_XLATE_1_DOUBLEm;
   2333     }
   2334     sal_memset(vent, 0, sizeof(vent));
   2335     if (soc_feature(unit, soc_feature_base_valid)) {
   2336         soc_mem_field32_set(unit, vxmem, vent, BASE_VALID_0f, 3);
   2337         soc_mem_field32_set(unit, vxmem, vent, BASE_VALID_1f, 7);
   2338     } else {
   2339         soc_mem_field32_set(unit, vxmem, vent, VALIDf, 1);
   2340     }
   2341 
   2342     if (BCM_VLAN_VALID(match_vlan)) {
   2343         BCM_IF_ERROR_RETURN(_bcm_esw_vlan_xlate_key_type_value_get(unit,
   2344                     VLXLT_HASH_KEY_TYPE_VIF_VLAN, &key_type));
   2345         soc_mem_field32_set(unit, vxmem, vent, VIF__VLANf,
   2346                             match_vlan);
   2347     } else {
   2348         BCM_IF_ERROR_RETURN(_bcm_esw_vlan_xlate_key_type_value_get(unit,
   2349                     VLXLT_HASH_KEY_TYPE_VIF, &key_type));
   2350     }
   2351     soc_mem_field32_set(unit, vxmem, vent, KEY_TYPEf, key_type);
   2352     if (soc_mem_field_valid(unit, vxmem, DATA_TYPEf)) {
   2353         soc_mem_field32_set(unit, vxmem, vent, DATA_TYPEf, key_type);
   2354     }
   2355 
   2356     if (virtual_interface_id >=
   2357             (1 << soc_mem_field_length(unit, vxmem, VIF__SRC_VIFf))) {
   2358         return BCM_E_PARAM;
   2359     }
   2360     soc_mem_field32_set(unit, vxmem, vent, VIF__SRC_VIFf,
   2361             virtual_interface_id);
   2362 
   2363     if (soc_mem_field_valid(unit, vxmem, SOURCE_TYPEf)) {
   2364         soc_mem_field32_set(unit, vxmem, vent, SOURCE_TYPEf, 1);
   2365     }
   2366     BCM_IF_ERROR_RETURN
   2367         (_bcm_esw_gport_resolve(unit, port,
   2368                                 &mod_out, &port_out, &trunk_out, &tmp_id));
   2369     if (BCM_GPORT_IS_TRUNK(port)) {
   2370         soc_mem_field32_set(unit, vxmem, vent, VIF__Tf, 1);
   2371         soc_mem_field32_set(unit, vxmem, vent, VIF__TGIDf, trunk_out);
   2372     } else {
   2373         soc_mem_field32_set(unit, vxmem, vent, VIF__MODULE_IDf, mod_out);
   2374         soc_mem_field32_set(unit, vxmem, vent, VIF__PORT_NUMf, port_out);
   2375     }
   2376 
   2377     soc_mem_field32_set(unit, vxmem, vent, VIF__MPLS_ACTIONf, 0x1); /* SVP */
   2378     soc_mem_field32_set(unit, vxmem, vent, VIF__SOURCE_VPf, vp);
   2379 
   2380     bcm_vlan_action_set_t_init(&action);
   2381     if (BCM_VLAN_VALID(match_vlan)) {
   2382         soc_mem_field32_set(unit, vxmem, vent, VIF__NEW_OVIDf, match_vlan);
   2383         action.dt_outer = bcmVlanActionCopy;
   2384         action.dt_inner = bcmVlanActionDelete;
   2385         action.ot_outer = bcmVlanActionReplace;
   2386     } else {
   2387         action.ot_outer_prio = bcmVlanActionReplace;
   2388         action.ut_outer = bcmVlanActionAdd;
   2389     }
   2390     BCM_IF_ERROR_RETURN
   2391         (_bcm_trx_vlan_action_profile_entry_add(unit, &action, &profile_idx));
   2392     soc_mem_field32_set(unit, vxmem, vent, VIF__TAG_ACTION_PROFILE_PTRf,
   2393             profile_idx);
   2394 #ifdef BCM_TRIDENT2_SUPPORT
   2395     if (soc_mem_field_valid(unit, vxmem, VIF__VLAN_ACTION_VALIDf)) {
   2396         soc_mem_field32_set(unit, vxmem, vent, VIF__VLAN_ACTION_VALIDf, 1);
   2397     }
   2398 #endif /* BCM_TRIDENT2_SUPPORT */
   2399 
   2400     rv = soc_mem_insert_return_old(unit, vxmem, MEM_BLOCK_ALL, vent, old_vent);
   2401     if (rv == SOC_E_EXISTS) {
   2402         /* Delete the old vlan translate profile entry */
   2403         profile_idx = soc_mem_field32_get(unit, vxmem, old_vent,
   2404                 VIF__TAG_ACTION_PROFILE_PTRf);
   2405         rv = _bcm_trx_vlan_action_profile_entry_delete(unit, profile_idx);
   2406     }
   2407     BCM_IF_ERROR_RETURN(rv);
   2408 
   2409     num_local_ports = 0;
   2410     if (BCM_GPORT_IS_TRUNK(port)) {
   2411         trunk_id = BCM_GPORT_TRUNK_GET(port);
   2412         rv = _bcm_trunk_id_validate(unit, trunk_id);
   2413         if (BCM_FAILURE(rv)) {
   2414             return BCM_E_PORT;
   2415         }
   2416         rv = _bcm_esw_trunk_local_members_get(unit, trunk_id,
   2417                 SOC_MAX_NUM_PORTS, local_member_array, &local_member_count);
   2418         if (BCM_FAILURE(rv)) {
   2419             return BCM_E_PORT;
   2420         }
   2421         for (idx = 0; idx < local_member_count; idx++) {
   2422             local_ports[num_local_ports++] = local_member_array[idx];
   2423         }
   2424     } else {
   2425         BCM_IF_ERROR_RETURN
   2426             (_bcm_esw_gport_resolve(unit, port, &mod_out, &port_out,
   2427                                     &trunk_id, &tmp_id)); 
   2428         if ((trunk_id != -1) || (tmp_id != -1)) {
   2429             return BCM_E_PARAM;
   2430         }
   2431 #if defined(BCM_TRIDENT2PLUS_SUPPORT) && defined(BCM_HGPROXY_COE_SUPPORT)
   2432         if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) &&
   2433             _bcm_xgs5_subport_coe_mod_port_local(unit, mod_out, port_out)) {
   2434             mod_local = TRUE;
   2435             _BCM_SUBPORT_COE_PORT_ID_SET(port_out, mod_out, port_out);
   2436             _BCM_SUBPORT_COE_PORT_TYPE_SET(port_out, _BCM_SUBPORT_COE_TYPE_SUBTAG);
   2437         } else
   2438 #endif /* BCM_TRIDENT2PLUS_SUPPORT && BCM_HGPROXY_COE_SUPPORT */
   2439         {
   2440             BCM_IF_ERROR_RETURN(
   2441                 _bcm_esw_modid_is_local(unit, mod_out, &mod_local));
   2442         }
   2443         if (mod_local) {
   2444             local_ports[num_local_ports++] = port_out;
   2445         }
   2446     }
   2447 
   2448     BCM_IF_ERROR_RETURN(_bcm_esw_pt_vtkey_type_value_get(unit,
   2449                 VLXLT_HASH_KEY_TYPE_VIF_VLAN, &port_key_type_vif_vlan));
   2450     BCM_IF_ERROR_RETURN(_bcm_esw_pt_vtkey_type_value_get(unit,
   2451                 VLXLT_HASH_KEY_TYPE_VIF, &port_key_type_vif));
   2452     for (idx = 0; idx < num_local_ports; idx++) {
   2453         BCM_IF_ERROR_RETURN(_bcm_esw_port_config_get(unit, local_ports[idx],
   2454                     _bcmPortVTKeyTypeFirst, &port_key_type_a));
   2455         BCM_IF_ERROR_RETURN(_bcm_esw_port_config_get(unit, local_ports[idx],
   2456                     _bcmPortVTKeyPortFirst, &use_port_a));
   2457         BCM_IF_ERROR_RETURN(_bcm_esw_port_config_get(unit, local_ports[idx],
   2458                     _bcmPortVTKeyTypeSecond, &port_key_type_b));
   2459         BCM_IF_ERROR_RETURN(_bcm_esw_port_config_get(unit, local_ports[idx],
   2460                     _bcmPortVTKeyPortSecond, &use_port_b));
   2461 
   2462         if (BCM_VLAN_VALID(match_vlan)) {
   2463             if ((port_key_type_a != port_key_type_vif_vlan) &&
   2464                     (port_key_type_b != port_key_type_vif_vlan)) {
   2465                 BCM_IF_ERROR_RETURN(_bcm_esw_port_config_set(unit,
   2466                             local_ports[idx], _bcmPortVTKeyTypeFirst,
   2467                             port_key_type_vif_vlan));
   2468                 BCM_IF_ERROR_RETURN(_bcm_esw_port_config_set(unit,
   2469                             local_ports[idx], _bcmPortVTKeyPortFirst, 1));
   2470                 if (port_key_type_a == port_key_type_vif) {
   2471                     /* The first slot contained VIF key type, which
   2472                      * was just overwritten by VIF_VLAN key type. Hence,
   2473                      * the VIF key type needs to be moved to second slot.
   2474                      */
   2475                     BCM_IF_ERROR_RETURN(_bcm_esw_port_config_set(unit,
   2476                                 local_ports[idx], _bcmPortVTKeyTypeSecond,
   2477                                 port_key_type_a));
   2478                     BCM_IF_ERROR_RETURN(_bcm_esw_port_config_set(unit,
   2479                                 local_ports[idx], _bcmPortVTKeyPortSecond,
   2480                                 use_port_a));
   2481                 }
   2482             }
   2483         } else {
   2484             if (port_key_type_b != port_key_type_vif) {
   2485                 BCM_IF_ERROR_RETURN(_bcm_esw_port_config_set(unit,
   2486                             local_ports[idx], _bcmPortVTKeyTypeSecond,
   2487                             port_key_type_vif));
   2488                 BCM_IF_ERROR_RETURN(_bcm_esw_port_config_set(unit,
   2489                             local_ports[idx], _bcmPortVTKeyPortSecond, 1));
   2490             }
   2491         }
   2492 
   2493         /* Enable ingress VLAN translation */
   2494         BCM_IF_ERROR_RETURN
   2495             (_bcm_esw_port_config_get(unit, local_ports[idx],
   2496                                       _bcmPortVlanTranslate, &vt_enable));
   2497         if (!vt_enable) {
   2498             BCM_IF_ERROR_RETURN
   2499                 (_bcm_esw_port_config_set(unit, local_ports[idx],
   2500                                           _bcmPortVlanTranslate, 1));
   2501         }
   2502 
   2503         if (BCM_VLAN_VALID(match_vlan)) {
   2504             /* Enable egress VLAN translation */
   2505             BCM_IF_ERROR_RETURN(
   2506                 _bcm_fb2_egr_vlan_control_field_set(
   2507                     unit, local_ports[idx], VT_ENABLEf, 1));
   2508         }
   2509     }
   2510 
   2511     return BCM_E_NONE;
   2512 }
   2513 
   2514 /*
   2515  * Function:
   2516  *      _bcm_trident_niv_match_delete
   2517  * Purpose:
   2518  *      Delete match criteria for NIV VP.
   2519  * Parameters:
   2520  *      unit - (IN) SOC unit number. 
   2521  *      port - (IN) Physical GPORT ID. 
   2522  *      virtual_interface_id - (IN) Virtual Interface ID. 
   2523  *      match_vlan - (IN) Outer VLAN ID to match. 
   2524  *      old_vp - (OUT) Pointer to the old virtual port number of the entry.
   2525  * Returns:
   2526  *      BCM_X_XXX
   2527  */
   2528 int
   2529 _bcm_trident_niv_match_delete(int unit, bcm_gport_t port,
   2530         uint16 virtual_interface_id, bcm_vlan_t match_vlan, int *old_vp)
   2531 {
   2532     uint32             vent[SOC_MAX_MEM_FIELD_WORDS];
   2533     uint32             old_vent[SOC_MAX_MEM_FIELD_WORDS];
   2534     int                key_type;
   2535     bcm_module_t       mod_out;
   2536     bcm_port_t         port_out;
   2537     bcm_trunk_t        trunk_out;
   2538     int                tmp_id;
   2539     uint32             profile_idx;
   2540     int                rv;
   2541     soc_mem_t             vxmem = VLAN_XLATEm;
   2542 
   2543     if (soc_mem_is_valid(unit, VLAN_XLATE_1_DOUBLEm)) {
   2544         vxmem = VLAN_XLATE_1_DOUBLEm;
   2545     }
   2546     sal_memset(vent, 0, sizeof(vent));
   2547 
   2548     if (BCM_VLAN_VALID(match_vlan)) {
   2549         BCM_IF_ERROR_RETURN(_bcm_esw_vlan_xlate_key_type_value_get(unit,
   2550                     VLXLT_HASH_KEY_TYPE_VIF_VLAN, &key_type));
   2551         soc_mem_field32_set(unit, vxmem, vent, VIF__VLANf, match_vlan);
   2552     } else {
   2553         BCM_IF_ERROR_RETURN(_bcm_esw_vlan_xlate_key_type_value_get(unit,
   2554                     VLXLT_HASH_KEY_TYPE_VIF, &key_type));
   2555     }
   2556     soc_mem_field32_set(unit, vxmem, vent, KEY_TYPEf, key_type);
   2557     if (soc_mem_field_valid(unit, vxmem, DATA_TYPEf)) {
   2558         soc_mem_field32_set(unit, vxmem, vent, DATA_TYPEf, key_type);
   2559     }
   2560 
   2561     if (virtual_interface_id >=
   2562               (1 << soc_mem_field_length(unit, vxmem, VIF__SRC_VIFf))) {
   2563         return BCM_E_PARAM;
   2564     }
   2565     soc_mem_field32_set(unit, vxmem, vent, VIF__SRC_VIFf,
   2566             virtual_interface_id);
   2567 
   2568     if (soc_mem_field_valid(unit, vxmem, SOURCE_TYPEf)) {
   2569         soc_mem_field32_set(unit, vxmem, vent, SOURCE_TYPEf, 1);
   2570     }
   2571     BCM_IF_ERROR_RETURN
   2572         (_bcm_esw_gport_resolve(unit, port, &mod_out, &port_out, &trunk_out,
   2573                                 &tmp_id));
   2574     if (BCM_GPORT_IS_TRUNK(port)) {
   2575         soc_mem_field32_set(unit, vxmem, vent, VIF__Tf, 1);
   2576         soc_mem_field32_set(unit, vxmem, vent, VIF__TGIDf, trunk_out);
   2577     } else {
   2578         soc_mem_field32_set(unit, vxmem, vent, VIF__MODULE_IDf, mod_out);
   2579         soc_mem_field32_set(unit, vxmem, vent, VIF__PORT_NUMf, port_out);
   2580     }
   2581 
   2582     if (soc_feature(unit, soc_feature_base_valid)) {
   2583         soc_mem_field32_set(unit, vxmem, vent, BASE_VALID_0f, 3);
   2584         soc_mem_field32_set(unit, vxmem, vent, BASE_VALID_1f, 7);
   2585     }
   2586 
   2587     rv = soc_mem_delete_return_old(unit, vxmem, MEM_BLOCK_ALL,
   2588             vent, old_vent);
   2589     if (BCM_SUCCESS(rv)) {
   2590         int vld;
   2591 
   2592         if (soc_feature(unit, soc_feature_base_valid)) {
   2593             vld = soc_mem_field32_get(unit, vxmem, old_vent,
   2594                                       BASE_VALID_0f) == 3 &&
   2595                   soc_mem_field32_get(unit, vxmem, old_vent,
   2596                                       BASE_VALID_1f) == 7;
   2597         } else {
   2598             vld = soc_mem_field32_get(unit, vxmem, old_vent, VALIDf);
   2599         }
   2600         if (vld) {
   2601             if (old_vp != NULL) {
   2602                 *old_vp = soc_mem_field32_get(unit, vxmem, old_vent,
   2603                                               VIF__SOURCE_VPf);
   2604             }
   2605             profile_idx = soc_mem_field32_get(unit, vxmem, old_vent,
   2606                                               VIF__TAG_ACTION_PROFILE_PTRf);
   2607             /* Delete the old vlan action profile entry */
   2608             rv = _bcm_trx_vlan_action_profile_entry_delete(unit, profile_idx);
   2609         }
   2610     }
   2611 
   2612     return rv;
   2613 }
   2614 
   2615 /*
   2616  * Function:
   2617  *      _trident_niv_vxlate_traverse
   2618  * Purpose:
   2619  * traverse the vlan_xlate table to find out entries created
   2620  * based on the niv port. Based on the delete_action flag to either 
   2621  * modify or delete the found entries 
   2622  *
   2623  * Parameters:
   2624  *      unit - (IN) SOC unit number.
   2625  *      vp - (IN) Virtual port number.
   2626  *      niv_port - (IN) new niv port info
   2627  *      delete_action - (IN) delete the found entry if TRUE or modify 
   2628  *                           if FALSE
   2629  * Returns:
   2630  *      BCM_X_XXX
   2631  */
   2632 
   2633 STATIC int 
   2634 _trident_niv_vxlate_traverse (int unit, int vp, 
   2635                bcm_niv_port_t *niv_port, int delete_action)
   2636 {
   2637     /* Indexes to iterate over memories, chunks and entries */
   2638     int             chnk_idx, ent_idx, chnk_idx_max, mem_idx_max;
   2639     int             buf_size, chunksize, chnk_end;
   2640     uint32          *vt_tbl_chnk;
   2641     uint32          *vent;
   2642     int             valid,  rv = BCM_E_NONE;
   2643     int             tmp_id;
   2644     bcm_module_t    mod_out;
   2645     bcm_port_t      port_out;
   2646     bcm_trunk_t     trunk_out;
   2647     uint32          old_vent[SOC_MAX_MEM_FIELD_WORDS];
   2648     soc_mem_t mem;
   2649     int key_val;
   2650     int vt_key;
   2651     int vent_vp;
   2652     int profile_idx;
   2653     int vif_hit;
   2654     int vif;
   2655     int vent_gport;
   2656 
   2657     if ((!delete_action) && (niv_port == NULL)) {
   2658         return BCM_E_INTERNAL;
   2659     }
   2660     mem = VLAN_XLATEm;
   2661     if (soc_mem_is_valid(unit, VLAN_XLATE_1_DOUBLEm)) {
   2662         mem = VLAN_XLATE_1_DOUBLEm;
   2663     }
   2664 
   2665     chunksize = soc_property_get(unit, spn_VLANDELETE_CHUNKS,
   2666                                  VLAN_MEM_CHUNKS_DEFAULT);
   2667     buf_size = 4 * SOC_MAX_MEM_FIELD_WORDS * chunksize;
   2668     vt_tbl_chnk = soc_cm_salloc(unit, buf_size, "vlan translate traverse");
   2669     if (NULL == vt_tbl_chnk) {
   2670         return BCM_E_MEMORY;
   2671     }
   2672 
   2673     mem_idx_max = soc_mem_index_max(unit, mem);
   2674     for (chnk_idx = soc_mem_index_min(unit, mem);
   2675          chnk_idx <= mem_idx_max;
   2676          chnk_idx += chunksize) {
   2677         sal_memset((void *)vt_tbl_chnk, 0, buf_size);
   2678 
   2679         chnk_idx_max =
   2680             ((chnk_idx + chunksize) <= mem_idx_max) ?
   2681             chnk_idx + chunksize - 1: mem_idx_max;
   2682 
   2683         soc_mem_lock(unit, mem);
   2684         rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY,
   2685                                 chnk_idx, chnk_idx_max, vt_tbl_chnk);
   2686         if (SOC_FAILURE(rv)) {
   2687             soc_mem_unlock(unit, mem);
   2688             break;
   2689         }
   2690         chnk_end = (chnk_idx_max - chnk_idx);
   2691         for (ent_idx = 0 ; ent_idx <= chnk_end; ent_idx ++) {
   2692             vent = soc_mem_table_idx_to_pointer(unit, mem, uint32 *,
   2693                                                 vt_tbl_chnk, ent_idx);
   2694             if (soc_feature(unit, soc_feature_base_valid)) {
   2695                 valid = soc_mem_field32_get(unit, mem, vent,
   2696                                             BASE_VALID_0f) == 3 &&
   2697                         soc_mem_field32_get(unit, mem, vent,
   2698                                             BASE_VALID_1f) == 7;
   2699             } else {
   2700                 valid = soc_mem_field32_get(unit, mem, vent, VALIDf);
   2701             }
   2702             if (!valid) {
   2703                 continue;
   2704             }
   2705             key_val = soc_mem_field32_get(unit, mem, vent, KEY_TYPEf);
   2706             rv = _bcm_esw_vlan_xlate_key_type_get(unit,
   2707                   key_val,&vt_key);
   2708 
   2709             if (BCM_FAILURE(rv)) {
   2710                 break;
   2711             }
   2712             switch (vt_key) {
   2713                 case VLXLT_HASH_KEY_TYPE_VIF_OTAG:
   2714                 case VLXLT_HASH_KEY_TYPE_VIF_ITAG:
   2715                 case VLXLT_HASH_KEY_TYPE_VIF_VLAN:
   2716                 case VLXLT_HASH_KEY_TYPE_VIF_CVLAN:
   2717                     vif_hit = TRUE;
   2718                     break;
   2719                 default:
   2720                     vif_hit = FALSE;
   2721                     break;
   2722             }
   2723             if (vif_hit == FALSE) {
   2724                 continue;
   2725             }
   2726             vent_vp = soc_mem_field32_get(unit, mem, vent, VIF__SOURCE_VPf);
   2727             vif = soc_mem_field32_get(unit, mem, vent, VIF__SRC_VIFf);
   2728             tmp_id = soc_mem_field32_get(unit, mem, vent, VIF__Tf);
   2729             if (tmp_id) {
   2730                 trunk_out = soc_mem_field32_get(unit, mem, vent, VIF__TGIDf);
   2731                 BCM_GPORT_TRUNK_SET(vent_gport,trunk_out);
   2732             } else {
   2733                 mod_out = soc_mem_field32_get(unit, mem, vent, VIF__MODULE_IDf);
   2734                 port_out = soc_mem_field32_get(unit, mem, vent, VIF__PORT_NUMf);
   2735                 BCM_GPORT_MODPORT_SET(vent_gport,mod_out,port_out);
   2736             }
   2737                
   2738             if ((vent_vp != vp) || 
   2739                 (vent_gport != NIV_PORT_INFO(unit, vp)->port) ||
   2740                 (vif != NIV_PORT_INFO(unit, vp)->virtual_interface_id) ) {
   2741                 continue;
   2742             }
   2743 
   2744             if (soc_feature(unit, soc_feature_base_valid)) {
   2745                 soc_mem_field32_set(unit, mem, vent, BASE_VALID_0f, 3);
   2746                 soc_mem_field32_set(unit, mem, vent, BASE_VALID_1f, 7);
   2747             }
   2748 
   2749             /* found the match, delete it first */
   2750             rv = soc_mem_delete_return_old(unit, mem,MEM_BLOCK_ALL,
   2751                                            vent, old_vent);
   2752 
   2753             if (BCM_FAILURE(rv)) {
   2754                 break;
   2755             }
   2756             if (delete_action) {
   2757                 profile_idx = soc_mem_field32_get(unit, mem, old_vent,
   2758                                     VIF__TAG_ACTION_PROFILE_PTRf);
   2759                 rv = _bcm_trx_vlan_action_profile_entry_delete(unit,
   2760                              profile_idx);
   2761                 if (BCM_FAILURE(rv)) {
   2762                     break;
   2763                 } else {
   2764                     continue;
   2765                 }
   2766             }
   2767 
   2768             /* modification action */
   2769             vif = niv_port->virtual_interface_id;
   2770 
   2771             /* replace with the new niv port info */
   2772             soc_mem_field32_set(unit, mem, old_vent, VIF__SRC_VIFf, vif);
   2773             rv = _bcm_esw_gport_resolve(unit, niv_port->port,
   2774                       &mod_out, &port_out, &trunk_out, &tmp_id);
   2775             if (BCM_FAILURE(rv)) {
   2776                 break;
   2777             }
   2778             if (BCM_GPORT_IS_TRUNK(niv_port->port)) {
   2779                 soc_mem_field32_set(unit, mem, old_vent, VIF__Tf, 1);
   2780                 soc_mem_field32_set(unit, mem, old_vent, VIF__TGIDf,
   2781                                     trunk_out);
   2782             } else {
   2783                 soc_mem_field32_set(unit, mem, old_vent, VIF__MODULE_IDf,
   2784                                     mod_out);
   2785                 soc_mem_field32_set(unit, mem, old_vent, VIF__PORT_NUMf,
   2786                              port_out);
   2787             }
   2788             rv = soc_mem_insert(unit, mem, MEM_BLOCK_ALL, old_vent);
   2789             if (BCM_FAILURE(rv)) {
   2790                 break;
   2791             }
   2792         }
   2793         soc_mem_unlock(unit, mem);
   2794         if (BCM_FAILURE(rv)) {
   2795             break;
   2796         }
   2797     }
   2798     soc_cm_sfree(unit, vt_tbl_chnk);
   2799     return rv;
   2800 }
   2801 
   2802 /*
   2803  * Function:
   2804  *      bcm_trident_niv_port_add
   2805  * Purpose:
   2806  *      Create a NIV port on VIS.
   2807  * Parameters:
   2808  *      unit - (IN) SOC unit number. 
   2809  *      niv_port - (IN/OUT) NIV port information (OUT : niv_port_id)
   2810  * Returns:
   2811  *      BCM_X_XXX
   2812  */
   2813 int
   2814 bcm_trident_niv_port_add(int unit,
   2815                          bcm_niv_port_t *niv_port)
   2816 {
   2817     int mode;
   2818     int vp, old_vp = 0, matched_vp;
   2819     int rv = BCM_E_NONE;
   2820     int num_vp;
   2821     int nh_index = 0;
   2822     bcm_if_t intf;
   2823     uint32 nh_flags;
   2824     bcm_l3_egress_t nh_info;
   2825     ing_dvp_table_entry_t dvp_entry;
   2826     source_vp_entry_t svp_entry;
   2827     int cml_default_enable=0, cml_default_new=0, cml_default_move=0;
   2828     int tpid_index, tpid_enable=0, old_tpid_enable=0;
   2829     int i;
   2830     _bcm_vp_info_t vp_info;
   2831 
   2832     _bcm_vp_info_init(&vp_info);
   2833     vp_info.vp_type = _bcmVpTypeNiv;
   2834 
   2835     BCM_IF_ERROR_RETURN(bcm_xgs3_l3_egress_mode_get(unit, &mode));
   2836     if (!mode) {
   2837         LOG_INFO(BSL_LS_BCM_L3,
   2838                  (BSL_META_U(unit,
   2839                              "L3 egress mode must be set first\n")));
   2840         return BCM_E_DISABLED;
   2841     }
   2842 
   2843     /* Check for invalid flag combinations */
   2844     if (niv_port->flags & BCM_NIV_PORT_MATCH_NONE) {
   2845         if ((niv_port->flags & BCM_NIV_PORT_REPLACE) ||
   2846             (niv_port->flags & BCM_NIV_PORT_MULTICAST) ||
   2847             (niv_port->flags & BCM_NIV_PORT_MATCH_DO_NOT_ADD)) {
   2848             return BCM_E_PARAM;
   2849         }
   2850     }
   2851 
   2852     if (!(niv_port->flags & BCM_NIV_PORT_REPLACE)) { /* Create new NIV VP */
   2853 
   2854         if (niv_port->flags & BCM_NIV_PORT_WITH_ID) {
   2855             if (!BCM_GPORT_IS_NIV_PORT(niv_port->niv_port_id)) {
   2856                 return BCM_E_PARAM;
   2857             }
   2858             vp = BCM_GPORT_NIV_PORT_ID_GET(niv_port->niv_port_id);
   2859             if (vp >= soc_mem_index_count(unit, SOURCE_VPm)) {
   2860                 return BCM_E_PARAM;
   2861             }
   2862             if (_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   2863                 return BCM_E_EXISTS;
   2864             } else {
   2865                 rv = _bcm_vp_used_set(unit, vp, vp_info);
   2866                 if (rv < 0) {
   2867                     return rv;
   2868                 }
   2869             }
   2870         } else {
   2871             /* allocate a new VP index */
   2872             num_vp = soc_mem_index_count(unit, SOURCE_VPm);
   2873             rv = _bcm_vp_alloc(unit, 0, (num_vp - 1), 1, SOURCE_VPm,
   2874                     vp_info, &vp);
   2875             if (rv < 0) {
   2876                 return rv;
   2877             }
   2878         }
   2879 
   2880         if (niv_port->flags & BCM_NIV_PORT_MATCH_NONE) {
   2881             /* For a NIV port without any match criteria, an invalid
   2882              * next hop index will be written to the ING_DVP_TABLE.
   2883              */
   2884             nh_index = NIV_INFO(unit)->invalid_next_hop_index;
   2885         } else {
   2886             /* Allocate a next hop index */
   2887             bcm_l3_egress_t_init(&nh_info);
   2888             nh_flags = _BCM_L3_SHR_MATCH_DISABLE | _BCM_L3_SHR_WRITE_DISABLE;
   2889             rv = bcm_xgs3_nh_add(unit, nh_flags, &nh_info, &nh_index);
   2890             if (rv < 0) {
   2891                 goto cleanup;
   2892             }
   2893            
   2894             /* configure next hop tables */
   2895             rv = _bcm_trident_niv_nh_info_set(unit, nh_index,
   2896                     (niv_port->flags & BCM_NIV_PORT_MULTICAST) ? 1 : 0,
   2897                     niv_port->port, niv_port->virtual_interface_id,
   2898                     niv_port->match_vlan, NULL, vp,
   2899                     (niv_port->flags & BCM_NIV_VNTAG_L_BIT_FORCE_1) ? 1 : 0);
   2900             if (rv < 0) {
   2901                 goto cleanup;
   2902             }
   2903         }
   2904 
   2905         /* Configure DVP table */
   2906         intf = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit) + nh_index;
   2907         rv = _bcm_vp_ing_dvp_config(unit, _bcmVpIngDvpConfigSet, vp, 
   2908                                     ING_DVP_CONFIG_INVALID_VP_TYPE, intf, 
   2909                                     ING_DVP_CONFIG_INVALID_PORT_TYPE);
   2910         if (rv < 0) {
   2911             goto cleanup;
   2912         }
   2913 
   2914         /* Configure SVP table */
   2915         sal_memset(&svp_entry, 0, sizeof(source_vp_entry_t));
   2916         soc_SOURCE_VPm_field32_set(unit, &svp_entry, ENTRY_TYPEf, 3);
   2917 
   2918         /* Set the CML */
   2919         rv = _bcm_vp_default_cml_mode_get(unit, &cml_default_enable,
   2920                 &cml_default_new, &cml_default_move);
   2921         if (rv < 0) {
   2922             goto cleanup;
   2923         }
   2924         if (cml_default_enable) {
   2925             /* Set the CML to default values */
   2926             soc_SOURCE_VPm_field32_set(unit, &svp_entry, CML_FLAGS_NEWf, cml_default_new);
   2927             soc_SOURCE_VPm_field32_set(unit, &svp_entry, CML_FLAGS_MOVEf, cml_default_move);
   2928         } else {
   2929             /* Set the CML to PVP_CML_SWITCH by default (hw learn and forward) */
   2930             soc_SOURCE_VPm_field32_set(unit, &svp_entry, CML_FLAGS_NEWf, 0x8);
   2931             soc_SOURCE_VPm_field32_set(unit, &svp_entry, CML_FLAGS_MOVEf, 0x8);
   2932         }
   2933 
   2934         /* Set the SD-tag mode and TPID */
   2935         if (niv_port->match_service_tpid) {
   2936             rv = _bcm_fb2_outer_tpid_entry_add(unit, niv_port->match_service_tpid,
   2937                     &tpid_index);
   2938             if (rv < 0) {
   2939                 goto cleanup;
   2940             }
   2941             tpid_enable = 1 << tpid_index;
   2942             if (soc_mem_is_valid(unit, SVP_ATTRS_1m)) {
   2943                 rv = _bcm_trident_niv_tpid_enb_set(unit, NULL, vp, tpid_enable);
   2944                 if (rv < 0) {
   2945                     goto cleanup;
   2946                 }
   2947             } else {
   2948                 rv = _bcm_trident_niv_tpid_enb_set(unit, (uint32 *)&svp_entry,
   2949                                                    vp, tpid_enable);
   2950                 if (rv < 0) {
   2951                     goto cleanup;
   2952                 }
   2953             }
   2954             soc_SOURCE_VPm_field32_set(unit, &svp_entry, SD_TAG_MODEf, 1);
   2955         } else {
   2956             soc_SOURCE_VPm_field32_set(unit, &svp_entry, SD_TAG_MODEf, 0);
   2957         }
   2958 
   2959         soc_SOURCE_VPm_field32_set(unit, &svp_entry, CLASS_IDf, niv_port->if_class);
   2960 
   2961         rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp_entry);
   2962         if (rv < 0) {
   2963             goto cleanup;
   2964         }
   2965 
   2966         /* Configure SOURCE_VP_2 table */
   2967 #ifdef BCM_TRIDENT2_SUPPORT
   2968         if (soc_mem_field_valid(unit, SOURCE_VP_2m, PARSE_USING_SGLP_TPIDf)) {
   2969             source_vp_2_entry_t svp_2_entry;
   2970 
   2971             sal_memset(&svp_2_entry, 0, sizeof(source_vp_2_entry_t));
   2972             soc_SOURCE_VP_2m_field32_set(unit, &svp_2_entry, PARSE_USING_SGLP_TPIDf, 1);
   2973             rv = WRITE_SOURCE_VP_2m(unit, MEM_BLOCK_ALL, vp, &svp_2_entry);
   2974             if (rv < 0) {
   2975                 goto cleanup;
   2976             }
   2977         } else {
   2978             /* TD3TBD, in TD3, PARSE_USING_SGLP_TPID is removed */
   2979         }
   2980 #endif /* BCM_TRIDENT2_SUPPORT */
   2981 
   2982         /* Configure ingress VLAN translation table for unicast VPs */
   2983         if (!(niv_port->flags & BCM_NIV_PORT_MULTICAST) &&
   2984             !(niv_port->flags & BCM_NIV_PORT_MATCH_NONE) &&
   2985             !(niv_port->flags & BCM_NIV_PORT_MATCH_DO_NOT_ADD)) {
   2986             rv = _bcm_trident_niv_match_add(unit, niv_port->port,
   2987                     niv_port->virtual_interface_id, niv_port->match_vlan, vp);
   2988             if (rv < 0) {
   2989                 goto cleanup;
   2990             }
   2991         }
   2992 
   2993         if (!(niv_port->flags & BCM_NIV_PORT_MATCH_NONE)) {
   2994             /* Increment port's VP count */
   2995             rv = _bcm_trident_niv_port_cnt_update(unit, niv_port->port, vp, 
   2996                                                   TRUE, TRUE);
   2997             if (rv < 0) {
   2998                 goto cleanup;
   2999             }
   3000         }
   3001 
   3002     } else { /* Replace properties of existing NIV VP */
   3003         int all_same = 0;
   3004         int tpid_enb_len = 0;
   3005         bcm_niv_port_t niv_port_old;
   3006 
   3007         if (!(niv_port->flags & BCM_NIV_PORT_WITH_ID)) {
   3008             return BCM_E_PARAM;
   3009         }
   3010         if (!BCM_GPORT_IS_NIV_PORT(niv_port->niv_port_id)) {
   3011             return BCM_E_PARAM;
   3012         }
   3013         vp = BCM_GPORT_NIV_PORT_ID_GET(niv_port->niv_port_id);
   3014         if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   3015             return BCM_E_PARAM;
   3016         }
   3017 
   3018         bcm_niv_port_t_init(&niv_port_old);
   3019         niv_port_old.niv_port_id = niv_port->niv_port_id;
   3020         BCM_IF_ERROR_RETURN
   3021             (bcm_trident_niv_port_get(unit, &niv_port_old));
   3022 
   3023         if (BCM_GPORT_IS_TRUNK(niv_port->port)
   3024             && niv_port->port == niv_port_old.port
   3025             && (niv_port->flags & BCM_NIV_PORT_MULTICAST) 
   3026                 == (niv_port_old.flags & BCM_NIV_PORT_MULTICAST)
   3027             && (niv_port->flags & BCM_NIV_PORT_MATCH_DO_NOT_ADD)
   3028                 == (niv_port_old.flags & BCM_NIV_PORT_MATCH_DO_NOT_ADD)
   3029             && niv_port->virtual_interface_id 
   3030                 == niv_port_old.virtual_interface_id
   3031             && niv_port->match_vlan == niv_port_old.match_vlan
   3032             && niv_port->match_service_tpid
   3033                 == niv_port_old.match_service_tpid
   3034             && niv_port->if_class == niv_port_old.if_class) {
   3035 
   3036             all_same = 1;
   3037         } 
   3038 
   3039         matched_vp = vp;
   3040 
   3041         if (all_same == 0) {
   3042             /* For existing niv vp, NH entry already exists */
   3043             BCM_IF_ERROR_RETURN
   3044                 (READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp_entry));
   3045             
   3046             nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp_entry,
   3047                     NEXT_HOP_INDEXf);
   3048             
   3049             /* Update existing next hop entries */
   3050         BCM_IF_ERROR_RETURN
   3051             (_bcm_trident_niv_nh_info_set(unit, nh_index,
   3052                     (niv_port->flags & BCM_NIV_PORT_MULTICAST) ? 1 : 0,
   3053                     niv_port->port, niv_port->virtual_interface_id,
   3054                     niv_port->match_vlan, NULL, vp,
   3055                     (niv_port->flags & BCM_NIV_VNTAG_L_BIT_FORCE_1) ? 1 : 0));
   3056 
   3057             /* Update SD-tag mode, SD-tag TPID, and class ID */
   3058             BCM_IF_ERROR_RETURN
   3059                 (READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp_entry));
   3060             if (soc_mem_is_valid(unit, SVP_ATTRS_1m)) {
   3061                 BCM_IF_ERROR_RETURN(_bcm_trident_niv_tpid_enb_get(unit, NULL,
   3062                                     vp, &old_tpid_enable));
   3063                 tpid_enb_len = soc_mem_field_length(unit, SVP_ATTRS_1m,
   3064                                                     TPID_ENABLEf);
   3065             } else {
   3066                 BCM_IF_ERROR_RETURN(_bcm_trident_niv_tpid_enb_get(unit,
   3067                                     (uint32 *)&svp_entry, vp, &old_tpid_enable));
   3068                 tpid_enb_len = soc_mem_field_length(unit, SOURCE_VPm,
   3069                                                     TPID_ENABLEf);
   3070             }
   3071             if (niv_port->match_service_tpid) {
   3072                 BCM_IF_ERROR_RETURN(_bcm_fb2_outer_tpid_entry_add(unit,
   3073                             niv_port->match_service_tpid, &tpid_index));
   3074                 tpid_enable = 1 << tpid_index;
   3075                 if (soc_mem_is_valid(unit, SVP_ATTRS_1m)) {
   3076                     BCM_IF_ERROR_RETURN(_bcm_trident_niv_tpid_enb_set(unit, NULL,
   3077                                         vp, tpid_enable));
   3078                 } else {
   3079                     BCM_IF_ERROR_RETURN(_bcm_trident_niv_tpid_enb_set(unit,
   3080                                         (uint32 *)&svp_entry, vp, tpid_enable));
   3081                 }
   3082                 soc_SOURCE_VPm_field32_set(unit, &svp_entry, SD_TAG_MODEf, 1);
   3083             } else {
   3084                 soc_SOURCE_VPm_field32_set(unit, &svp_entry, SD_TAG_MODEf, 0);
   3085             }
   3086             if (old_tpid_enable) {
   3087                 for (i= 0; i < tpid_enb_len; i++) {
   3088                     if (old_tpid_enable & (1 << i)) {
   3089                         BCM_IF_ERROR_RETURN(
   3090                             _bcm_fb2_outer_tpid_entry_delete(unit, i));
   3091                     }
   3092                 }
   3093             }
   3094             soc_SOURCE_VPm_field32_set(unit, &svp_entry, CLASS_IDf,
   3095                     niv_port->if_class);
   3096             BCM_IF_ERROR_RETURN
   3097                 (WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp_entry));
   3098 
   3099             /* Delete old ingress VLAN translation entry,
   3100              * install new ingress VLAN translation entry
   3101              */
   3102             if (!(NIV_PORT_INFO(unit, vp)->flags & BCM_NIV_PORT_MULTICAST) &&
   3103                 !(NIV_PORT_INFO(unit, vp)->flags & BCM_NIV_PORT_MATCH_NONE) &&
   3104                 !(NIV_PORT_INFO(unit, vp)->flags & BCM_NIV_PORT_MATCH_DO_NOT_ADD)) {
   3105                 BCM_IF_ERROR_RETURN(_bcm_trident_niv_match_delete(unit,
   3106                             NIV_PORT_INFO(unit, vp)->port,
   3107                             NIV_PORT_INFO(unit, vp)->virtual_interface_id,
   3108                             NIV_PORT_INFO(unit, vp)->match_vlan,
   3109                             &old_vp));
   3110             }
   3111 #ifdef BCM_TRIDENT2_SUPPORT
   3112             /* The NIV port id may be one of members of a vplag. */
   3113             if (_bcm_vp_used_get(unit, old_vp, _bcmVpTypeVpLag)) {
   3114                 matched_vp = old_vp;
   3115             }
   3116 #endif
   3117         }
   3118 
   3119         if (!(niv_port->flags & BCM_NIV_PORT_MULTICAST) &&
   3120             !(niv_port->flags & BCM_NIV_PORT_MATCH_DO_NOT_ADD)) {
   3121             BCM_IF_ERROR_RETURN
   3122                 (_bcm_trident_niv_match_add(unit, niv_port->port,
   3123                                             niv_port->virtual_interface_id,
   3124                                             niv_port->match_vlan, matched_vp));
   3125         }
   3126 
   3127         if (all_same == 0) {
   3128             if (!(NIV_PORT_INFO(unit, vp)->flags & BCM_NIV_PORT_MULTICAST)) {
   3129                 /* traverse the vlan_xlate table to find out entries created
   3130                  * based on the niv port. Check the new niv port's multicast flag 
   3131                  * to modify or delete existing entries accordingly 
   3132                  */
   3133                 rv = _trident_niv_vxlate_traverse(unit,vp,niv_port,
   3134                         (niv_port->flags & BCM_NIV_PORT_MULTICAST)? TRUE:FALSE);
   3135                 BCM_IF_ERROR_RETURN(rv);
   3136             }
   3137         }
   3138         /* Decrement old port's VP count, increment new port's VP count */
   3139         BCM_IF_ERROR_RETURN
   3140             (_bcm_trident_niv_port_cnt_update(unit,
   3141                 NIV_PORT_INFO(unit, vp)->port, vp, FALSE, TRUE));
   3142 
   3143         BCM_IF_ERROR_RETURN
   3144             (_bcm_trident_niv_port_cnt_update(unit,
   3145                 niv_port->port, vp, TRUE, TRUE));
   3146 
   3147         if (all_same == 1) {
   3148             return BCM_E_NONE;
   3149         }
   3150     }
   3151 
   3152     /* Set NIV VP software state */
   3153     NIV_PORT_INFO(unit, vp)->flags = niv_port->flags;
   3154     NIV_PORT_INFO(unit, vp)->port = niv_port->port;
   3155     NIV_PORT_INFO(unit, vp)->virtual_interface_id = niv_port->virtual_interface_id;
   3156     NIV_PORT_INFO(unit, vp)->match_vlan = niv_port->match_vlan;
   3157     NIV_PORT_INFO(unit, vp)->egress_list = NULL;
   3158 
   3159     BCM_GPORT_NIV_PORT_ID_SET(niv_port->niv_port_id, vp);
   3160 
   3161     return rv;
   3162 
   3163 cleanup: /* In case of failure */
   3164     if (!(niv_port->flags & BCM_NIV_PORT_REPLACE)) {
   3165         (void) _bcm_vp_free(unit, _bcmVpTypeNiv, 1, vp);
   3166         if (!(niv_port->flags & BCM_NIV_PORT_MATCH_NONE)) {
   3167             _bcm_trident_niv_nh_info_delete(unit, nh_index);
   3168         }
   3169 
   3170         (void)_bcm_vp_ing_dvp_config(unit, _bcmVpIngDvpConfigClear, vp, 
   3171                                      ING_DVP_CONFIG_INVALID_VP_TYPE, 
   3172                                      ING_DVP_CONFIG_INVALID_INTF_ID, 
   3173                                      ING_DVP_CONFIG_INVALID_PORT_TYPE);
   3174 
   3175         sal_memset(&svp_entry, 0, sizeof(source_vp_entry_t));
   3176         (void)WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp_entry);
   3177 
   3178         if (tpid_enable) {
   3179             (void) _bcm_fb2_outer_tpid_entry_delete(unit, tpid_index);
   3180         }
   3181 
   3182 #ifdef BCM_TRIDENT2_SUPPORT
   3183         if (soc_mem_is_valid(unit, SOURCE_VP_2m)) {
   3184             source_vp_2_entry_t svp_2_entry;
   3185 
   3186             sal_memset(&svp_2_entry, 0, sizeof(source_vp_2_entry_t));
   3187             (void)WRITE_SOURCE_VP_2m(unit, MEM_BLOCK_ALL, vp, &svp_2_entry);
   3188         }
   3189 #endif /* BCM_TRIDENT2_SUPPORT */
   3190 
   3191         if (!(niv_port->flags & BCM_NIV_PORT_MULTICAST) &&
   3192             !(niv_port->flags & BCM_NIV_PORT_MATCH_NONE) &&
   3193             !(niv_port->flags & BCM_NIV_PORT_MATCH_DO_NOT_ADD)) {
   3194             (void) _bcm_trident_niv_match_delete(unit, niv_port->port,
   3195                     niv_port->virtual_interface_id, niv_port->match_vlan, NULL);
   3196         }
   3197     }
   3198 
   3199     return rv;
   3200 }
   3201 
   3202 /*
   3203  * Function:
   3204  *      bcm_trident_niv_port_delete
   3205  * Purpose:
   3206  *      Destroy a NIV virtual port.
   3207  * Parameters:
   3208  *      unit - (IN) SOC unit number. 
   3209  *      gport - (IN) NIV GPORT ID.
   3210  * Returns:
   3211  *      BCM_X_XXX
   3212  */
   3213 int
   3214 bcm_trident_niv_port_delete(int unit, bcm_gport_t gport)
   3215 {
   3216     int vp;
   3217     source_vp_entry_t svp_entry;
   3218     int nh_index;
   3219     ing_dvp_table_entry_t dvp_entry;
   3220     int old_tpid_enable, i, tpid_enb_len;
   3221 
   3222     if (!BCM_GPORT_IS_NIV_PORT(gport)) {
   3223         return BCM_E_PARAM;
   3224     }
   3225 
   3226     vp = BCM_GPORT_NIV_PORT_ID_GET(gport);
   3227     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   3228         return BCM_E_NOT_FOUND;
   3229     }
   3230 
   3231     if (NIV_PORT_INFO(unit, vp)->flags & BCM_NIV_PORT_MATCH_NONE) {
   3232         if (NIV_PORT_INFO(unit, vp)->egress_list != NULL) {
   3233             /* There are still NIV egress objects attached to this
   3234              * NIV port.
   3235              */
   3236             return BCM_E_BUSY;
   3237         }
   3238     }
   3239 
   3240     /* Delete ingress VLAN translation entry */
   3241     if (!(NIV_PORT_INFO(unit, vp)->flags & BCM_NIV_PORT_MULTICAST) &&
   3242         !(NIV_PORT_INFO(unit, vp)->flags & BCM_NIV_PORT_MATCH_NONE) &&
   3243         !(NIV_PORT_INFO(unit, vp)->flags & BCM_NIV_PORT_MATCH_DO_NOT_ADD)) {
   3244         BCM_IF_ERROR_RETURN(_bcm_trident_niv_match_delete(unit,
   3245                     NIV_PORT_INFO(unit, vp)->port,
   3246                     NIV_PORT_INFO(unit, vp)->virtual_interface_id,
   3247                     NIV_PORT_INFO(unit, vp)->match_vlan,
   3248                     NULL));
   3249         BCM_IF_ERROR_RETURN(_trident_niv_vxlate_traverse(unit,vp,
   3250                     NULL, TRUE));
   3251     }
   3252 
   3253     /* Clear SVP entry */
   3254     BCM_IF_ERROR_RETURN
   3255         (READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp_entry));
   3256     if (soc_mem_is_valid(unit, SVP_ATTRS_1m)) {
   3257         BCM_IF_ERROR_RETURN(_bcm_trident_niv_tpid_enb_get(unit, NULL,
   3258                             vp, &old_tpid_enable));
   3259         tpid_enb_len = soc_mem_field_length(unit, SVP_ATTRS_1m,
   3260                                             TPID_ENABLEf);
   3261     } else {
   3262         BCM_IF_ERROR_RETURN(_bcm_trident_niv_tpid_enb_get(unit,
   3263                             (uint32 *)&svp_entry, vp, &old_tpid_enable));
   3264         tpid_enb_len = soc_mem_field_length(unit, SOURCE_VPm,
   3265                                             TPID_ENABLEf);
   3266     }
   3267 
   3268     if (old_tpid_enable) {
   3269         for (i= 0; i < tpid_enb_len; i++) {
   3270             if (old_tpid_enable & (1 << i)) {
   3271                 BCM_IF_ERROR_RETURN(_bcm_fb2_outer_tpid_entry_delete(unit, i));
   3272             }
   3273         }
   3274     }
   3275     sal_memset(&svp_entry, 0, sizeof(source_vp_entry_t));
   3276     BCM_IF_ERROR_RETURN
   3277         (WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp_entry));
   3278 
   3279     /* Clear SOURCE_VP_2 entry */
   3280 #ifdef BCM_TRIDENT2_SUPPORT
   3281     if (soc_mem_is_valid(unit, SOURCE_VP_2m)) {
   3282         source_vp_2_entry_t svp_2_entry;
   3283 
   3284         sal_memset(&svp_2_entry, 0, sizeof(source_vp_2_entry_t));
   3285         BCM_IF_ERROR_RETURN
   3286             (WRITE_SOURCE_VP_2m(unit, MEM_BLOCK_ALL, vp, &svp_2_entry));
   3287     }
   3288 #endif /* BCM_TRIDENT2_SUPPORT */
   3289 
   3290     BCM_IF_ERROR_RETURN
   3291         (READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp_entry));
   3292     nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp_entry, NEXT_HOP_INDEXf);
   3293 
   3294     /* Clear DVP entry */
   3295     BCM_IF_ERROR_RETURN(
   3296         _bcm_vp_ing_dvp_config(unit, _bcmVpIngDvpConfigClear, vp, 
   3297                                ING_DVP_CONFIG_INVALID_VP_TYPE, 
   3298                                ING_DVP_CONFIG_INVALID_INTF_ID, 
   3299                                ING_DVP_CONFIG_INVALID_PORT_TYPE));
   3300 
   3301     if (!(NIV_PORT_INFO(unit, vp)->flags & BCM_NIV_PORT_MATCH_NONE)) {
   3302         /* Clear next hop entries and free next hop index */
   3303         BCM_IF_ERROR_RETURN
   3304             (_bcm_trident_niv_nh_info_delete(unit, nh_index));
   3305 
   3306         /* Decrement port's VP count */
   3307         BCM_IF_ERROR_RETURN
   3308             (_bcm_trident_niv_port_cnt_update(unit,
   3309                                               NIV_PORT_INFO(unit, vp)->port,
   3310                                               vp, FALSE, TRUE));
   3311     }
   3312 
   3313     /* Free VP */
   3314     BCM_IF_ERROR_RETURN
   3315         (_bcm_vp_free(unit, _bcmVpTypeNiv, 1, vp));
   3316 
   3317     /* Clear NIV VP software state */
   3318     sal_memset(NIV_PORT_INFO(unit, vp), 0, sizeof(_bcm_trident_niv_port_info_t));
   3319 
   3320     return BCM_E_NONE;
   3321 }
   3322 
   3323 /*
   3324  * Function:
   3325  *      bcm_trident_niv_port_delete_all
   3326  * Purpose:
   3327  *      Destroy all NIV virtual ports.
   3328  * Parameters:
   3329  *      unit - (IN) SOC unit number. 
   3330  * Returns:
   3331  *      BCM_X_XXX
   3332  */
   3333 int
   3334 bcm_trident_niv_port_delete_all(int unit)
   3335 {
   3336     int i;
   3337     bcm_gport_t niv_port_id;
   3338 
   3339     for (i = soc_mem_index_min(unit, SOURCE_VPm);
   3340          i <= soc_mem_index_max(unit, SOURCE_VPm);
   3341          i++) {
   3342         if (_bcm_vp_used_get(unit, i, _bcmVpTypeNiv)) {
   3343             BCM_GPORT_NIV_PORT_ID_SET(niv_port_id, i);
   3344             BCM_IF_ERROR_RETURN(bcm_trident_niv_port_delete(unit, niv_port_id));
   3345         }
   3346     }
   3347 
   3348     return BCM_E_NONE;
   3349 }
   3350 
   3351 /*
   3352  * Function:
   3353  *      bcm_trident_niv_port_get
   3354  * Purpose:
   3355  *      Get NIV virtual port info.
   3356  * Parameters:
   3357  *      unit - (IN) SOC unit number. 
   3358  *      niv_port - (IN/OUT) Pointer to NIV virtual port structure. 
   3359  * Returns:
   3360  *      BCM_X_XXX
   3361  */
   3362 int
   3363 bcm_trident_niv_port_get(int unit, bcm_niv_port_t *niv_port)
   3364 {
   3365     int vp;
   3366     source_vp_entry_t svp_entry;
   3367     int old_tpid_enable, i;
   3368     int tp_enb_length;
   3369 
   3370     if (!BCM_GPORT_IS_NIV_PORT(niv_port->niv_port_id)) {
   3371         return BCM_E_PARAM;
   3372     }
   3373 
   3374     vp = BCM_GPORT_NIV_PORT_ID_GET(niv_port->niv_port_id);
   3375     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   3376         return BCM_E_NOT_FOUND;
   3377     }
   3378 
   3379     bcm_niv_port_t_init(niv_port);
   3380     niv_port->flags = NIV_PORT_INFO(unit, vp)->flags;
   3381     BCM_GPORT_NIV_PORT_ID_SET(niv_port->niv_port_id, vp);
   3382     niv_port->port = NIV_PORT_INFO(unit, vp)->port;
   3383     niv_port->virtual_interface_id = NIV_PORT_INFO(unit, vp)->virtual_interface_id;
   3384     niv_port->match_vlan = NIV_PORT_INFO(unit, vp)->match_vlan;
   3385 
   3386     BCM_IF_ERROR_RETURN(READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp_entry));
   3387 
   3388     if (soc_mem_is_valid(unit, SVP_ATTRS_1m)) {
   3389         BCM_IF_ERROR_RETURN(_bcm_trident_niv_tpid_enb_get(unit, NULL,
   3390                             vp, &old_tpid_enable));
   3391         tp_enb_length = soc_mem_field_length(unit, SVP_ATTRS_1m,
   3392                                             TPID_ENABLEf);
   3393     } else {
   3394         BCM_IF_ERROR_RETURN(_bcm_trident_niv_tpid_enb_get(unit,
   3395                             (uint32 *)&svp_entry, vp, &old_tpid_enable));
   3396         tp_enb_length = soc_mem_field_length(unit, SOURCE_VPm,
   3397                                             TPID_ENABLEf);
   3398     }
   3399 
   3400     if (old_tpid_enable) {
   3401         for (i= 0; i < tp_enb_length; i++) {
   3402             if (old_tpid_enable & (1 << i)) {
   3403                 BCM_IF_ERROR_RETURN(_bcm_fb2_outer_tpid_entry_get(unit,
   3404                             &niv_port->match_service_tpid, i));
   3405             }
   3406         }
   3407     }
   3408     niv_port->if_class = soc_SOURCE_VPm_field32_get(unit, &svp_entry, CLASS_IDf);
   3409 
   3410     return BCM_E_NONE;
   3411 }
   3412 
   3413 /*
   3414  * Function:
   3415  *      bcm_trident_niv_port_traverse
   3416  * Purpose:
   3417  *      Traverse all NIV ports and call supplied callback routine.
   3418  * Parameters:
   3419  *      unit      - (IN) Device Number
   3420  *      cb        - (IN) User-provided callback
   3421  *      user_data - (IN/OUT) Cookie
   3422  * Returns:
   3423  *      BCM_E_XXX
   3424  */
   3425 int
   3426 bcm_trident_niv_port_traverse(int unit, bcm_niv_port_traverse_cb cb, 
   3427                                   void *user_data)
   3428 {
   3429     int i;
   3430     bcm_niv_port_t niv_port;
   3431 
   3432     for (i = soc_mem_index_min(unit, SOURCE_VPm);
   3433          i <= soc_mem_index_max(unit, SOURCE_VPm);
   3434          i++) {
   3435         if (_bcm_vp_used_get(unit, i, _bcmVpTypeNiv)) {
   3436             bcm_niv_port_t_init(&niv_port);
   3437             BCM_GPORT_NIV_PORT_ID_SET(niv_port.niv_port_id, i);
   3438             BCM_IF_ERROR_RETURN(bcm_trident_niv_port_get(unit, &niv_port));
   3439             BCM_IF_ERROR_RETURN(cb(unit, &niv_port, user_data));
   3440         }
   3441     }
   3442 
   3443     return BCM_E_NONE;
   3444 }
   3445 
   3446 /*
   3447  * Function:
   3448  *      _bcm_trident_niv_port_resolve
   3449  * Purpose:
   3450  *      Get the modid, port, trunk values for a NIV virtual port
   3451  * Parameters:
   3452  *      unit     - (IN) BCM device number
   3453  *      gport    - (IN) Global port identifier
   3454  *      modid    - (OUT) Module ID
   3455  *      port     - (OUT) Port number
   3456  *      trunk_id - (OUT) Trunk ID
   3457  *      id       - (OUT) Virtual port ID
   3458  * Returns:
   3459  *      BCM_E_XXX
   3460  */
   3461 int
   3462 _bcm_trident_niv_port_resolve(int unit, bcm_gport_t niv_port_id,
   3463                           bcm_module_t *modid, bcm_port_t *port,
   3464                           bcm_trunk_t *trunk_id, int *id)
   3465 
   3466 {
   3467     int rv = BCM_E_NONE, nh_index, vp;
   3468     ing_l3_next_hop_entry_t ing_nh;
   3469     ing_dvp_table_entry_t dvp;
   3470 
   3471     if (!BCM_GPORT_IS_NIV_PORT(niv_port_id)) {
   3472         return (BCM_E_BADID);
   3473     }
   3474 
   3475     vp = BCM_GPORT_NIV_PORT_ID_GET(niv_port_id);
   3476     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   3477         return BCM_E_NOT_FOUND;
   3478     }
   3479     BCM_IF_ERROR_RETURN(READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, &dvp));
   3480     nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp,
   3481                                               NEXT_HOP_INDEXf);
   3482     BCM_IF_ERROR_RETURN(soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   3483                                       nh_index, &ing_nh));
   3484 
   3485     if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh,
   3486             _NIV_ENTRY_TYPEf(unit, ING_L3_NEXT_HOPm)) != 0x2) {
   3487         /* Entry type is not L2 DVP */
   3488         return BCM_E_NOT_FOUND;
   3489     }
   3490 
   3491     if (soc_feature(unit, soc_feature_generic_dest)) {
   3492         uint32 dt, dv;
   3493         dv = soc_mem_field32_dest_get(unit, ING_L3_NEXT_HOPm,
   3494                 &ing_nh, DESTINATIONf, &dt);
   3495         if (dt == SOC_MEM_FIF_DEST_LAG) {
   3496             /* Trunk group */
   3497             *trunk_id = dv & SOC_MEM_FIF_DGPP_TGID_MASK;
   3498         } else {
   3499             *port = dv & SOC_MEM_FIF_DGPP_PORT_MASK;
   3500             *modid = (dv & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >>
   3501                       SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS;
   3502         }
   3503     } else {
   3504         if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) {
   3505             *trunk_id = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, TGIDf);
   3506         } else {
   3507             *modid = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, MODULE_IDf);
   3508             *port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf);
   3509         }
   3510     }
   3511     *id = vp;
   3512     return rv;
   3513 }
   3514 
   3515 /*
   3516  * Purpose:
   3517  *	Create NIV Forwarding table entry
   3518  * Parameters:
   3519  *	unit - (IN) Device Number
   3520  *	iv_fwd_entry - (IN) NIV Forwarding table entry
   3521  */
   3522 int
   3523 bcm_trident_niv_forward_add(int unit, bcm_niv_forward_t *iv_fwd_entry)
   3524 {
   3525     int rv = BCM_E_NONE;
   3526     bcm_module_t mod_out;
   3527     bcm_port_t port_out;
   3528     bcm_trunk_t tgid_out;
   3529     int id_out;
   3530     l2x_entry_t l2x_entry;
   3531 
   3532     if (iv_fwd_entry->name_space > 0xfff) {
   3533         return BCM_E_PARAM;
   3534     }
   3535 
   3536     sal_memset(&l2x_entry, 0, sizeof(l2x_entry));
   3537     if (!(iv_fwd_entry->flags & BCM_NIV_FORWARD_MULTICAST)) {
   3538         if (iv_fwd_entry->virtual_interface_id > 0xfff) {
   3539             return BCM_E_PARAM;
   3540         }
   3541 
   3542         BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit,
   3543                     iv_fwd_entry->dest_port,
   3544                     &mod_out, &port_out, &tgid_out, &id_out));
   3545         if (-1 != id_out) {
   3546             return BCM_E_PARAM;
   3547         }
   3548 
   3549         soc_L2Xm_field32_set(unit, &l2x_entry, VIF__Pf, 0);
   3550 
   3551         if (tgid_out != -1) {
   3552             BCM_IF_ERROR_RETURN(_bcm_trunk_id_validate(unit, tgid_out));
   3553             if (soc_feature(unit, soc_feature_generic_dest)) {
   3554                 soc_mem_field32_dest_set(unit, L2Xm, &l2x_entry,
   3555                     VIF__DESTINATIONf, SOC_MEM_FIF_DEST_LAG, tgid_out);
   3556             } else {
   3557                 soc_L2Xm_field32_set(unit, &l2x_entry, VIF__DEST_TYPEf, 1);
   3558                 soc_L2Xm_field32_set(unit, &l2x_entry, VIF__TGIDf, tgid_out);
   3559             }
   3560         } else {
   3561             if (soc_feature(unit, soc_feature_generic_dest)) {
   3562                 soc_mem_field32_dest_set(unit, L2Xm, &l2x_entry,
   3563                     VIF__DESTINATIONf, SOC_MEM_FIF_DEST_DGPP,
   3564                     mod_out << SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS | port_out);
   3565             } else {
   3566                 soc_L2Xm_field32_set(unit, &l2x_entry, VIF__MODULE_IDf, mod_out);
   3567                 soc_L2Xm_field32_set(unit, &l2x_entry, VIF__PORT_NUMf, port_out);
   3568             }
   3569         }
   3570     } else { /* Multicast forward entry */
   3571         if (iv_fwd_entry->virtual_interface_id > 0x3fff) {
   3572             return BCM_E_PARAM;
   3573         }
   3574         if (!_BCM_MULTICAST_IS_L2(iv_fwd_entry->dest_multicast)) {
   3575             return BCM_E_PARAM;
   3576         }
   3577 
   3578         soc_L2Xm_field32_set(unit, &l2x_entry, VIF__Pf, 1);
   3579         if (soc_feature(unit, soc_feature_generic_dest)) {
   3580             soc_mem_field32_dest_set(unit, L2Xm, &l2x_entry,
   3581                 VIF__DESTINATIONf, SOC_MEM_FIF_DEST_L2MC,
   3582                 _BCM_MULTICAST_ID_GET(iv_fwd_entry->dest_multicast));
   3583         } else {
   3584             soc_L2Xm_field32_set(unit, &l2x_entry, VIF__L2MC_PTRf,
   3585                 _BCM_MULTICAST_ID_GET(iv_fwd_entry->dest_multicast));
   3586         }
   3587     }
   3588 
   3589     if (soc_feature(unit, soc_feature_base_valid)) {
   3590         soc_L2Xm_field32_set(unit, &l2x_entry, BASE_VALIDf, 1);
   3591     } else {
   3592         soc_L2Xm_field32_set(unit, &l2x_entry, VALIDf, 1);
   3593     }
   3594     soc_L2Xm_field32_set(unit, &l2x_entry, VIF__NAMESPACEf,
   3595             iv_fwd_entry->name_space);
   3596     soc_L2Xm_field32_set(unit, &l2x_entry, VIF__DST_VIFf,
   3597             iv_fwd_entry->virtual_interface_id);
   3598 
   3599     if (SOC_IS_KATANA2(unit)) {
   3600         soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf,
   3601                 KT2_L2_HASH_KEY_TYPE_VIF);
   3602     } else {
   3603         soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf,
   3604                 TR_L2_HASH_KEY_TYPE_VIF);
   3605     }
   3606     soc_L2Xm_field32_set(unit, &l2x_entry, VIF__STATIC_BITf, 1);
   3607 
   3608     soc_mem_lock(unit, L2Xm);
   3609 
   3610     if (!(iv_fwd_entry->flags & BCM_NIV_FORWARD_REPLACE)) {
   3611         l2x_entry_t  l2x_lookup;
   3612         int          l2_index;
   3613 
   3614         /* See if the entry already exists */
   3615         rv = soc_mem_generic_lookup(unit, L2Xm, MEM_BLOCK_ANY, 0, &l2x_entry,
   3616                                     &l2x_lookup, &l2_index);
   3617         if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) {
   3618             soc_mem_unlock(unit, L2Xm);
   3619             return rv;
   3620         }
   3621         if (BCM_SUCCESS(rv)) {
   3622             soc_mem_unlock(unit, L2Xm);
   3623             return BCM_E_EXISTS;
   3624         }
   3625 
   3626         rv = soc_mem_insert(unit, L2Xm, MEM_BLOCK_ALL, &l2x_entry);
   3627         if (SOC_FAILURE(rv)) {
   3628             soc_mem_unlock(unit, L2Xm);
   3629             return rv;
   3630         }
   3631     } else { /* Replace existing entry */
   3632         rv = soc_mem_delete(unit, L2Xm, MEM_BLOCK_ALL, &l2x_entry);
   3633         if (SOC_FAILURE(rv)) {
   3634             soc_mem_unlock(unit, L2Xm);
   3635             return rv;
   3636         }
   3637         rv = soc_mem_insert(unit, L2Xm, MEM_BLOCK_ALL, &l2x_entry);
   3638         if (SOC_FAILURE(rv)) {
   3639             soc_mem_unlock(unit, L2Xm);
   3640             return rv;
   3641         }
   3642     }
   3643 
   3644     soc_mem_unlock(unit, L2Xm);
   3645 
   3646     return rv;
   3647 }
   3648 
   3649 /*
   3650  * Purpose:
   3651  *	Delete NIV Forwarding table entry
   3652  * Parameters:
   3653  *      unit - (IN) Device Number
   3654  *      iv_fwd_entry - (IN) NIV Forwarding table entry
   3655  */
   3656 int
   3657 bcm_trident_niv_forward_delete(int unit, bcm_niv_forward_t *iv_fwd_entry)
   3658 {
   3659     int rv = BCM_E_NONE;
   3660     l2x_entry_t l2x_entry;
   3661 
   3662     if (iv_fwd_entry->name_space > 0xfff) {
   3663         return BCM_E_PARAM;
   3664     }
   3665     
   3666     sal_memset(&l2x_entry, 0, sizeof(l2x_entry));
   3667     if (!(iv_fwd_entry->flags & BCM_NIV_FORWARD_MULTICAST)) {
   3668         if (iv_fwd_entry->virtual_interface_id > 0xfff) {
   3669             return BCM_E_PARAM;
   3670         }
   3671         soc_L2Xm_field32_set(unit, &l2x_entry, VIF__Pf, 0);
   3672 
   3673     } else { /* Multicast forward entry */
   3674         if (iv_fwd_entry->virtual_interface_id > 0x3fff) {
   3675             return BCM_E_PARAM;
   3676         }
   3677         soc_L2Xm_field32_set(unit, &l2x_entry, VIF__Pf, 1);
   3678     }
   3679 
   3680     soc_L2Xm_field32_set(unit, &l2x_entry, VIF__NAMESPACEf,
   3681             iv_fwd_entry->name_space);
   3682 
   3683     soc_L2Xm_field32_set(unit, &l2x_entry, VIF__DST_VIFf,
   3684             iv_fwd_entry->virtual_interface_id);
   3685     if (SOC_IS_KATANA2(unit)) {
   3686         soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf,
   3687                 KT2_L2_HASH_KEY_TYPE_VIF);
   3688     } else {
   3689         soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf,
   3690                 TR_L2_HASH_KEY_TYPE_VIF);
   3691     }
   3692 
   3693     soc_mem_lock(unit, L2Xm);
   3694     rv = soc_mem_delete(unit, L2Xm, MEM_BLOCK_ALL, &l2x_entry);
   3695     soc_mem_unlock(unit, L2Xm);
   3696 
   3697     return rv;
   3698 }
   3699 
   3700 /*
   3701  * Purpose:
   3702  *	Delete all NIV Forwarding table entries
   3703  * Parameters:
   3704  *	unit - Device Number
   3705  */
   3706 int
   3707 bcm_trident_niv_forward_delete_all(int unit)
   3708 {
   3709     int rv = BCM_E_NONE;
   3710     int field_len;
   3711 
   3712 #ifdef BCM_TOMAHAWK_SUPPORT
   3713     if (soc_feature(unit, soc_feature_l2_bulk_unified_table)) {
   3714         l2_bulk_entry_t match_mask;
   3715         l2_bulk_entry_t match_data;
   3716         soc_field_t vld_f = VALIDf;
   3717 
   3718         if (soc_feature(unit, soc_feature_base_valid)) {
   3719             vld_f = BASE_VALIDf;
   3720         }
   3721 
   3722         sal_memset(&match_mask, 0, sizeof(match_mask));
   3723         sal_memset(&match_data, 0, sizeof(match_data));
   3724 
   3725         soc_mem_field32_set(unit, L2_BULKm, &match_mask, vld_f, 1);
   3726         soc_mem_field32_set(unit, L2_BULKm, &match_data, vld_f, 1);
   3727 
   3728         field_len = soc_mem_field_length(unit, L2_BULKm, KEY_TYPEf);
   3729         soc_mem_field32_set(unit, L2_BULKm, &match_mask, KEY_TYPEf,
   3730                             (1 << field_len) - 1);
   3731    
   3732         if (SOC_IS_KATANA2(unit)) {
   3733             soc_mem_field32_set(unit, L2_BULKm, &match_data, KEY_TYPEf,
   3734                     KT2_L2_HASH_KEY_TYPE_VIF);
   3735         } else {
   3736             soc_mem_field32_set(unit, L2_BULKm, &match_data, KEY_TYPEf,
   3737                     TR_L2_HASH_KEY_TYPE_VIF);
   3738         }
   3739 
   3740         soc_mem_lock(unit, L2Xm);
   3741         rv = WRITE_L2_BULKm(unit, MEM_BLOCK_ALL, _BCM_L2_BULK_MATCH_MASK_INX,
   3742                             &match_mask);
   3743         if (BCM_SUCCESS(rv)) {
   3744             rv = WRITE_L2_BULKm(unit, MEM_BLOCK_ALL, _BCM_L2_BULK_MATCH_DATA_INX,
   3745                                 &match_data);
   3746         }
   3747         if (BCM_SUCCESS(rv)) {
   3748             rv = soc_reg_field32_modify(unit, L2_BULK_CONTROLr, REG_PORT_ANY,
   3749                                         ACTIONf, 1);
   3750         }
   3751         if (BCM_SUCCESS(rv)) {
   3752             rv = soc_reg_field32_modify(unit, L2_BULK_CONTROLr, REG_PORT_ANY,
   3753                                     NUM_ENTRIESf, soc_mem_index_count(unit, L2Xm));
   3754         }
   3755     } else
   3756 #endif /* BCM_TOMAHAWK_SUPPORT */
   3757     {
   3758         l2_bulk_match_mask_entry_t match_mask;
   3759         l2_bulk_match_data_entry_t match_data;
   3760 
   3761         sal_memset(&match_mask, 0, sizeof(match_mask));
   3762         sal_memset(&match_data, 0, sizeof(match_data));
   3763 
   3764         soc_mem_field32_set(unit, L2_BULK_MATCH_MASKm, &match_mask, VALIDf, 1);
   3765         soc_mem_field32_set(unit, L2_BULK_MATCH_DATAm, &match_data, VALIDf, 1);
   3766 
   3767         field_len = soc_mem_field_length(unit, L2_BULK_MATCH_MASKm, KEY_TYPEf);
   3768         soc_mem_field32_set(unit, L2_BULK_MATCH_MASKm, &match_mask, KEY_TYPEf,
   3769                 (1 << field_len) - 1);
   3770 
   3771         if (SOC_IS_KATANA2(unit)) {
   3772             soc_mem_field32_set(unit, L2_BULK_MATCH_DATAm, &match_data, KEY_TYPEf,
   3773                     KT2_L2_HASH_KEY_TYPE_VIF);
   3774         } else {
   3775             soc_mem_field32_set(unit, L2_BULK_MATCH_DATAm, &match_data, KEY_TYPEf,
   3776                     TR_L2_HASH_KEY_TYPE_VIF);
   3777         }
   3778 
   3779         soc_mem_lock(unit, L2Xm);
   3780         rv = WRITE_L2_BULK_MATCH_MASKm(unit, MEM_BLOCK_ALL, 0,
   3781                 &match_mask);
   3782         if (BCM_SUCCESS(rv)) {
   3783             rv = WRITE_L2_BULK_MATCH_DATAm(unit, MEM_BLOCK_ALL, 0,
   3784                     &match_data);
   3785         }
   3786         if (BCM_SUCCESS(rv)) {
   3787             rv = soc_reg_field32_modify(unit, L2_BULK_CONTROLr, REG_PORT_ANY,
   3788                     ACTIONf, 1);
   3789         }
   3790     }
   3791     if (BCM_SUCCESS(rv)) {
   3792         rv = soc_l2x_port_age(unit, L2_BULK_CONTROLr, INVALIDr);
   3793     }
   3794     soc_mem_unlock(unit, L2Xm);
   3795 
   3796     return rv;
   3797 }
   3798 
   3799 /*
   3800  * Purpose:
   3801  *      Get NIV Forwarding table entry
   3802  * Parameters:
   3803  *      unit - (IN) Device Number
   3804  *      iv_fwd_entry - (IN/OUT) NIV forwarding table info
   3805  */
   3806 int
   3807 bcm_trident_niv_forward_get(int unit, bcm_niv_forward_t *iv_fwd_entry)
   3808 {
   3809     int rv = BCM_E_NONE;
   3810     l2x_entry_t l2x_entry, l2x_entry_out;
   3811     int idx;
   3812     _bcm_gport_dest_t dest;
   3813     int l2mc_index;
   3814 
   3815     if (iv_fwd_entry->name_space > 0xfff) {
   3816         return BCM_E_PARAM;
   3817     }
   3818     sal_memset(&l2x_entry, 0, sizeof(l2x_entry));
   3819 
   3820     if (!(iv_fwd_entry->flags & BCM_NIV_FORWARD_MULTICAST)) {
   3821         if (iv_fwd_entry->virtual_interface_id > 0xfff) {
   3822             return BCM_E_PARAM;
   3823         }
   3824 
   3825         soc_L2Xm_field32_set(unit, &l2x_entry, VIF__Pf, 0);
   3826 
   3827     } else { /* Multicast forward entry */
   3828         if (iv_fwd_entry->virtual_interface_id > 0x3fff) {
   3829             return BCM_E_PARAM;
   3830         }
   3831         soc_L2Xm_field32_set(unit, &l2x_entry, VIF__Pf, 1);
   3832     }
   3833 
   3834     if (SOC_IS_KATANA2(unit)) {
   3835         soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf,
   3836                 KT2_L2_HASH_KEY_TYPE_VIF);
   3837     } else {
   3838         soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf,
   3839                 TR_L2_HASH_KEY_TYPE_VIF);
   3840     }
   3841     soc_L2Xm_field32_set(unit, &l2x_entry, VIF__NAMESPACEf,
   3842             iv_fwd_entry->name_space);
   3843     soc_L2Xm_field32_set(unit, &l2x_entry, VIF__DST_VIFf,
   3844             iv_fwd_entry->virtual_interface_id);
   3845 
   3846     soc_mem_lock(unit, L2Xm);
   3847     rv = soc_mem_search(unit, L2Xm, MEM_BLOCK_ALL, &idx, &l2x_entry,
   3848             &l2x_entry_out, 0);
   3849     soc_mem_unlock(unit, L2Xm);
   3850 
   3851     if (SOC_SUCCESS(rv)) {
   3852         uint32 dv, dt = SOC_MEM_FIF_DEST_INVALID;
   3853         if (!(iv_fwd_entry->flags & BCM_NIV_FORWARD_MULTICAST)) {
   3854             if (soc_feature(unit, soc_feature_generic_dest)) {
   3855                 dv = soc_mem_field32_dest_get(unit, L2Xm, &l2x_entry_out,
   3856                                               VIF__DESTINATIONf, &dt);
   3857                 if (dt == SOC_MEM_FIF_DEST_LAG) {
   3858                     dest.tgid = dv;
   3859                     dest.gport_type = _SHR_GPORT_TYPE_TRUNK;
   3860                 } else {
   3861                     dest.port = dv & SOC_MEM_FIF_DGPP_PORT_MASK;
   3862                     dest.modid = (dv & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >>
   3863                                     SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS;
   3864                     dest.gport_type = _SHR_GPORT_TYPE_MODPORT;
   3865                 }
   3866             } else {
   3867                 if (soc_L2Xm_field32_get(unit, &l2x_entry_out, VIF__DEST_TYPEf)) {
   3868                     dest.tgid = soc_L2Xm_field32_get(unit, &l2x_entry_out,
   3869                         VIF__TGIDf);
   3870                     dest.gport_type = _SHR_GPORT_TYPE_TRUNK;
   3871                 } else {
   3872                     dest.modid = soc_L2Xm_field32_get(unit, &l2x_entry_out,
   3873                             VIF__MODULE_IDf);
   3874                     dest.port = soc_L2Xm_field32_get(unit, &l2x_entry_out,
   3875                             VIF__PORT_NUMf);
   3876                     dest.gport_type = _SHR_GPORT_TYPE_MODPORT;
   3877                 }
   3878             }
   3879             BCM_IF_ERROR_RETURN(_bcm_esw_gport_construct(unit, &dest,
   3880                         &(iv_fwd_entry->dest_port)));
   3881         } else {
   3882             if (soc_feature(unit, soc_feature_generic_dest)) {
   3883                 dv = soc_mem_field32_dest_get(unit, L2Xm, &l2x_entry_out,
   3884                                               VIF__DESTINATIONf, &dt);
   3885                 l2mc_index = (dt == SOC_MEM_FIF_DEST_L2MC) ? dv : 0;
   3886             } else {
   3887                 l2mc_index = soc_L2Xm_field32_get(unit, &l2x_entry_out,
   3888                                                   VIF__L2MC_PTRf);
   3889             }
   3890             _BCM_MULTICAST_GROUP_SET(iv_fwd_entry->dest_multicast,
   3891                     _BCM_MULTICAST_TYPE_L2, l2mc_index);
   3892         }
   3893     }
   3894 
   3895     return rv;
   3896 }
   3897 
   3898 /*
   3899  * Purpose:
   3900  *      Traverse all valid NIV forward entries and call the
   3901  *      supplied callback routine.
   3902  * Parameters:
   3903  *      unit      - Device Number
   3904  *      cb        - User callback function, called once per NIV forward entry.
   3905  *      user_data - cookie
   3906  * Returns:
   3907  *      BCM_E_XXX
   3908  */
   3909 int
   3910 bcm_trident_niv_forward_traverse(int unit,
   3911                              bcm_niv_forward_traverse_cb cb,
   3912                              void *user_data)
   3913 {
   3914     int rv = BCM_E_NONE;
   3915     int chunk_entries, chunk_bytes;
   3916     uint8 *l2_tbl_chunk = NULL;
   3917     int chunk_idx_min, chunk_idx_max, chunk_end;
   3918     int ent_idx, mem_idx_min, mem_idx_max;
   3919     l2x_entry_t *l2x_entry;
   3920     bcm_niv_forward_t iv_fwd_entry;
   3921     int l2mc_index;
   3922     _bcm_gport_dest_t dest;
   3923     uint32 dv, dt = SOC_MEM_FIF_DEST_INVALID;
   3924 
   3925     chunk_entries = soc_property_get(unit, spn_L2DELETE_CHUNKS,
   3926                                  L2_MEM_CHUNKS_DEFAULT);
   3927     chunk_bytes = 4 * SOC_MEM_WORDS(unit, L2Xm) * chunk_entries;
   3928     l2_tbl_chunk = soc_cm_salloc(unit, chunk_bytes, "niv forward traverse");
   3929     if (NULL == l2_tbl_chunk) {
   3930         return BCM_E_MEMORY;
   3931     }
   3932 
   3933     mem_idx_min = soc_mem_index_min(unit, L2Xm);
   3934     mem_idx_max = soc_mem_index_max(unit, L2Xm);
   3935     for (chunk_idx_min = mem_idx_min; chunk_idx_min <= mem_idx_max; 
   3936          chunk_idx_min += chunk_entries) {
   3937         sal_memset(l2_tbl_chunk, 0, chunk_bytes);
   3938 
   3939         chunk_idx_max = chunk_idx_min + chunk_entries - 1;
   3940         if (chunk_idx_max > mem_idx_max) {
   3941             chunk_idx_max = mem_idx_max;
   3942         }
   3943 
   3944         rv = soc_mem_read_range(unit, L2Xm, MEM_BLOCK_ANY,
   3945                                 chunk_idx_min, chunk_idx_max, l2_tbl_chunk);
   3946         if (SOC_FAILURE(rv)) {
   3947             break;
   3948         }
   3949 
   3950         chunk_end = (chunk_idx_max - chunk_idx_min);
   3951         for (ent_idx = 0; ent_idx <= chunk_end; ent_idx++) {
   3952             l2x_entry = soc_mem_table_idx_to_pointer(unit, L2Xm, l2x_entry_t *, 
   3953                                              l2_tbl_chunk, ent_idx);
   3954 
   3955             if (soc_L2Xm_field32_get(unit, l2x_entry,
   3956                     (soc_feature(unit, soc_feature_base_valid) ?
   3957                     BASE_VALIDf : VALIDf)) == 0) {
   3958                 continue;
   3959             }
   3960             if (SOC_IS_KATANA2(unit)) {
   3961                 if (soc_L2Xm_field32_get(unit, l2x_entry, KEY_TYPEf) != 
   3962                         KT2_L2_HASH_KEY_TYPE_VIF) {
   3963                     continue;
   3964                 }
   3965             } else {
   3966                 if (soc_L2Xm_field32_get(unit, l2x_entry, KEY_TYPEf) != 
   3967                         TR_L2_HASH_KEY_TYPE_VIF) {
   3968                     continue;
   3969                 }
   3970             }
   3971             bcm_niv_forward_t_init(&iv_fwd_entry);
   3972 
   3973             iv_fwd_entry.name_space = soc_L2Xm_field32_get(unit, l2x_entry,
   3974                     VIF__NAMESPACEf);
   3975             iv_fwd_entry.virtual_interface_id = soc_L2Xm_field32_get(unit,
   3976                     l2x_entry, VIF__DST_VIFf);
   3977 
   3978             if (soc_L2Xm_field32_get(unit, l2x_entry, VIF__Pf)) {
   3979                 /* Multicast NIV forward entry */
   3980                 iv_fwd_entry.flags |= BCM_NIV_FORWARD_MULTICAST;
   3981                 if (soc_feature(unit, soc_feature_generic_dest)) {
   3982                     dv = soc_mem_field32_dest_get(unit, L2Xm, l2x_entry,
   3983                                                   VIF__DESTINATIONf, &dt);
   3984                     l2mc_index = (dt == SOC_MEM_FIF_DEST_L2MC) ? dv : 0;
   3985                 } else {
   3986                     l2mc_index = soc_L2Xm_field32_get(unit, l2x_entry,
   3987                             VIF__L2MC_PTRf);
   3988                 }
   3989                 _BCM_MULTICAST_GROUP_SET(iv_fwd_entry.dest_multicast,
   3990                         _BCM_MULTICAST_TYPE_L2, l2mc_index);
   3991             } else {
   3992                 if (soc_feature(unit, soc_feature_generic_dest)) {
   3993                     dv = soc_mem_field32_dest_get(unit, L2Xm, l2x_entry,
   3994                                                   VIF__DESTINATIONf, &dt);
   3995                     if (dt == SOC_MEM_FIF_DEST_LAG) {
   3996                         dest.tgid = dv;
   3997                         dest.gport_type = _SHR_GPORT_TYPE_TRUNK;
   3998                     } else {
   3999                         dest.port = dv & SOC_MEM_FIF_DGPP_PORT_MASK;
   4000                         dest.modid = (dv & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >>
   4001                                         SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS;
   4002                         dest.gport_type = _SHR_GPORT_TYPE_MODPORT;
   4003                     }
   4004                 } else {
   4005                     if (soc_L2Xm_field32_get(unit, l2x_entry, VIF__DEST_TYPEf)) {
   4006                         dest.tgid = soc_L2Xm_field32_get(unit, l2x_entry,
   4007                                 VIF__TGIDf);
   4008                         dest.gport_type = _SHR_GPORT_TYPE_TRUNK;
   4009                     } else {
   4010                         dest.modid = soc_L2Xm_field32_get(unit, l2x_entry,
   4011                                 VIF__MODULE_IDf);
   4012                         dest.port = soc_L2Xm_field32_get(unit, l2x_entry,
   4013                                 VIF__PORT_NUMf);
   4014                         dest.gport_type = _SHR_GPORT_TYPE_MODPORT;
   4015                     }
   4016                 }
   4017                 rv = _bcm_esw_gport_construct(unit, &dest,
   4018                         &(iv_fwd_entry.dest_port));
   4019                 if (BCM_FAILURE(rv)) {
   4020                     break;
   4021                 }
   4022             }
   4023 
   4024             rv = cb(unit, &iv_fwd_entry, user_data);
   4025             if (BCM_FAILURE(rv)) {
   4026                 break;
   4027             }
   4028         }
   4029         if (BCM_FAILURE(rv)) {
   4030             break;
   4031         }
   4032     }
   4033     soc_cm_sfree(unit, l2_tbl_chunk);
   4034 
   4035     return rv;
   4036 }
   4037 
   4038 /*
   4039  * Function:
   4040  *      bcm_trident_niv_ethertype_set
   4041  * Purpose:
   4042  *      Set NIV Ethertype.
   4043  * Parameters:
   4044  *      unit      - (IN) BCM device number
   4045  *      ethertype - (IN) NIV Ethertype
   4046  * Returns:
   4047  *      BCM_E_XXX
   4048  */
   4049 int
   4050 bcm_trident_niv_ethertype_set(int unit, int ethertype)
   4051 {
   4052     if (ethertype < 0 || ethertype > 0xffff) {
   4053         return BCM_E_PARAM;
   4054     }
   4055 
   4056 #ifdef BCM_TRIDENT3_SUPPORT
   4057     if (SOC_IS_TRIDENT3X(unit)) {
   4058         if (SOC_REG_FIELD_VALID(unit, NIV_ETHERTYPEr, ETHERTYPEf)) {
   4059             BCM_IF_ERROR_RETURN
   4060                 (soc_reg_field32_modify(unit, NIV_ETHERTYPEr,
   4061                                     REG_PORT_ANY, ETHERTYPEf, ethertype));
   4062             BCM_IF_ERROR_RETURN
   4063                 (soc_reg_field32_modify(unit, NIV_ETHERTYPEr,
   4064                                     REG_PORT_ANY, ENABLEf, ethertype ? 1 : 0));
   4065         }
   4066         if (SOC_REG_FIELD_VALID(unit, EGR_NIV_ETHERTYPE_2r, ETHERTYPEf)) {
   4067             BCM_IF_ERROR_RETURN
   4068                 (soc_reg_field32_modify(unit, EGR_NIV_ETHERTYPE_2r,
   4069                                     REG_PORT_ANY, ETHERTYPEf, ethertype));
   4070             BCM_IF_ERROR_RETURN
   4071                 (soc_reg_field32_modify(unit, EGR_NIV_ETHERTYPE_2r,
   4072                                     REG_PORT_ANY, ENABLEf, ethertype ? 1 : 0));
   4073         }
   4074         soc_td3_rx_etype_niv[unit] = ethertype;
   4075     } else
   4076 #endif
   4077     {
   4078         BCM_IF_ERROR_RETURN
   4079             (soc_reg_field32_modify(unit, NIV_ETHERTYPEr,
   4080                                     REG_PORT_ANY, ETHERTYPEf, ethertype));
   4081         BCM_IF_ERROR_RETURN
   4082             (soc_reg_field32_modify(unit, NIV_ETHERTYPEr,
   4083                                     REG_PORT_ANY, ENABLEf, ethertype ? 1 : 0));
   4084         BCM_IF_ERROR_RETURN
   4085             (soc_reg_field32_modify(unit, EGR_NIV_ETHERTYPEr,
   4086                                     REG_PORT_ANY, ETHERTYPEf, ethertype));
   4087         BCM_IF_ERROR_RETURN
   4088             (soc_reg_field32_modify(unit, EGR_NIV_ETHERTYPEr,
   4089                                     REG_PORT_ANY, ENABLEf, ethertype ? 1 : 0));
   4090         BCM_IF_ERROR_RETURN
   4091             (soc_reg_field32_modify(unit, EGR_NIV_ETHERTYPE_2r,
   4092                                     REG_PORT_ANY, ETHERTYPEf, ethertype));
   4093         BCM_IF_ERROR_RETURN
   4094             (soc_reg_field32_modify(unit, EGR_NIV_ETHERTYPE_2r,
   4095                                     REG_PORT_ANY, ENABLEf, ethertype ? 1 : 0));
   4096     }
   4097 
   4098     return BCM_E_NONE;
   4099 }
   4100 
   4101 /*
   4102  * Function:
   4103  *      bcm_trident_niv_ethertype_get
   4104  * Purpose:
   4105  *      Get NIV Ethertype.
   4106  * Parameters:
   4107  *      unit      - (IN) BCM device number
   4108  *      ethertype - (OUT) NIV Ethertype
   4109  * Returns:
   4110  *      BCM_E_XXX
   4111  */
   4112 int
   4113 bcm_trident_niv_ethertype_get(int unit, int *ethertype)
   4114 {
   4115     uint32 rval;
   4116     soc_reg_t reg;
   4117 
   4118     if (ethertype == NULL) {
   4119         return BCM_E_PARAM;
   4120     }
   4121 
   4122     reg = NIV_ETHERTYPEr;
   4123 
   4124     BCM_IF_ERROR_RETURN(soc_reg32_get(unit, reg, REG_PORT_ANY, 0, &rval));
   4125     if (soc_reg_field_get(unit, reg, rval, ENABLEf)) {
   4126         *ethertype = soc_reg_field_get(unit, reg, rval, ETHERTYPEf);
   4127     } else {
   4128         *ethertype = 0;
   4129     }
   4130 
   4131     return BCM_E_NONE;
   4132 }
   4133 
   4134 /*
   4135  * Function:
   4136  *      bcm_trident_niv_untagged_add
   4137  * Purpose:
   4138  *      Set NIV VP tagging/untagging status by adding
   4139  *      a (NIV VP, VLAN) egress VLAN translation entry.
   4140  * Parameters:
   4141  *      unit - (IN) SOC unit number. 
   4142  *      vlan - (IN) VLAN ID. 
   4143  *      vp   - (IN) Virtual port number.
   4144  *      flags - (IN) Untagging indication.
   4145  *      egr_vt_added - (OUT) Indicates if (VP, VLAN) added to egress VLAN
   4146  *                           translation table.
   4147  * Returns:
   4148  *      BCM_X_XXX
   4149  */
   4150 int
   4151 bcm_trident_niv_untagged_add(int unit, bcm_vlan_t vlan, int vp, int flags,
   4152         int *egr_vt_added)
   4153 {
   4154     uint32 vent[SOC_MAX_MEM_FIELD_WORDS];
   4155     uint32 old_vent[SOC_MAX_MEM_FIELD_WORDS];
   4156     bcm_vlan_action_set_t action;
   4157     uint32 profile_idx;
   4158     int rv = BCM_E_NONE;
   4159     bcm_vlan_t    match_vlan;
   4160     soc_mem_t evx_mem = EGR_VLAN_XLATEm;
   4161 
   4162     if (soc_mem_is_valid(unit, EGR_VLAN_XLATE_1_DOUBLEm)) {
   4163         evx_mem = EGR_VLAN_XLATE_1_DOUBLEm;
   4164     }
   4165 
   4166     *egr_vt_added = FALSE;
   4167     _bcm_trident_niv_match_info_get(unit, vp, NULL, &match_vlan, NULL);
   4168 
   4169     sal_memset(vent, 0, sizeof(vent));
   4170     if (evx_mem == EGR_VLAN_XLATE_1_DOUBLEm) {
   4171         soc_mem_field32_set(unit, evx_mem, vent, BASE_VALID_0f, 3);
   4172         soc_mem_field32_set(unit, evx_mem, vent, BASE_VALID_1f, 7);
   4173         soc_mem_field32_set(unit, evx_mem, vent, DATA_TYPEf, 1);
   4174         soc_mem_field32_set(unit, evx_mem, vent, KEY_TYPEf, 1);
   4175     } else {
   4176         soc_mem_field32_set(unit, evx_mem, vent, VALIDf, 1);
   4177         if (soc_mem_field_valid(unit, evx_mem, ENTRY_TYPEf)) {
   4178             soc_mem_field32_set(unit, evx_mem, vent, ENTRY_TYPEf, 1);
   4179         } else if (soc_mem_field_valid(unit, evx_mem, KEY_TYPEf)) {
   4180             soc_mem_field32_set(unit, evx_mem, vent, KEY_TYPEf, 1);
   4181         }
   4182     }
   4183 
   4184     soc_mem_field32_set(unit, evx_mem, vent, DVPf, vp);
   4185     soc_mem_field32_set(unit, evx_mem, vent, OVIDf, vlan);
   4186 
   4187     if (!BCM_VLAN_VALID(match_vlan)) {
   4188         if (!(flags & BCM_VLAN_PORT_UNTAGGED)) {
   4189             /* No need to insert an egress vlan translation entry
   4190              * to remove the outer tag.
   4191              */
   4192             return BCM_E_NONE;
   4193         }
   4194 
   4195 #ifdef BCM_TRIDENT2_SUPPORT
   4196         if (soc_mem_field_valid(unit, EGR_VP_VLAN_MEMBERSHIPm, UNTAGf)) {
   4197             if (flags & BCM_VLAN_GPORT_ADD_VP_VLAN_MEMBERSHIP) {
   4198                 /* The UNTAG field of EGR_VP_VLAN_MEMBERSHIP table will
   4199                  * be configured with untagging status. It would be redundant
   4200                  * to insert an egress VLAN translation entry.
   4201                  */
   4202                 return BCM_E_NONE;
   4203             }
   4204         } 
   4205 #endif /* BCM_TRIDENT2_SUPPORT */
   4206 
   4207         bcm_vlan_action_set_t_init(&action);
   4208         action.dt_outer = bcmVlanActionDelete;
   4209         action.ot_outer = bcmVlanActionDelete;
   4210     } else {
   4211         /* NIV port's match_vlan is valid. It needs to be inserted
   4212          * into the packet using an egress vlan translation entry.
   4213          */
   4214         soc_mem_field32_set(unit, evx_mem, vent, NEW_OVIDf, match_vlan);
   4215         bcm_vlan_action_set_t_init(&action);
   4216         action.dt_outer = bcmVlanActionReplace;
   4217         action.ot_outer = bcmVlanActionReplace;
   4218         if (flags & BCM_VLAN_PORT_UNTAGGED) {
   4219             action.dt_inner = bcmVlanActionNone;
   4220             action.ot_inner = bcmVlanActionNone;
   4221         } else {
   4222             action.dt_inner = bcmVlanActionCopy;
   4223             action.ot_inner = bcmVlanActionCopy;
   4224         }
   4225     }
   4226     BCM_IF_ERROR_RETURN
   4227         (_bcm_trx_egr_vlan_action_profile_entry_add(unit, &action, &profile_idx));
   4228     soc_mem_field32_set(unit, evx_mem, vent, TAG_ACTION_PROFILE_PTRf,
   4229             profile_idx);
   4230 
   4231     rv = soc_mem_insert_return_old(unit, evx_mem, MEM_BLOCK_ALL,
   4232                                    vent, old_vent);
   4233     if (rv == SOC_E_EXISTS) {
   4234         /* Delete the old vlan translate profile entry */
   4235         profile_idx = soc_mem_field32_get(unit, evx_mem, old_vent,
   4236                                           TAG_ACTION_PROFILE_PTRf);
   4237         rv = _bcm_trx_egr_vlan_action_profile_entry_delete(unit, profile_idx);
   4238     }
   4239 
   4240     *egr_vt_added = TRUE;
   4241 
   4242     return rv;
   4243 }
   4244 
   4245 /*
   4246  * Function:
   4247  *      bcm_trident_niv_untagged_delete
   4248  * Purpose:
   4249  *      Delete (NIV VP, VLAN) egress VLAN translation entry.
   4250  * Parameters:
   4251  *      unit - (IN) SOC unit number. 
   4252  *      vlan - (IN) VLAN ID. 
   4253  *      vp   - (IN) Virtual port number.
   4254  * Returns:
   4255  *      BCM_X_XXX
   4256  */
   4257 int
   4258 bcm_trident_niv_untagged_delete(int unit, bcm_vlan_t vlan, int vp)
   4259 {
   4260     uint32 vent[SOC_MAX_MEM_FIELD_WORDS];
   4261     uint32 old_vent[SOC_MAX_MEM_FIELD_WORDS];
   4262     uint32 profile_idx;
   4263     int rv;
   4264     soc_mem_t evx_mem = EGR_VLAN_XLATEm;
   4265 
   4266     if (soc_mem_is_valid(unit, EGR_VLAN_XLATE_1_DOUBLEm)) {
   4267         evx_mem = EGR_VLAN_XLATE_1_DOUBLEm;
   4268     }
   4269 
   4270     sal_memset(vent, 0, sizeof(vent));
   4271     if (evx_mem == EGR_VLAN_XLATE_1_DOUBLEm) {
   4272         soc_mem_field32_set(unit, evx_mem, vent, DATA_TYPEf, 1);
   4273         soc_mem_field32_set(unit, evx_mem, vent, KEY_TYPEf, 1);
   4274     } else {
   4275         if (soc_mem_field_valid(unit, evx_mem, ENTRY_TYPEf)) {
   4276             soc_mem_field32_set(unit, evx_mem, vent, ENTRY_TYPEf, 1);
   4277         } else if (soc_mem_field_valid(unit, evx_mem, KEY_TYPEf)) {
   4278             soc_mem_field32_set(unit, evx_mem, vent, KEY_TYPEf, 1);
   4279         }
   4280     }
   4281     soc_mem_field32_set(unit, evx_mem, vent, DVPf, vp);
   4282     soc_mem_field32_set(unit, evx_mem, vent, OVIDf, vlan);
   4283 
   4284     if (soc_feature(unit, soc_feature_base_valid)) {
   4285         soc_mem_field32_set(unit, evx_mem, vent, BASE_VALID_0f, 3);
   4286         soc_mem_field32_set(unit, evx_mem, vent, BASE_VALID_1f, 7);
   4287     }
   4288 
   4289     rv = soc_mem_delete_return_old(unit, evx_mem, MEM_BLOCK_ALL,
   4290                                    vent, old_vent);
   4291     if (rv == SOC_E_NONE) {
   4292         int vld;
   4293         if (soc_feature(unit, soc_feature_base_valid)) {
   4294             vld = soc_mem_field32_get(unit, evx_mem, old_vent,
   4295                                       BASE_VALID_0f) == 3 &&
   4296                   soc_mem_field32_get(unit, evx_mem, old_vent,
   4297                                       BASE_VALID_1f) == 7;
   4298         } else {
   4299             vld = soc_mem_field32_get(unit, evx_mem, old_vent, VALIDf);
   4300         }
   4301         if (vld) {
   4302             /* Delete the old vlan translate profile entry */
   4303             profile_idx = soc_mem_field32_get(unit, evx_mem, old_vent,
   4304                                               TAG_ACTION_PROFILE_PTRf);
   4305             rv = _bcm_trx_egr_vlan_action_profile_entry_delete(unit, profile_idx);
   4306         }
   4307     }
   4308 
   4309     return rv;
   4310 }
   4311 
   4312 /*
   4313  * Function:
   4314  *      bcm_trident_niv_untagged_get
   4315  * Purpose:
   4316  *      Get tagging/untagging status of a NIV virtual port by
   4317  *      reading the (NIV VP, VLAN) egress vlan translation entry.
   4318  * Parameters:
   4319  *      unit - (IN) SOC unit number. 
   4320  *      vlan - (IN) VLAN to remove virtual port from.
   4321  *      vp   - (IN) Virtual port number.
   4322  *      flags - (OUT) Untagging status of the NIV virtual port.
   4323  * Returns:
   4324  *      BCM_E_XXX
   4325  */
   4326 int
   4327 bcm_trident_niv_untagged_get(int unit, bcm_vlan_t vlan, int vp,
   4328                                   int *flags)
   4329 {
   4330     uint32 vent[SOC_MAX_MEM_FIELD_WORDS];
   4331     uint32 res_vent[SOC_MAX_MEM_FIELD_WORDS];
   4332     int idx;
   4333     uint32 profile_idx;
   4334     int rv;
   4335     bcm_vlan_action_set_t action;
   4336     bcm_vlan_t    match_vlan;
   4337     soc_mem_t evx_mem = EGR_VLAN_XLATEm;
   4338 
   4339     if (soc_mem_is_valid(unit, EGR_VLAN_XLATE_1_DOUBLEm)) {
   4340         evx_mem = EGR_VLAN_XLATE_1_DOUBLEm;
   4341     }
   4342 
   4343     *flags = 0;
   4344     _bcm_trident_niv_match_info_get(unit, vp, NULL, &match_vlan, NULL);
   4345 
   4346     sal_memset(vent, 0, sizeof(vent));
   4347     if (evx_mem == EGR_VLAN_XLATE_1_DOUBLEm) {
   4348         soc_mem_field32_set(unit, evx_mem, vent, DATA_TYPEf, 1);
   4349         soc_mem_field32_set(unit, evx_mem, vent, KEY_TYPEf, 1);
   4350     } else {
   4351         if (soc_mem_field_valid(unit, evx_mem, ENTRY_TYPEf)) {
   4352             soc_mem_field32_set(unit, evx_mem, vent, ENTRY_TYPEf, 1);
   4353         } else if (soc_mem_field_valid(unit, evx_mem, KEY_TYPEf)) {
   4354             soc_mem_field32_set(unit, evx_mem, vent, KEY_TYPEf, 1);
   4355         }
   4356     }
   4357 
   4358     soc_mem_field32_set(unit, evx_mem, vent, DVPf, vp);
   4359     soc_mem_field32_set(unit, evx_mem, vent, OVIDf, vlan);
   4360 
   4361     rv = soc_mem_search(unit, evx_mem, MEM_BLOCK_ALL, &idx,
   4362                         vent, res_vent, 0);
   4363     if (rv == SOC_E_NONE) {
   4364         int vld;
   4365         if (soc_feature(unit, soc_feature_base_valid)) {
   4366             vld = soc_mem_field32_get(unit, evx_mem, res_vent,
   4367                                       BASE_VALID_0f) == 3 &&
   4368                   soc_mem_field32_get(unit, evx_mem, res_vent,
   4369                                       BASE_VALID_1f) == 7;
   4370         } else {
   4371             vld = soc_mem_field32_get(unit, evx_mem, res_vent, VALIDf);
   4372         }
   4373 
   4374         if (vld) {
   4375             profile_idx = soc_mem_field32_get(unit, evx_mem, res_vent,
   4376                                               TAG_ACTION_PROFILE_PTRf);
   4377             _bcm_trx_egr_vlan_action_profile_entry_get(unit, &action, profile_idx);
   4378 
   4379             if (!BCM_VLAN_VALID(match_vlan)) {
   4380                 if (bcmVlanActionDelete == action.ot_outer) {
   4381                     *flags = BCM_VLAN_PORT_UNTAGGED;
   4382                 }
   4383             } else {
   4384                 if (bcmVlanActionNone == action.ot_inner) {
   4385                     *flags = BCM_VLAN_PORT_UNTAGGED;
   4386                 }
   4387             }
   4388         }
   4389     }
   4390 
   4391     return rv;
   4392 }
   4393 
   4394 /*
   4395  * Function:
   4396  *      bcm_trident_niv_port_untagged_vlan_set
   4397  * Purpose:
   4398  *      Set the default VLAN ID for a NIV port.
   4399  * Parameters:
   4400  *      unit - StrataSwitch unit number.
   4401  *      port - NIV gport.
   4402  *      vid -  VLAN ID used for packets that ingress without a VLAN tag.
   4403  * Returns:
   4404  *      BCM_E_xxx
   4405  */
   4406 int
   4407 bcm_trident_niv_port_untagged_vlan_set(int unit, bcm_port_t port,
   4408         bcm_vlan_t vid)
   4409 {
   4410     int                rv = BCM_E_NONE;
   4411     int                vp;
   4412     uint32             key_data[SOC_MAX_MEM_FIELD_WORDS];
   4413     uint32             entry_data[SOC_MAX_MEM_FIELD_WORDS];
   4414     int                key_type;
   4415     bcm_module_t       mod_out;
   4416     bcm_port_t         port_out;
   4417     bcm_trunk_t        trunk_out;
   4418     int                tmp_id;
   4419     int                entry_index;
   4420     bcm_gport_t        gport;
   4421     bcm_vlan_t         match_vlan;
   4422     uint16             virtual_interface_id;
   4423     int                tmp_vp;
   4424     uint8              *vt_buf = NULL;
   4425     int                index, index_min, index_max;
   4426     vlan_xlate_entry_t *vent = NULL;
   4427     int                action;
   4428     int                cnt = 0;
   4429 
   4430     soc_mem_t          vx_mem = VLAN_XLATEm;
   4431 
   4432     if (soc_mem_is_valid(unit, VLAN_XLATE_1_DOUBLEm)) {
   4433         vx_mem = VLAN_XLATE_1_DOUBLEm;
   4434     }
   4435 
   4436     /* Get VP */
   4437     if (BCM_GPORT_IS_NIV_PORT(port)) {
   4438         vp = BCM_GPORT_NIV_PORT_ID_GET(port);
   4439     } else {
   4440         return BCM_E_PORT;
   4441     }
   4442     
   4443     if (!(NIV_PORT_INFO(unit, vp)->flags & BCM_NIV_PORT_MATCH_DO_NOT_ADD)) {
   4444         _bcm_trident_niv_match_info_get(unit, vp, &gport,
   4445                                         &match_vlan, &virtual_interface_id);
   4446 
   4447         /* Construct lookup key */
   4448         sal_memset(key_data, 0, sizeof(key_data));
   4449 
   4450         if (BCM_VLAN_VALID(match_vlan)) {
   4451             BCM_IF_ERROR_RETURN(_bcm_esw_vlan_xlate_key_type_value_get(unit,
   4452                         VLXLT_HASH_KEY_TYPE_VIF_VLAN, &key_type));
   4453             soc_mem_field32_set(unit, vx_mem, key_data, VIF__VLANf, match_vlan);
   4454         } else {
   4455             BCM_IF_ERROR_RETURN(_bcm_esw_vlan_xlate_key_type_value_get(unit,
   4456                         VLXLT_HASH_KEY_TYPE_VIF, &key_type));
   4457         }
   4458         soc_mem_field32_set(unit, vx_mem, key_data, KEY_TYPEf, key_type);
   4459         if (soc_mem_field_valid(unit, vx_mem, DATA_TYPEf)) {
   4460             soc_mem_field32_set(unit, vx_mem, key_data, DATA_TYPEf, key_type);
   4461         }
   4462 
   4463         soc_mem_field32_set(unit, vx_mem, key_data, VIF__SRC_VIFf,
   4464                             virtual_interface_id);
   4465 
   4466         if (soc_mem_field_valid(unit, vx_mem, SOURCE_TYPEf)) {
   4467             soc_mem_field32_set(unit, vx_mem, key_data, SOURCE_TYPEf, 1);
   4468         }
   4469         BCM_IF_ERROR_RETURN
   4470             (_bcm_esw_gport_resolve(unit, gport,
   4471                                     &mod_out, &port_out, &trunk_out, &tmp_id));
   4472         if (BCM_GPORT_IS_TRUNK(gport)) {
   4473             soc_mem_field32_set(unit, vx_mem, key_data, VIF__Tf, 1);
   4474             soc_mem_field32_set(unit, vx_mem, key_data, VIF__TGIDf, trunk_out);
   4475         } else {
   4476             soc_mem_field32_set(unit, vx_mem, key_data, VIF__MODULE_IDf, mod_out);
   4477             soc_mem_field32_set(unit, vx_mem, key_data, VIF__PORT_NUMf, port_out);
   4478         }
   4479 
   4480         /* Lookup existing entry */
   4481         SOC_IF_ERROR_RETURN(soc_mem_search(unit, vx_mem, MEM_BLOCK_ALL,
   4482                     &entry_index, key_data, entry_data, 0));
   4483 
   4484         /* Replace entry's new VLAN */
   4485         soc_mem_field32_set(unit, vx_mem, entry_data, VIF__NEW_OVIDf, vid);
   4486 
   4487         /* Insert new entry */
   4488         rv = soc_mem_insert(unit, vx_mem, MEM_BLOCK_ALL, entry_data);
   4489         if (rv == SOC_E_EXISTS) {
   4490             rv = BCM_E_NONE;
   4491         } else {
   4492             return BCM_E_INTERNAL;
   4493         }
   4494     } else {
   4495         vt_buf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, vx_mem),
   4496                                "VLAN_XLATE buffer");
   4497 
   4498         if (NULL == vt_buf) {
   4499             return BCM_E_MEMORY;
   4500         }
   4501 
   4502         index_min = soc_mem_index_min(unit, vx_mem);
   4503         index_max = soc_mem_index_max(unit, vx_mem);
   4504 
   4505         soc_mem_lock(unit, vx_mem);
   4506         if ((rv = soc_mem_read_range(unit, vx_mem, MEM_BLOCK_ANY,
   4507                                      index_min, index_max, vt_buf)) < 0) {
   4508             soc_cm_sfree(unit, vt_buf);
   4509             soc_mem_unlock(unit, vx_mem);
   4510             return rv;
   4511         }
   4512 
   4513         for (index = index_min; index <= index_max; index++) {
   4514             vent = soc_mem_table_idx_to_pointer(unit, vx_mem,
   4515                                                 void *,
   4516                                                 vt_buf, index);
   4517             if (soc_feature(unit, soc_feature_base_valid)) {
   4518                 if ((soc_mem_field32_get(unit, vx_mem, vent, BASE_VALID_0f) != 3) ||
   4519                          (soc_mem_field32_get(unit, vx_mem, vent, BASE_VALID_1f) != 7)) {
   4520                     continue;
   4521                 }
   4522             } else {
   4523                 if (soc_mem_field32_get(unit, vx_mem, vent, VALIDf) == 0) {
   4524                     continue;
   4525                 }
   4526             }
   4527             action = soc_mem_field32_get(unit, vx_mem, vent, VIF__MPLS_ACTIONf);
   4528             if (action != 1) {
   4529                 /* Entry is not for an SVP */
   4530                 continue;
   4531             }
   4532             tmp_vp = soc_mem_field32_get(unit, vx_mem, vent, VIF__SOURCE_VPf);
   4533             if (vp != tmp_vp) {
   4534                 continue;
   4535             }
   4536             /* Replace entry's new VLAN */
   4537             soc_mem_field32_set(unit, vx_mem, vent, VIF__NEW_OVIDf, vid);
   4538             cnt++;
   4539         }
   4540 
   4541         if (cnt == 0) {
   4542             soc_cm_sfree(unit, vt_buf);
   4543             soc_mem_unlock(unit, vx_mem);
   4544             return BCM_E_NOT_FOUND;
   4545         }
   4546 
   4547         rv = soc_mem_write_range(unit, vx_mem, MEM_BLOCK_ALL, index_min,
   4548                                  index_max, vt_buf);
   4549         soc_cm_sfree(unit, vt_buf);
   4550         soc_mem_unlock(unit, vx_mem);
   4551     }
   4552 
   4553     return rv;
   4554 }
   4555 
   4556 /*
   4557  * Function:
   4558  *      bcm_trident_niv_port_untagged_vlan_get
   4559  * Purpose:
   4560  *      Get the default VLAN ID for a NIV port.
   4561  * Parameters:
   4562  *      unit - StrataSwitch unit number.
   4563  *      port - NIV gport.
   4564  *      vid  - (OUT) VLAN ID used for packets that ingress without a VLAN tag.
   4565  * Returns:
   4566  *      BCM_E_xxx
   4567  */
   4568 int
   4569 bcm_trident_niv_port_untagged_vlan_get(int unit, bcm_port_t port,
   4570         bcm_vlan_t *vid)
   4571 {
   4572     int                rv = BCM_E_NONE;
   4573     int                vp;
   4574     uint32             key_data[SOC_MAX_MEM_FIELD_WORDS];
   4575     uint32             entry_data[SOC_MAX_MEM_FIELD_WORDS];
   4576     int                key_type;
   4577     bcm_module_t       mod_out;
   4578     bcm_port_t         port_out;
   4579     bcm_trunk_t        trunk_out;
   4580     int                tmp_id;
   4581     int                entry_index;
   4582     bcm_gport_t        gport;
   4583     bcm_vlan_t         match_vlan;
   4584     uint16             virtual_interface_id;
   4585     soc_mem_t          vx_mem = VLAN_XLATEm;
   4586     int                tmp_vp;
   4587     uint8              *vt_buf = NULL;
   4588     int                index, index_min, index_max;
   4589     vlan_xlate_entry_t *vent = NULL;
   4590     int                action;
   4591 
   4592     if (soc_mem_is_valid(unit, VLAN_XLATE_1_DOUBLEm)) {
   4593         vx_mem = VLAN_XLATE_1_DOUBLEm;
   4594     }
   4595 
   4596     /* Get VP */
   4597     if (BCM_GPORT_IS_NIV_PORT(port)) {
   4598         vp = BCM_GPORT_NIV_PORT_ID_GET(port);
   4599     } else {
   4600         return BCM_E_PORT;
   4601     }
   4602 
   4603     if (!(NIV_PORT_INFO(unit, vp)->flags & BCM_NIV_PORT_MATCH_DO_NOT_ADD)) {
   4604         /* Construct lookup key */
   4605         sal_memset(key_data, 0, sizeof(key_data));
   4606         _bcm_trident_niv_match_info_get(unit, vp, &gport,
   4607                                         &match_vlan, &virtual_interface_id);
   4608 
   4609         if (BCM_VLAN_VALID(match_vlan)) {
   4610             BCM_IF_ERROR_RETURN(_bcm_esw_vlan_xlate_key_type_value_get(unit,
   4611                         VLXLT_HASH_KEY_TYPE_VIF_VLAN, &key_type));
   4612             soc_mem_field32_set(unit, vx_mem, key_data, VIF__VLANf, match_vlan);
   4613         } else {
   4614             BCM_IF_ERROR_RETURN(_bcm_esw_vlan_xlate_key_type_value_get(unit,
   4615                         VLXLT_HASH_KEY_TYPE_VIF, &key_type));
   4616         }
   4617         soc_mem_field32_set(unit, vx_mem, key_data, KEY_TYPEf, key_type);
   4618         if (soc_mem_field_valid(unit, vx_mem, DATA_TYPEf)) {
   4619             soc_mem_field32_set(unit, vx_mem, key_data, DATA_TYPEf, key_type);
   4620         }
   4621 
   4622         soc_mem_field32_set(unit, vx_mem, key_data, VIF__SRC_VIFf,
   4623                                     virtual_interface_id);
   4624 
   4625         if (soc_mem_field_valid(unit, vx_mem, SOURCE_TYPEf)) {
   4626             soc_mem_field32_set(unit, vx_mem, key_data, SOURCE_TYPEf, 1);
   4627         }
   4628         BCM_IF_ERROR_RETURN
   4629             (_bcm_esw_gport_resolve(unit, gport,
   4630                                     &mod_out, &port_out, &trunk_out, &tmp_id));
   4631         if (BCM_GPORT_IS_TRUNK(gport)) {
   4632             soc_mem_field32_set(unit, vx_mem, key_data, VIF__Tf, 1);
   4633             soc_mem_field32_set(unit, vx_mem, key_data, VIF__TGIDf, trunk_out);
   4634         } else {
   4635             soc_mem_field32_set(unit, vx_mem, key_data, VIF__MODULE_IDf, mod_out);
   4636             soc_mem_field32_set(unit, vx_mem, key_data, VIF__PORT_NUMf, port_out);
   4637         }
   4638 
   4639         /* Lookup existing entry */
   4640         SOC_IF_ERROR_RETURN(soc_mem_search(unit, vx_mem, MEM_BLOCK_ALL,
   4641                     &entry_index, key_data, entry_data, 0));
   4642 
   4643         /* Get entry's VLAN */
   4644         *vid = soc_mem_field32_get(unit, vx_mem, entry_data, VIF__NEW_OVIDf);
   4645     } else {
   4646         vt_buf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, vx_mem),
   4647                                "VLAN_XLATE buffer");
   4648 
   4649         if (NULL == vt_buf) {
   4650             return BCM_E_MEMORY;
   4651         }
   4652 
   4653         index_min = soc_mem_index_min(unit, vx_mem);
   4654         index_max = soc_mem_index_max(unit, vx_mem);
   4655 
   4656         soc_mem_lock(unit, vx_mem);
   4657         if ((rv = soc_mem_read_range(unit, vx_mem, MEM_BLOCK_ANY,
   4658                                      index_min, index_max, vt_buf)) < 0) {
   4659             soc_cm_sfree(unit, vt_buf);
   4660             soc_mem_unlock(unit, vx_mem);
   4661             return rv;
   4662         }
   4663 
   4664         for (index = index_min; index <= index_max; index++) {
   4665             vent = soc_mem_table_idx_to_pointer(unit, vx_mem,
   4666                                                 void *,
   4667                                                 vt_buf, index);
   4668             if (soc_mem_field32_get(unit, vx_mem, vent, VALIDf) == 0) {
   4669                 continue;
   4670             }
   4671             action = soc_mem_field32_get(unit, vx_mem, vent, VIF__MPLS_ACTIONf);
   4672             if (action != 1) {
   4673                 /* Entry is not for an SVP */
   4674                 continue;
   4675             }
   4676             tmp_vp = soc_mem_field32_get(unit, vx_mem, vent, VIF__SOURCE_VPf);
   4677             if (vp != tmp_vp) {
   4678                 continue;
   4679             }
   4680             /* Get entry's VLAN */
   4681             *vid = soc_mem_field32_get(unit, vx_mem, vent, VIF__NEW_OVIDf);
   4682             break;
   4683         }
   4684         soc_cm_sfree(unit, vt_buf);
   4685         soc_mem_unlock(unit, vx_mem);
   4686         if (index > index_max) {
   4687             return BCM_E_NOT_FOUND;
   4688         }
   4689     }
   4690 
   4691     return rv;
   4692 }
   4693 
   4694 #ifdef BCM_TRIDENT2_SUPPORT
   4695 
   4696 /*
   4697  * Function:
   4698  *      _bcm_td2_niv_match_vp_replace
   4699  * Purpose:
   4700  *      Replace VP value in NIV VP's match entry.
   4701  * Parameters:
   4702  *      unit - (IN) SOC unit number. 
   4703  *      vp - (IN) NIV VP whose match entry is being replaced.
   4704  *      new_vp - (IN) New VP value.
   4705  *      old_vp - (OUT) Old VP value.
   4706  * Returns:
   4707  *      BCM_X_XXX
   4708  */
   4709 STATIC int
   4710 _bcm_td2_niv_match_vp_replace(int unit, int vp, int new_vp, int *old_vp)
   4711 {
   4712     int                rv = BCM_E_NONE;
   4713     uint32             key_data[SOC_MAX_MEM_FIELD_WORDS];
   4714     uint32             entry_data[SOC_MAX_MEM_FIELD_WORDS];
   4715     int                key_type;
   4716     bcm_module_t       mod_out;
   4717     bcm_port_t         port_out;
   4718     bcm_trunk_t        trunk_out;
   4719     int                tmp_id;
   4720     int                entry_index;
   4721     bcm_gport_t        port;
   4722     bcm_vlan_t         match_vlan;
   4723     uint16             vtl_id;
   4724     soc_mem_t          mem = VLAN_XLATEm;
   4725 
   4726     if (soc_mem_is_valid(unit, VLAN_XLATE_1_DOUBLEm)) {
   4727         mem = VLAN_XLATE_1_DOUBLEm;
   4728     }
   4729 
   4730     /* Construct lookup key */
   4731     sal_memset(key_data, 0, sizeof(key_data));
   4732     _bcm_trident_niv_match_info_get(unit, vp, &port, &match_vlan, &vtl_id);
   4733     if (BCM_VLAN_VALID(match_vlan)) {
   4734         BCM_IF_ERROR_RETURN(_bcm_esw_vlan_xlate_key_type_value_get(unit,
   4735                     VLXLT_HASH_KEY_TYPE_VIF_VLAN, &key_type));
   4736         soc_mem_field32_set(unit, mem, key_data, VIF__VLANf, match_vlan);
   4737     } else {
   4738         BCM_IF_ERROR_RETURN(_bcm_esw_vlan_xlate_key_type_value_get(unit,
   4739                     VLXLT_HASH_KEY_TYPE_VIF, &key_type));
   4740     }
   4741     soc_mem_field32_set(unit, mem, key_data, KEY_TYPEf, key_type);
   4742     if (soc_mem_field_valid(unit, mem, DATA_TYPEf)) {
   4743         soc_mem_field32_set(unit, mem, key_data, DATA_TYPEf, key_type);
   4744     }
   4745 
   4746     soc_mem_field32_set(unit, mem, key_data, VIF__SRC_VIFf, vtl_id);
   4747 
   4748     if (soc_mem_field_valid(unit, mem, SOURCE_TYPEf)) {
   4749         soc_mem_field32_set(unit, mem, key_data, SOURCE_TYPEf, 1);
   4750     }
   4751     BCM_IF_ERROR_RETURN
   4752         (_bcm_esw_gport_resolve(unit, port,
   4753                                 &mod_out, &port_out, &trunk_out, &tmp_id));
   4754     if (BCM_GPORT_IS_TRUNK(port)) {
   4755         soc_mem_field32_set(unit, mem, key_data, VIF__Tf, 1);
   4756         soc_mem_field32_set(unit, mem, key_data, VIF__TGIDf, trunk_out);
   4757     } else {
   4758         soc_mem_field32_set(unit, mem, key_data, VIF__MODULE_IDf, mod_out);
   4759         soc_mem_field32_set(unit, mem, key_data, VIF__PORT_NUMf, port_out);
   4760     }
   4761 
   4762     /* Lookup existing entry */
   4763     SOC_IF_ERROR_RETURN(soc_mem_search(unit, mem, MEM_BLOCK_ALL,
   4764                 &entry_index, key_data, entry_data, 0));
   4765 
   4766     /* Replace entry's VP value */
   4767     *old_vp = soc_mem_field32_get(unit, mem, entry_data, VIF__SOURCE_VPf);
   4768     soc_mem_field32_set(unit, mem, entry_data, VIF__SOURCE_VPf, new_vp);
   4769 
   4770     /* Insert new entry */
   4771     rv = soc_mem_insert(unit, mem, MEM_BLOCK_ALL, entry_data);
   4772     if (rv == SOC_E_EXISTS) {
   4773         rv = BCM_E_NONE;
   4774     } else {
   4775         return BCM_E_INTERNAL;
   4776     }
   4777 
   4778     return rv;
   4779 }
   4780 
   4781 /*
   4782  * Function:
   4783  *      bcm_td2_niv_port_source_vp_lag_set
   4784  * Purpose:
   4785  *      Set source VP LAG for a NIV virtual port.
   4786  * Parameters:
   4787  *      unit - (IN) SOC unit number. 
   4788  *      gport - (IN) NIV virtual port GPORT ID. 
   4789  *      vp_lag_vp - (IN) VP representing the VP LAG. 
   4790  * Returns:
   4791  *      BCM_X_XXX
   4792  */
   4793 int
   4794 bcm_td2_niv_port_source_vp_lag_set(int unit, bcm_gport_t gport,
   4795         int vp_lag_vp)
   4796 {
   4797     int vp, old_vp;
   4798 
   4799     if (!BCM_GPORT_IS_NIV_PORT(gport)) {
   4800         return BCM_E_PARAM;
   4801     }
   4802     vp = BCM_GPORT_NIV_PORT_ID_GET(gport);
   4803     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   4804         return BCM_E_PARAM;
   4805     }
   4806 
   4807     /* Set source VP LAG by replacing the SVP field in NIV VP's
   4808      * match entry with the VP value representing the VP LAG.
   4809      */
   4810     BCM_IF_ERROR_RETURN
   4811         (_bcm_td2_niv_match_vp_replace(unit, vp, vp_lag_vp, &old_vp));
   4812 
   4813     return BCM_E_NONE;
   4814 }
   4815 
   4816 /*
   4817  * Function:
   4818  *      bcm_td2_niv_port_source_vp_lag_clear
   4819  * Purpose:
   4820  *      Clear source VP LAG for a NIV virtual port.
   4821  * Parameters:
   4822  *      unit - (IN) SOC unit number. 
   4823  *      gport - (IN) NIV virtual port GPORT ID. 
   4824  *      vp_lag_vp - (IN) VP representing the VP LAG. 
   4825  * Returns:
   4826  *      BCM_X_XXX
   4827  */
   4828 int
   4829 bcm_td2_niv_port_source_vp_lag_clear(int unit, bcm_gport_t gport,
   4830         int vp_lag_vp)
   4831 {
   4832     int vp, old_vp;
   4833 
   4834     if (!BCM_GPORT_IS_NIV_PORT(gport)) {
   4835         return BCM_E_PARAM;
   4836     }
   4837     vp = BCM_GPORT_NIV_PORT_ID_GET(gport);
   4838     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   4839         return BCM_E_PARAM;
   4840     }
   4841 
   4842     /* Clear source VP LAG by replacing the SVP field in NIV VP's
   4843      * match entry with the VP value.
   4844      */
   4845     BCM_IF_ERROR_RETURN
   4846         (_bcm_td2_niv_match_vp_replace(unit, vp, vp, &old_vp));
   4847 
   4848     /* Check that the old VP value matches the VP value representing
   4849      * the VP LAG or has been restored.
   4850      */
   4851     if ((old_vp != vp_lag_vp) && (old_vp != vp)) {
   4852         return BCM_E_INTERNAL;
   4853     }
   4854 
   4855     return BCM_E_NONE;
   4856 }
   4857 
   4858 /*
   4859  * Function:
   4860  *      bcm_td2_niv_port_source_vp_lag_get
   4861  * Purpose:
   4862  *      Set source VP LAG for a NIV virtual port.
   4863  * Parameters:
   4864  *      unit - (IN) SOC unit number. 
   4865  *      gport - (IN) NIV virtual port GPORT ID. 
   4866  *      vp_lag_vp - (OUT) VP representing the VP LAG. 
   4867  * Returns:
   4868  *      BCM_X_XXX
   4869  */
   4870 int
   4871 bcm_td2_niv_port_source_vp_lag_get(int unit, bcm_gport_t gport,
   4872         int *vp_lag_vp)
   4873 {
   4874     int                vp;
   4875     uint32             key_data[SOC_MAX_MEM_FIELD_WORDS];
   4876     uint32             entry_data[SOC_MAX_MEM_FIELD_WORDS];
   4877     int                key_type;
   4878     bcm_module_t       mod_out;
   4879     bcm_port_t         port_out;
   4880     bcm_trunk_t        trunk_out;
   4881     int                tmp_id;
   4882     int                entry_index;
   4883     bcm_gport_t        port;
   4884     bcm_vlan_t         match_vlan;
   4885     uint16             vtl_id;
   4886     soc_mem_t          mem = VLAN_XLATEm;
   4887 
   4888     if (soc_mem_is_valid(unit, VLAN_XLATE_1_DOUBLEm)) {
   4889         mem = VLAN_XLATE_1_DOUBLEm;
   4890     }
   4891 
   4892     if (!BCM_GPORT_IS_NIV_PORT(gport)) {
   4893         return BCM_E_PARAM;
   4894     }
   4895     vp = BCM_GPORT_NIV_PORT_ID_GET(gport);
   4896     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   4897         return BCM_E_PARAM;
   4898     }
   4899 
   4900     /* Construct match entry lookup key */
   4901     sal_memset(key_data, 0, sizeof(key_data));
   4902     _bcm_trident_niv_match_info_get(unit, vp, &port, &match_vlan, &vtl_id);
   4903 
   4904     if (BCM_VLAN_VALID(match_vlan)) {
   4905         BCM_IF_ERROR_RETURN(_bcm_esw_vlan_xlate_key_type_value_get(unit,
   4906                     VLXLT_HASH_KEY_TYPE_VIF_VLAN, &key_type));
   4907         soc_mem_field32_set(unit, mem, key_data, VIF__VLANf, match_vlan);
   4908     } else {
   4909         BCM_IF_ERROR_RETURN(_bcm_esw_vlan_xlate_key_type_value_get(unit,
   4910                     VLXLT_HASH_KEY_TYPE_VIF, &key_type));
   4911     }
   4912     soc_mem_field32_set(unit, mem, key_data, KEY_TYPEf, key_type);
   4913     if (soc_mem_field_valid(unit, mem, DATA_TYPEf)) {
   4914         soc_mem_field32_set(unit, mem, key_data, DATA_TYPEf, key_type);
   4915     }
   4916 
   4917     soc_mem_field32_set(unit, mem, key_data, VIF__SRC_VIFf, vtl_id);
   4918 
   4919     if (soc_mem_field_valid(unit, mem, SOURCE_TYPEf)) {
   4920         soc_mem_field32_set(unit, mem, key_data, SOURCE_TYPEf, 1);
   4921     }
   4922     BCM_IF_ERROR_RETURN
   4923         (_bcm_esw_gport_resolve(unit, port,
   4924                                 &mod_out, &port_out, &trunk_out, &tmp_id));
   4925     if (BCM_GPORT_IS_TRUNK(port)) {
   4926         soc_mem_field32_set(unit, mem, key_data, VIF__Tf, 1);
   4927         soc_mem_field32_set(unit, mem, key_data, VIF__TGIDf, trunk_out);
   4928     } else {
   4929         soc_mem_field32_set(unit, mem, key_data, VIF__MODULE_IDf, mod_out);
   4930         soc_mem_field32_set(unit, mem, key_data, VIF__PORT_NUMf, port_out);
   4931     }
   4932 
   4933     /* Lookup existing entry */
   4934     SOC_IF_ERROR_RETURN(soc_mem_search(unit, mem, MEM_BLOCK_ALL,
   4935                 &entry_index, key_data, entry_data, 0));
   4936 
   4937     /* Get VP value representing VP LAG */
   4938     *vp_lag_vp = soc_mem_field32_get(unit, mem, entry_data, VIF__SOURCE_VPf);
   4939     if (!_bcm_vp_used_get(unit, *vp_lag_vp, _bcmVpTypeVpLag)) {
   4940         return BCM_E_INTERNAL;
   4941     }
   4942 
   4943     return BCM_E_NONE;
   4944 }
   4945 
   4946 #endif /* BCM_TRIDENT2_SUPPORT */
   4947 
   4948 /* Function:
   4949  *      _bcm_trident_local_port_match
   4950  * Purpose:
   4951  *      Determine if two gports represent the same local physical port(s).
   4952  * Parameters:
   4953  *      unit - (IN) SOC unit Number
   4954  *      gport1 - (IN) GPORT ID 1
   4955  *      gport2 - (IN) GPORT ID 2
   4956  *      match  - (OUT) Match indication
   4957  * Returns:
   4958  *      BCM_E_XXX
   4959  */
   4960 STATIC int
   4961 _bcm_trident_local_port_match(int unit, bcm_gport_t gport1,
   4962         bcm_gport_t gport2, int *match)
   4963 {
   4964     bcm_module_t mod1, mod2;
   4965     bcm_port_t port1, port2;
   4966     bcm_trunk_t tgid1, tgid2;
   4967     int id1, id2;
   4968     int mod_local;
   4969 
   4970     *match = FALSE;
   4971 
   4972     BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, gport1,
   4973                 &mod1, &port1, &tgid1, &id1));
   4974     BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, gport2,
   4975                 &mod2, &port2, &tgid2, &id2));
   4976     if (id1 != -1 || id2 != -1) {
   4977         return BCM_E_PORT;
   4978     }
   4979 
   4980     if (BCM_TRUNK_INVALID != tgid1) {
   4981         if (BCM_TRUNK_INVALID != tgid2) {
   4982             if (tgid1 == tgid2) {
   4983                 *match = TRUE;
   4984             }
   4985         }
   4986     } else {
   4987         BCM_IF_ERROR_RETURN(_bcm_esw_modid_is_local(unit, mod1, &mod_local));
   4988         if (!mod_local) {
   4989             return BCM_E_PORT;
   4990         }
   4991         if (BCM_TRUNK_INVALID == tgid2) {
   4992             BCM_IF_ERROR_RETURN(_bcm_esw_modid_is_local(unit, mod2, &mod_local));
   4993             if (!mod_local) {
   4994                 return BCM_E_PORT;
   4995             }
   4996             if (mod1 == mod2 && port1 == port2) {
   4997                 *match = TRUE;
   4998             }
   4999         }
   5000     }
   5001 
   5002     return BCM_E_NONE;
   5003 }
   5004 
   5005 /*
   5006  * Function:
   5007  *      bcm_trident_niv_port_learn_set
   5008  * Purpose:
   5009  *      Set the CML bits for an niv port.
   5010  * Returns:
   5011  *      BCM_E_XXX
   5012  */
   5013 int
   5014 bcm_trident_niv_port_learn_set(int unit, bcm_gport_t niv_port_id, 
   5015                                 uint32 flags)
   5016 {
   5017     int vp, cml = 0, rv = BCM_E_NONE, entry_type;
   5018     source_vp_entry_t svp;
   5019 
   5020     rv = _bcm_niv_check_init(unit);
   5021 
   5022     if (rv != BCM_E_NONE){
   5023         return rv;
   5024     }
   5025 
   5026     cml = 0;
   5027     if (!(flags & BCM_PORT_LEARN_FWD)) {
   5028        cml |= (1 << 0);
   5029     }
   5030     if (flags & BCM_PORT_LEARN_CPU) {
   5031        cml |= (1 << 1);
   5032     }
   5033     if (flags & BCM_PORT_LEARN_PENDING) {
   5034        cml |= (1 << 2);
   5035     }
   5036     if (flags & BCM_PORT_LEARN_ARL) {
   5037        cml |= (1 << 3);
   5038     }
   5039 
   5040     /* Get the VP index from the gport */
   5041     vp = BCM_GPORT_NIV_PORT_ID_GET(niv_port_id);
   5042 
   5043     MEM_LOCK(unit, SOURCE_VPm);
   5044     /* Be sure the entry is used and is set for MIM */
   5045     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   5046         MEM_UNLOCK(unit, SOURCE_VPm);
   5047         return BCM_E_NOT_FOUND;
   5048     }
   5049     /* coverity[negative_returns] */
   5050     rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp);
   5051     if (rv < 0) {
   5052         MEM_UNLOCK(unit, SOURCE_VPm);
   5053         return rv;
   5054     }
   5055 
   5056     /* Ensure that the entry_type is either 3 or 1. The ENTRYP_TYPE is
   5057      * modified from 3 to 1 when a NIV port is added to a VXLAN VPN via
   5058      * bcm_vxlan_port_add. 
   5059      */
   5060     entry_type = soc_SOURCE_VPm_field32_get(unit, &svp, ENTRY_TYPEf);
   5061     if ((entry_type != 3) && ((entry_type != 1))){
   5062         MEM_UNLOCK(unit, SOURCE_VPm);
   5063         return BCM_E_NOT_FOUND;
   5064     }
   5065 
   5066     soc_SOURCE_VPm_field32_set(unit, &svp, CML_FLAGS_MOVEf, cml);
   5067     soc_SOURCE_VPm_field32_set(unit, &svp, CML_FLAGS_NEWf, cml);
   5068     rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp);
   5069     MEM_UNLOCK(unit, SOURCE_VPm);
   5070     return rv;
   5071 }
   5072 
   5073 /*
   5074  * Function:    
   5075  *      bcm_trident_niv_port_learn_get
   5076  * Purpose:
   5077  *      Get the CML bits for an mpls port
   5078  * Returns: 
   5079  *      BCM_E_XXX
   5080  */     
   5081 int     
   5082 bcm_trident_niv_port_learn_get(int unit, bcm_gport_t niv_port_id, 
   5083                                 uint32 *flags)
   5084 {
   5085     int rv, vp, cml = 0, entry_type;
   5086     source_vp_entry_t svp;
   5087     
   5088     rv = _bcm_niv_check_init(unit);
   5089 
   5090     if (rv != BCM_E_NONE){
   5091         return rv;
   5092     }
   5093 	    
   5094     /* Get the VP index from the gport */
   5095     vp = BCM_GPORT_NIV_PORT_ID_GET(niv_port_id);
   5096     if (vp == -1) {
   5097        return BCM_E_PARAM;
   5098     }
   5099 
   5100     /* Be sure the entry is used and is set for NIV */
   5101     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   5102         return BCM_E_NOT_FOUND;
   5103     }
   5104     rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp);
   5105     if (rv < 0) {
   5106         return rv;
   5107     }
   5108 
   5109     /* Ensure that the entry_type is either 3 or 1. The ENTRYP_TYPE is
   5110      * modified from 3 to 1 when a NIV port is added to a VXLAN VPN via
   5111      * bcm_vxlan_port_add. 
   5112      */
   5113     entry_type = soc_SOURCE_VPm_field32_get(unit, &svp, ENTRY_TYPEf);
   5114     if ((entry_type != 3) && ((entry_type != 1))){
   5115         return BCM_E_NOT_FOUND;
   5116     }
   5117 
   5118     cml = soc_SOURCE_VPm_field32_get(unit, &svp, CML_FLAGS_NEWf);
   5119     
   5120     *flags = 0;
   5121     if (!(cml & (1 << 0))) {
   5122        *flags |= BCM_PORT_LEARN_FWD;
   5123     }
   5124     if (cml & (1 << 1)) {
   5125        *flags |= BCM_PORT_LEARN_CPU;
   5126     }
   5127     if (cml & (1 << 2)) {
   5128        *flags |= BCM_PORT_LEARN_PENDING;
   5129     }
   5130     if (cml & (1 << 3)) {
   5131        *flags |= BCM_PORT_LEARN_ARL;
   5132     }
   5133     return BCM_E_NONE;
   5134 }
   5135 
   5136 /* Function:
   5137  *      _bcm_trident_niv_egress_match_ex_port
   5138  * Purpose:
   5139  *      Determine if two NIV egress objects' attributes match, except for
   5140  *      port.
   5141  * Parameters:
   5142  *      unit - (IN) SOC unit Number
   5143  *      niv_egress1 - (IN) NIV egress object 1, represented by
   5144  *                         bcm_niv_egress_t.
   5145  *      niv_egress2 - (IN) NIV egress object 2, represented by
   5146  *                         _bcm_trident_niv_egress_t.
   5147  *      match - (OUT) Match indication
   5148  * Returns:
   5149  *      BCM_E_XXX
   5150  */
   5151 STATIC int
   5152 _bcm_trident_niv_egress_match_ex_port(int unit,
   5153         bcm_niv_egress_t *niv_egress1,
   5154         _bcm_trident_niv_egress_t *niv_egress2,
   5155         int *match)
   5156 {
   5157     int flags_match, vif_match, vlan_match = 1;
   5158     int service_tpid_match = 1, service_vlan_match = 1;
   5159     int service_pri_match = 1, service_cfi_match = 1;
   5160     int service_qos_map_id_match = 1, l3_intf_match = 1;
   5161 
   5162     flags_match = (niv_egress1->flags == niv_egress2->flags);
   5163     vif_match   = (niv_egress1->virtual_interface_id ==
   5164                    niv_egress2->virtual_interface_id);
   5165     if (niv_egress1->flags & BCM_NIV_EGRESS_L3) {
   5166         l3_intf_match = (niv_egress1->intf == niv_egress2->intf);
   5167     } else {
   5168         vlan_match  = (niv_egress1->match_vlan == niv_egress2->match_vlan);
   5169         service_tpid_match = (niv_egress1->service_tpid == niv_egress2->service_tpid);
   5170         service_vlan_match = (niv_egress1->service_vlan == niv_egress2->service_vlan);
   5171         service_pri_match  = (niv_egress1->service_pri  == niv_egress2->service_pri);
   5172         service_cfi_match  = (niv_egress1->service_cfi  == niv_egress2->service_cfi);
   5173         service_qos_map_id_match = (niv_egress1->service_qos_map_id ==
   5174                                    niv_egress2->service_qos_map_id);
   5175     }
   5176 
   5177     if (flags_match && vif_match && vlan_match && service_tpid_match &&
   5178             service_vlan_match && service_pri_match && service_cfi_match &&
   5179             service_qos_map_id_match && l3_intf_match) {
   5180         *match = TRUE;
   5181     } else {
   5182         *match = FALSE;
   5183     }
   5184 
   5185     return BCM_E_NONE;
   5186 }
   5187 
   5188 /* 
   5189  * Function:
   5190  *      _bcm_trident_niv_egress_pbmp_get
   5191  * Purpose:
   5192  *      Get the pbmp of the multicast egress objects
   5193  *      attaching to vp in the linked list.
   5194  * Parameters:
   5195  *      unit  - (IN) SOC unit Number
   5196  *      vp    - (IN) Virtual port number. 
   5197  *      pbmp  - (OUT) pbmp of the multicast egress objects attaching to vp.
   5198  * Returns:
   5199  *      BCM_E_XXX
   5200  */
   5201 STATIC void
   5202 _bcm_trident_niv_egress_pbmp_get(int unit, int vp, bcm_pbmp_t *pbmp)
   5203 {
   5204     _bcm_trident_niv_nh_info_t  *nh_info;
   5205     BCM_PBMP_CLEAR(*pbmp);
   5206 
   5207     nh_info = NIV_PORT_MC_NH_INFO(unit, vp);
   5208     while (nh_info) {
   5209         BCM_PBMP_PORT_ADD(*pbmp, nh_info->port);
   5210         nh_info = nh_info->next;
   5211     }
   5212 
   5213     return;
   5214 }
   5215 
   5216 /* 
   5217  * Function:
   5218  *      _bcm_trident_niv_egress_pbmp_delete
   5219  * Purpose:
   5220  *      delete the pbmp of the multicast egress objects
   5221  *      attaching to vp from the linked list.
   5222  *      decrease the next hop ref_count of the port.
   5223  *      if next hop ref_count of the port is zero,
   5224  *      delete the node of the port from the list.
   5225  * Parameters:
   5226  *      unit - (IN) SOC unit Number
   5227  *      vp   - (IN) Virtual port number. 
   5228  *      pbmp - (IN) pbmp of the multicast egress objects attaching to vp.
   5229  * Returns:
   5230  *      BCM_E_XXX
   5231  */
   5232 STATIC void
   5233 _bcm_trident_niv_egress_pbmp_delete(int unit, int vp, bcm_pbmp_t pbmp)
   5234 {
   5235     _bcm_trident_niv_nh_info_t      *ni_pre, *ni_cur, *ni_del;
   5236 
   5237     ni_cur  = NIV_PORT_MC_NH_INFO(unit, vp);
   5238     ni_pre  = ni_cur;
   5239     ni_del  = NULL;
   5240     while (ni_cur) {
   5241         if (!BCM_PBMP_MEMBER(pbmp, ni_cur->port)) {
   5242             ni_pre = ni_cur;
   5243             ni_cur = ni_cur->next;
   5244             continue;
   5245         }
   5246 
   5247         /* port match */
   5248         ni_cur->nh_ref_cnt--;
   5249         if (ni_cur->nh_ref_cnt > 0) {
   5250             ni_pre = ni_cur;                
   5251             ni_cur = ni_cur->next;
   5252             continue;
   5253         } 
   5254 
   5255         /* Next hop refence count is zero. */
   5256         if (ni_cur == NIV_PORT_MC_NH_INFO(unit, vp)) {
   5257             NIV_PORT_MC_NH_INFO(unit, vp) = ni_cur->next;
   5258             ni_del = ni_cur;
   5259             ni_cur = ni_cur->next;
   5260             ni_pre = ni_cur; 
   5261         } else {
   5262             ni_del = ni_cur;
   5263             ni_pre->next = ni_cur->next;
   5264             ni_cur = ni_cur->next;
   5265         }
   5266         sal_free(ni_del);
   5267     }
   5268 
   5269     return;
   5270 }
   5271 
   5272 /*
   5273  * Function:
   5274  *      _bcm_trident_niv_egress_pbmp_add
   5275  * Purpose:
   5276  *      add the pbmp of the multicast egress objects
   5277  *      attaching to vp to the linked list.
   5278  *      decrease the next hop ref_count of the port.
   5279  *      if next hop ref_count of the port is zero,
   5280  *      delete the node of the port from the list.
   5281  * Parameters:
   5282  *      unit  - (IN) SOC unit Number
   5283  *      vp    - (IN) Virtual port number. 
   5284  *      pbmp  - (IN) pbmp of the multicast egress objects attaching to vp.
   5285  * Returns:
   5286  *      BCM_E_XXX
   5287  */
   5288 STATIC int
   5289 _bcm_trident_niv_egress_pbmp_add(int unit, int vp, bcm_pbmp_t pbmp)
   5290 {
   5291     bcm_port_t                      port;
   5292     int                             alloc_size;
   5293     _bcm_trident_niv_nh_info_t      *nh_info;
   5294     bcm_pbmp_t                      sucess_pbmp; 
   5295     
   5296     nh_info = NIV_PORT_MC_NH_INFO(unit, vp);
   5297     while (nh_info) {
   5298         if (BCM_PBMP_MEMBER(pbmp, nh_info->port)) {
   5299             nh_info->nh_ref_cnt++;
   5300             BCM_PBMP_PORT_REMOVE(pbmp, nh_info->port);
   5301         }
   5302         nh_info = nh_info->next;
   5303     }
   5304 
   5305     BCM_PBMP_CLEAR(sucess_pbmp);
   5306     alloc_size = sizeof(_bcm_trident_niv_nh_info_t);
   5307     BCM_PBMP_ITER(pbmp, port) {
   5308         nh_info = sal_alloc(alloc_size, "NIV Egress Next Hop Info");
   5309         if (NULL == nh_info) {
   5310             _bcm_trident_niv_egress_pbmp_delete(unit, vp, sucess_pbmp);
   5311             return BCM_E_MEMORY;
   5312         }
   5313         sal_memset(nh_info, 0, alloc_size);
   5314         nh_info->port = port;
   5315         nh_info->nh_ref_cnt = 1;
   5316         nh_info->next = NIV_PORT_MC_NH_INFO(unit, vp);
   5317         NIV_PORT_MC_NH_INFO(unit, vp) = nh_info;
   5318         BCM_PBMP_PORT_ADD(sucess_pbmp, port);
   5319     }
   5320 
   5321     return BCM_E_NONE;
   5322 }
   5323 
   5324 /*
   5325  * Function:
   5326  *      _bcm_trident_niv_egress_pbmp_clear
   5327  * Purpose:
   5328  *      clear the linked list which maintain the pbmp of
   5329  *      the multicast egress objects attaching to vp.
   5330  * Parameters:
   5331  *      unit  - (IN) SOC unit Number
   5332  *      vp    - (IN) Virtual port number. 
   5333  * Returns:
   5334  *      BCM_E_XXX
   5335  */
   5336 STATIC void
   5337 _bcm_trident_niv_egress_pbmp_clear(int unit, int vp)
   5338 {
   5339     _bcm_trident_niv_nh_info_t  *cur_node, *next_node;
   5340 
   5341     next_node = NULL;
   5342     cur_node = NIV_PORT_MC_NH_INFO(unit, vp);
   5343     while (cur_node) {
   5344         next_node = cur_node->next;
   5345         sal_free(cur_node);
   5346         cur_node = next_node;
   5347     }
   5348     NIV_PORT_MC_NH_INFO(unit, vp) = NULL;
   5349 
   5350     return;
   5351 }
   5352 
   5353 /*
   5354  * Function:
   5355  *      _bcm_trident_niv_egress_hash_calc
   5356  * Purpose:
   5357  *      Calculate the hash value according to the egress object info.
   5358  * Parameters:
   5359  *      unit     -  (IN) SOC unit number.
   5360  *      hash_key -  (IN) hash key.
   5361  *      hash     -  (OUT) Hash(signature) calculated value.
   5362  * Returns:
   5363  *      BCM_X_XXX
   5364  */
   5365 STATIC int
   5366 _bcm_trident_niv_egress_hash_calc(int unit, void *hash_key, uint16 *hash)
   5367 {
   5368     uint32 sw_buf[7];
   5369     int size;
   5370     int buf_idx = 0;
   5371     bcm_niv_egress_t *niv_egress;
   5372 
   5373     /* Input parameters check. */
   5374     if ((NULL == hash_key) || (NULL == hash)) {
   5375         return (BCM_E_PARAM);
   5376     }
   5377     size = sizeof(sw_buf);
   5378     sal_memset(sw_buf, 0, size);
   5379     niv_egress = (bcm_niv_egress_t *)hash_key;
   5380 
   5381     /*
   5382      * Copy entry information to a temporary buffer, so we can
   5383      * mask some fields we don't want to include in hash calculation.
   5384      */
   5385     sw_buf[buf_idx++] = niv_egress->flags;
   5386     sw_buf[buf_idx++] = niv_egress->intf;
   5387     sw_buf[buf_idx++] = niv_egress->virtual_interface_id << 16;
   5388     if (!(niv_egress->flags & BCM_NIV_EGRESS_L3)) {
   5389         sw_buf[buf_idx++] = ((niv_egress->service_tpid << 16) | 
   5390                               niv_egress->service_vlan);
   5391         sw_buf[buf_idx++] = ((niv_egress->service_pri << 16) | 
   5392                               niv_egress->service_cfi);
   5393         sw_buf[buf_idx++] = niv_egress->service_qos_map_id;
   5394     }
   5395 
   5396     size = sizeof(uint32) * buf_idx;
   5397     *hash = _shr_crc16(0, (uint8 *)&sw_buf[0], size);
   5398 
   5399     return BCM_E_NONE;
   5400 }
   5401 
   5402 /* Function:
   5403  *      bcm_trident_niv_egress_add
   5404  * Purpose:
   5405  *      Add a NIV egress object to a NIV port
   5406  * Parameters:
   5407  *      unit - (IN) SOC unit Number
   5408  *      niv_port - (IN) NIV port
   5409  *      niv_egress - (IN/OUT) NIV egress object, the egress_if field is output.
   5410  * Returns:
   5411  *      BCM_E_XXX
   5412  */
   5413 int
   5414 bcm_trident_niv_egress_add(
   5415     int unit, 
   5416     bcm_gport_t niv_port, 
   5417     bcm_niv_egress_t *niv_egress)
   5418 {
   5419     int vp;
   5420     int match_ex_port;
   5421     int local_port_match;
   5422     int shared_nh_found;
   5423     bcm_pbmp_t existing_pbmp, new_pbmp, update_pbmp;
   5424     _bcm_trident_niv_egress_t *curr_ptr = NULL, *temp_ptr = NULL;
   5425     int nh_index;
   5426     bcm_module_t mod_out;
   5427     bcm_port_t port_out;
   5428     bcm_trunk_t tgid_out;
   5429     int id_out;
   5430     bcm_port_t local_member_array[SOC_MAX_NUM_PORTS];
   5431     int local_member_count;
   5432     int i;
   5433     int mod_local = FALSE;
   5434     bcm_l3_egress_t nh_info;
   5435     uint32 nh_flags;
   5436     bcm_port_t local_port;
   5437     bcm_gport_t gport;
   5438     _bcm_trident_niv_sd_tag_t niv_sd_tag;
   5439     bcm_if_t intf;
   5440     int      alloc_size;
   5441     uint16   hash_val;
   5442     int      bkt_idx = 0;
   5443     int      multicast;
   5444 #ifdef BCM_TRIDENT2_SUPPORT    
   5445     int vp_routing = FALSE;
   5446 #endif
   5447 #if defined(BCM_HGPROXY_COE_SUPPORT)
   5448     int is_local_subport = FALSE;
   5449 #endif
   5450 
   5451 
   5452     /* Verify niv_port is a valid NIV port with no match criteria */
   5453     if (!BCM_GPORT_IS_NIV_PORT(niv_port)) {
   5454         return BCM_E_PARAM;
   5455     }
   5456     vp = BCM_GPORT_NIV_PORT_ID_GET(niv_port);
   5457     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   5458         return BCM_E_NOT_FOUND;
   5459     }
   5460     if (!(NIV_PORT_INFO(unit, vp)->flags & BCM_NIV_PORT_MATCH_NONE)) {
   5461         return BCM_E_PARAM;
   5462     }
   5463 
   5464     if (niv_egress == NULL) {
   5465         return BCM_E_PARAM;
   5466     }
   5467 
   5468 #ifdef BCM_TRIDENT2_SUPPORT
   5469     if (soc_feature(unit, soc_feature_virtual_port_routing)) {
   5470         vp_routing = TRUE;    
   5471     }
   5472 #endif
   5473 
   5474     if (!(niv_egress->flags & BCM_NIV_EGRESS_MULTICAST)) {
   5475         /* When adding a unicast NIV egress object to a NIV port,
   5476          * check that there are no other NIV egress objects on the
   5477          * NIV port's egress_list. A NIV port cannot be overloaded
   5478          * with multiple unicast NIV egress objects.
   5479          */
   5480         if (NULL != NIV_PORT_INFO(unit, vp)->egress_list) {
   5481             return BCM_E_CONFIG;
   5482         }
   5483         /* BCM_NIV_EGRESS_L3 must be with BCM_NIV_EGRESS_MULTICAST */
   5484         if (niv_egress->flags & BCM_NIV_EGRESS_L3) {
   5485             return BCM_E_PARAM;
   5486         }
   5487     } else {
   5488         /* For a multicast NIV egress object, the field
   5489          * match_vlan is not applicable.
   5490          */
   5491         if (niv_egress->match_vlan) {
   5492            return BCM_E_PARAM;
   5493         } 
   5494 #ifdef BCM_TRIDENT2_SUPPORT
   5495         if (vp_routing) {
   5496         } else
   5497 #endif
   5498         {
   5499             if (niv_egress->flags & BCM_NIV_EGRESS_L3) {
   5500                 return BCM_E_UNAVAIL;
   5501             }
   5502         }
   5503        
   5504     }
   5505 
   5506     BCM_PBMP_CLEAR(new_pbmp);
   5507     BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, niv_egress->port,
   5508                 &mod_out, &port_out, &tgid_out, &id_out));
   5509     if (BCM_TRUNK_INVALID != tgid_out) {
   5510         BCM_IF_ERROR_RETURN(_bcm_esw_trunk_local_members_get(unit,
   5511                     tgid_out, SOC_MAX_NUM_PORTS, local_member_array,
   5512                     &local_member_count));
   5513 
   5514         /*
   5515          * For multicast, it will be unnecessary to create next hop
   5516          * if there is no local port member. 
   5517          */
   5518         if (niv_egress->flags & BCM_NIV_EGRESS_MULTICAST) {
   5519             if (local_member_count <= 0) {
   5520                 return BCM_E_NONE;
   5521             } 
   5522         }
   5523  
   5524         for (i = 0; i < local_member_count; i++) {
   5525             BCM_PBMP_PORT_ADD(new_pbmp, local_member_array[i]);
   5526         }
   5527     } else {
   5528 #if defined(BCM_HGPROXY_COE_SUPPORT)
   5529         BCM_IF_ERROR_RETURN(
   5530             _bcm_esw_port_is_local_subport(
   5531                 unit, niv_egress->port, mod_out, port_out,
   5532                 &is_local_subport, &port_out));
   5533         if (is_local_subport) {
   5534             mod_local = TRUE;
   5535         } else
   5536 #endif
   5537         {
   5538             BCM_IF_ERROR_RETURN(
   5539                 _bcm_esw_modid_is_local(unit, mod_out, &mod_local));
   5540         }
   5541  
   5542         /*
   5543          * For multicast, it will be unnecessary to create next hop
   5544          * if there is no local port member. 
   5545          */
   5546         if (niv_egress->flags & BCM_NIV_EGRESS_MULTICAST) {
   5547             if (!mod_local) {
   5548                 return BCM_E_NONE;
   5549             }
   5550         }
   5551  
   5552         if (mod_local) {
   5553             BCM_PBMP_PORT_ADD(new_pbmp, port_out);
   5554         } else {
   5555             return BCM_E_PORT;
   5556         }
   5557     }
   5558 
   5559     /* Traverse NIV port's existing list of NIV egress objects.
   5560      * If an existing egress object has the same multicast flag,
   5561      * virtual_interface_id, match_vlan, and SD-tag but different port,
   5562      * its next hop index can be shared with the new NIV egress object.
   5563      * Also, create a bitmap of the physical ports on which the VP resides.
   5564      */ 
   5565     BCM_PBMP_CLEAR(existing_pbmp);
   5566     shared_nh_found = FALSE;
   5567     curr_ptr = NIV_PORT_INFO(unit, vp)->egress_list;
   5568     if (niv_egress->flags & BCM_NIV_EGRESS_MULTICAST) {
   5569         BCM_IF_ERROR_RETURN(
   5570             _bcm_trident_niv_egress_hash_calc(unit, (void *)niv_egress,
   5571                                               &hash_val));
   5572         bkt_idx  = hash_val % TD_NIV_PORT_HASH_BKT_SIZE;
   5573         if (NIV_PORT_INFO(unit, vp)->egress_list != NULL) {
   5574             curr_ptr = NIV_PORT_HASH_BKT(unit, vp, bkt_idx)->next;
   5575         }
   5576     }
   5577     while (NULL != curr_ptr) {
   5578         /* Determine if the attributes of the current NIV egress object match
   5579          * those of the new NIV egress object, except for the port attribute.
   5580          */ 
   5581         BCM_IF_ERROR_RETURN(_bcm_trident_niv_egress_match_ex_port(unit,
   5582                     niv_egress, curr_ptr, &match_ex_port));
   5583         if (match_ex_port) {
   5584             /* Check if ports also match. If so, the NIV egress object
   5585              * already exists.
   5586              */
   5587             BCM_IF_ERROR_RETURN(_bcm_trident_local_port_match(unit,
   5588                         niv_egress->port, curr_ptr->port, &local_port_match));
   5589             if (local_port_match) {
   5590                 return BCM_E_EXISTS;
   5591             }
   5592 
   5593             /* If ports don't match, the next hop index can be shared. */
   5594             shared_nh_found = TRUE;
   5595             nh_index = curr_ptr->next_hop_index;
   5596             break;
   5597         }
   5598         /* Advance to next NIV egress object */
   5599         curr_ptr = curr_ptr->next;
   5600     }
   5601 
   5602     if (!shared_nh_found) {
   5603         /* If match not found, allocate a new next hop index. */
   5604         bcm_l3_egress_t_init(&nh_info);
   5605         nh_flags = _BCM_L3_SHR_MATCH_DISABLE | _BCM_L3_SHR_WRITE_DISABLE;
   5606         BCM_IF_ERROR_RETURN
   5607             (bcm_xgs3_nh_add(unit, nh_flags, &nh_info, &nh_index));
   5608 
   5609         /* Configure next hop entry */
   5610 #ifdef BCM_TRIDENT2_SUPPORT
   5611         if (niv_egress->flags & BCM_NIV_EGRESS_L3) {
   5612             /* Configure next hop entry for L3MC */ 
   5613             BCM_IF_ERROR_RETURN
   5614                 (_bcm_trident_niv_l3mc_nh_info_set(unit, nh_index, 
   5615                     niv_egress->flags, niv_egress->multicast_flags, 
   5616                     niv_egress->port, niv_egress->intf, 
   5617                     niv_egress->virtual_interface_id, vp, 
   5618                     (niv_egress->flags & BCM_NIV_VNTAG_L_BIT_FORCE_1) ? 1 : 0));
   5619         }
   5620         else 
   5621 #endif
   5622         {
   5623             sal_memset(&niv_sd_tag, 0, sizeof(niv_sd_tag));
   5624             niv_sd_tag.flags = niv_egress->flags;
   5625             niv_sd_tag.service_tpid = niv_egress->service_tpid;
   5626             niv_sd_tag.service_vlan = niv_egress->service_vlan;
   5627             niv_sd_tag.service_pri  = niv_egress->service_pri;
   5628             niv_sd_tag.service_cfi  = niv_egress->service_cfi;
   5629             niv_sd_tag.service_qos_map_id = niv_egress->service_qos_map_id;
   5630             multicast = (niv_egress->flags & BCM_NIV_EGRESS_MULTICAST) ?
   5631                             ((niv_egress->flags & BCM_NIV_EGRESS_P_BIT_CLEAR) ?
   5632                                  0 : 1) : 0;
   5633             BCM_IF_ERROR_RETURN
   5634                 (_bcm_trident_niv_nh_info_set(unit, nh_index, multicast,
   5635                     niv_egress->port, niv_egress->virtual_interface_id,
   5636                     niv_egress->match_vlan, &niv_sd_tag, vp, 
   5637                     (niv_egress->flags & BCM_NIV_VNTAG_L_BIT_FORCE_1) ? 1 : 0));
   5638         }
   5639     } else {
   5640         /* Increment next hop's reference count */
   5641         _bcm_xgs3_nh_ref_cnt_incr(unit, nh_index);
   5642     }
   5643 
   5644     /* Update next hop index in ING_DVP_TABLE */
   5645     intf = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit) + nh_index;
   5646     BCM_IF_ERROR_RETURN(
   5647         _bcm_vp_ing_dvp_config(unit, _bcmVpIngDvpConfigUpdate, vp, 
   5648                                ING_DVP_CONFIG_INVALID_VP_TYPE, intf, 
   5649                                ING_DVP_CONFIG_INVALID_PORT_TYPE));
   5650 
   5651     /* Configure ingress VLAN translation table for unicast
   5652      * NIV egress object.
   5653      */
   5654     if (!(niv_egress->flags & BCM_NIV_EGRESS_MULTICAST)) {
   5655         BCM_IF_ERROR_RETURN(_bcm_trident_niv_match_add(unit,
   5656                     niv_egress->port, niv_egress->virtual_interface_id,
   5657                     niv_egress->match_vlan, vp));
   5658     }
   5659 
   5660     /* Increment the VP count on the new NIV egress object's physical
   5661      * port(s), unless the physical port(s) match those of VP's
   5662      * other NIV egress objects.
   5663      */
   5664     
   5665     if (niv_egress->flags & BCM_NIV_EGRESS_MULTICAST) {
   5666         _bcm_trident_niv_egress_pbmp_get(unit, vp, &existing_pbmp);
   5667     }
   5668     BCM_PBMP_CLEAR(update_pbmp);
   5669     BCM_PBMP_ASSIGN(update_pbmp, new_pbmp);
   5670     BCM_PBMP_REMOVE(update_pbmp, existing_pbmp);
   5671     BCM_PBMP_ITER(update_pbmp, local_port) {
   5672         BCM_IF_ERROR_RETURN
   5673             (bcm_esw_port_gport_get(unit, local_port, &gport));
   5674         BCM_IF_ERROR_RETURN
   5675             (_bcm_trident_niv_port_cnt_update(unit, gport, vp, TRUE, FALSE));
   5676     }
   5677 
   5678     if (niv_egress->flags & BCM_NIV_EGRESS_MULTICAST) {
   5679         BCM_IF_ERROR_RETURN(
   5680             _bcm_trident_niv_egress_pbmp_add(unit, vp, new_pbmp));
   5681     }
   5682 
   5683     /* Insert the new NIV egress object into VP's egress object list */
   5684     curr_ptr = sal_alloc(sizeof(_bcm_trident_niv_egress_t),
   5685             "NIV egress object");
   5686     if (NULL == curr_ptr) {
   5687         return BCM_E_MEMORY;
   5688     }
   5689     sal_memset(curr_ptr, 0, sizeof(_bcm_trident_niv_egress_t));
   5690     curr_ptr->flags = niv_egress->flags;
   5691     curr_ptr->port = niv_egress->port;
   5692     curr_ptr->virtual_interface_id = niv_egress->virtual_interface_id;
   5693     curr_ptr->match_vlan = niv_egress->match_vlan;
   5694     curr_ptr->service_tpid = niv_egress->service_tpid;
   5695     curr_ptr->service_vlan = niv_egress->service_vlan;
   5696     curr_ptr->service_pri = niv_egress->service_pri;
   5697     curr_ptr->service_cfi = niv_egress->service_cfi;
   5698     curr_ptr->service_qos_map_id = niv_egress->service_qos_map_id;
   5699     curr_ptr->next_hop_index = nh_index;
   5700     curr_ptr->intf = niv_egress->intf;
   5701     curr_ptr->multicast_flags = niv_egress->multicast_flags;
   5702     if (!(niv_egress->flags & BCM_NIV_EGRESS_MULTICAST)) {
   5703         curr_ptr->next = NIV_PORT_INFO(unit, vp)->egress_list;
   5704         NIV_PORT_INFO(unit, vp)->egress_list = curr_ptr;
   5705     } else {
   5706         if ((NIV_PORT_INFO(unit, vp)->egress_list == NULL)) {
   5707             alloc_size = sizeof(_bcm_trident_niv_egress_t) *
   5708                          TD_NIV_PORT_HASH_BKT_SIZE;
   5709             temp_ptr = sal_alloc(alloc_size, "NIV egress object");
   5710             if (NULL == temp_ptr) {
   5711                 sal_free(curr_ptr);
   5712                 return BCM_E_MEMORY;
   5713             }
   5714             sal_memset(temp_ptr, 0, alloc_size);
   5715             NIV_PORT_INFO(unit, vp)->egress_list = temp_ptr;
   5716         }
   5717         curr_ptr->next = NIV_PORT_HASH_BKT(unit, vp, bkt_idx)->next;
   5718         NIV_PORT_HASH_BKT(unit, vp, bkt_idx)->next = curr_ptr;
   5719     }
   5720 
   5721     /* Set NIV egress object ID */
   5722     if (niv_egress->flags & BCM_NIV_EGRESS_L3) {
   5723         niv_egress->egress_if = nh_index + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   5724     }
   5725     else {    
   5726         niv_egress->egress_if = nh_index + BCM_XGS3_EGRESS_IDX_MIN(unit);
   5727     }
   5728 
   5729     return BCM_E_NONE;
   5730 }
   5731 
   5732 /* Function:
   5733  *      bcm_trident_niv_egress_delete
   5734  * Purpose:
   5735  *      Delete a NIV egress object from a NIV port
   5736  * Parameters:
   5737  *      unit - (IN) SOC unit Number
   5738  *      niv_port - (IN) NIV port
   5739  *      niv_egress - (IN) NIV egress object
   5740  * Returns:
   5741  *      BCM_E_XXX
   5742  */
   5743 int
   5744 bcm_trident_niv_egress_delete(
   5745     int unit, 
   5746     bcm_gport_t niv_port, 
   5747     bcm_niv_egress_t *niv_egress)
   5748 {
   5749     int vp;
   5750     int match_found;
   5751     bcm_pbmp_t remaining_pbmp, pbmp;
   5752     _bcm_trident_niv_egress_t *curr_ptr, *prev_ptr, **head;
   5753     _bcm_trident_niv_egress_t *match_ptr = NULL;
   5754     int local_port_match;
   5755     int match_ex_port;
   5756     bcm_module_t mod_out;
   5757     bcm_port_t port_out;
   5758     bcm_trunk_t tgid_out;
   5759     int id_out;
   5760     bcm_port_t local_member_array[SOC_MAX_NUM_PORTS];
   5761     int local_member_count;
   5762     int i;
   5763     int mod_local = FALSE;
   5764     bcm_port_t local_port;
   5765     bcm_gport_t gport;
   5766     int nh_index;
   5767     bcm_if_t intf;
   5768     uint16   hash_val;
   5769     int      bkt_idx;
   5770 #if defined(BCM_HGPROXY_COE_SUPPORT)
   5771     int is_local_subport = FALSE;
   5772 #endif
   5773 
   5774     /* Verify niv_port is a valid NIV port with no match criteria */
   5775     if (!BCM_GPORT_IS_NIV_PORT(niv_port)) {
   5776         return BCM_E_PARAM;
   5777     }
   5778     vp = BCM_GPORT_NIV_PORT_ID_GET(niv_port);
   5779     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   5780         return BCM_E_NOT_FOUND;
   5781     }
   5782     if (!(NIV_PORT_INFO(unit, vp)->flags & BCM_NIV_PORT_MATCH_NONE)) {
   5783         return BCM_E_PARAM;
   5784     }
   5785 
   5786     if (niv_egress == NULL) {
   5787         return BCM_E_PARAM;
   5788     }
   5789 
   5790     /* Traverse NIV port's list of NIV egress objects to find the egress
   5791      * object to be deleted. Also, among the remaining egress objects,
   5792      * create a bitmap of the physical ports on which the VP resides.
   5793      */ 
   5794     match_found = FALSE;
   5795     BCM_PBMP_CLEAR(remaining_pbmp);
   5796     prev_ptr = NULL;
   5797     if (niv_egress->flags & BCM_NIV_EGRESS_MULTICAST) {
   5798         if ((NIV_PORT_INFO(unit, vp)->egress_list == NULL)) {
   5799             return BCM_E_NOT_FOUND;
   5800         }
   5801         BCM_IF_ERROR_RETURN(
   5802             _bcm_trident_niv_egress_hash_calc(unit, (void *)niv_egress,
   5803                                               &hash_val));
   5804         bkt_idx  = hash_val % TD_NIV_PORT_HASH_BKT_SIZE;
   5805         head = &(NIV_PORT_HASH_BKT(unit, vp, bkt_idx)->next);
   5806     } else {
   5807         head = &(NIV_PORT_INFO(unit, vp)->egress_list);
   5808     }
   5809     curr_ptr = *head;
   5810     while (NULL != curr_ptr) {
   5811         BCM_IF_ERROR_RETURN(_bcm_trident_niv_egress_match_ex_port(unit,
   5812                     niv_egress, curr_ptr, &match_ex_port));
   5813         BCM_IF_ERROR_RETURN(_bcm_trident_local_port_match(unit,
   5814                     niv_egress->port, curr_ptr->port, &local_port_match));
   5815         if (match_ex_port && local_port_match) {
   5816 
   5817             match_found = TRUE;
   5818             match_ptr = curr_ptr;
   5819             if (curr_ptr == *head) {
   5820                 *head = curr_ptr->next;
   5821             } else {
   5822                /* 
   5823                 * In the following line of code, Coverity thinks the
   5824                 * prev_ptr variable may still be NULL when dereferenced.
   5825                 * This situation will never occur because if curr_ptr
   5826                 * is not pointing to the head of the linked list,
   5827                 * prev_ptr would not be NULL.
   5828                 */
   5829                 /* coverity[var_deref_op : FALSE] */
   5830                 prev_ptr->next = curr_ptr->next;
   5831             }
   5832             break;
   5833         } else {
   5834             prev_ptr = curr_ptr;
   5835         }
   5836 
   5837         /* Advance to next NIV egress object */
   5838         curr_ptr = curr_ptr->next;
   5839     }
   5840     if (!match_found) {
   5841         return BCM_E_NOT_FOUND;
   5842     }
   5843 
   5844     /* Delete ingress VLAN translation entry */
   5845     if (!(match_ptr->flags & BCM_NIV_EGRESS_MULTICAST)) {
   5846         BCM_IF_ERROR_RETURN(_bcm_trident_niv_match_delete(unit,
   5847                     match_ptr->port, match_ptr->virtual_interface_id,
   5848                     match_ptr->match_vlan, NULL));
   5849     }
   5850 
   5851     /* If the VP's list of remaining egress objects is empty, modify VP's
   5852      * next hop index to invalid next hop index. If not empty,
   5853      * pick one of the next hop indices in the list.
   5854      */
   5855     if (NULL == *head) {
   5856         nh_index = NIV_INFO(unit)->invalid_next_hop_index;
   5857     } else {
   5858         nh_index = (*head)->next_hop_index;
   5859     }
   5860 
   5861     /* Update next hop index in ING_DVP_TABLE */
   5862     intf = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit) + nh_index;
   5863     BCM_IF_ERROR_RETURN(
   5864         _bcm_vp_ing_dvp_config(unit, _bcmVpIngDvpConfigUpdate, vp, 
   5865                                ING_DVP_CONFIG_INVALID_VP_TYPE, intf, 
   5866                                ING_DVP_CONFIG_INVALID_PORT_TYPE));
   5867 
   5868     /* Decrement next hop's reference count. If count reaches zero,
   5869      * free the next hop index and clear next hop table entries.
   5870      */
   5871     BCM_IF_ERROR_RETURN
   5872         (_bcm_trident_niv_nh_info_delete(unit, match_ptr->next_hop_index));
   5873 
   5874     /* Decrement the VP count on the deleted NIV egress object's physical
   5875      * port(s), unless the physical port(s) are shared by the VP's remaining
   5876      * NIV egress objects.
   5877      */
   5878     BCM_PBMP_CLEAR(pbmp);
   5879     BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, match_ptr->port,
   5880                 &mod_out, &port_out, &tgid_out, &id_out));
   5881     if (BCM_TRUNK_INVALID != tgid_out) {
   5882         BCM_IF_ERROR_RETURN(_bcm_esw_trunk_local_members_get(unit,
   5883                     tgid_out, SOC_MAX_NUM_PORTS, local_member_array,
   5884                     &local_member_count));
   5885         for (i = 0; i < local_member_count; i++) {
   5886             BCM_PBMP_PORT_ADD(pbmp, local_member_array[i]);
   5887         }
   5888     } else {
   5889 #if defined(BCM_HGPROXY_COE_SUPPORT)
   5890         BCM_IF_ERROR_RETURN(
   5891             _bcm_esw_port_is_local_subport(
   5892                 unit, niv_egress->port, mod_out, port_out,
   5893                 &is_local_subport, &port_out));
   5894         if (is_local_subport) {
   5895             mod_local = TRUE;
   5896         } else
   5897 #endif
   5898         {
   5899             BCM_IF_ERROR_RETURN(
   5900                 _bcm_esw_modid_is_local(unit, mod_out, &mod_local));
   5901         }
   5902         if (mod_local) {
   5903             BCM_PBMP_PORT_ADD(pbmp, port_out);
   5904         } else {
   5905             return BCM_E_INTERNAL;
   5906         }
   5907     }
   5908     if (niv_egress->flags & BCM_NIV_EGRESS_MULTICAST) {
   5909         _bcm_trident_niv_egress_pbmp_delete(unit, vp, pbmp);
   5910         _bcm_trident_niv_egress_pbmp_get(unit, vp, &remaining_pbmp);
   5911     }
   5912     BCM_PBMP_REMOVE(pbmp, remaining_pbmp);
   5913     BCM_PBMP_ITER(pbmp, local_port) {
   5914         BCM_IF_ERROR_RETURN
   5915             (bcm_esw_port_gport_get(unit, local_port, &gport));
   5916         BCM_IF_ERROR_RETURN
   5917             (_bcm_trident_niv_port_cnt_update(unit, gport, vp, FALSE, FALSE));
   5918     }
   5919     if ((niv_egress->flags & BCM_NIV_EGRESS_MULTICAST) &&
   5920          BCM_PBMP_IS_NULL(remaining_pbmp)) {
   5921          sal_free(NIV_PORT_INFO(unit, vp)->egress_list);
   5922          NIV_PORT_INFO(unit, vp)->egress_list = NULL;
   5923     }
   5924     /* Free the deleted NIV egress object */
   5925     sal_free(match_ptr);
   5926 
   5927     return BCM_E_NONE;
   5928 }
   5929 
   5930 /* Function:
   5931  *      bcm_trident_niv_egress_set
   5932  * Purpose:
   5933  *      Set an array of NIV egress objects for a NIV port
   5934  * Parameters:
   5935  *      unit - (IN) SOC unit Number
   5936  *      niv_port - (IN) NIV port
   5937  *      array_size - (IN) Number of NIV egress objects
   5938  *      niv_egress_array - (IN/OUT) Array of NIV egress objects. Each NIV
   5939  *                                  egress structure's egress_if field is
   5940  *                                  an output.
   5941  * Returns:
   5942  *      BCM_E_XXX
   5943  */
   5944 int
   5945 bcm_trident_niv_egress_set(
   5946     int unit, 
   5947     bcm_gport_t niv_port, 
   5948     int array_size, 
   5949     bcm_niv_egress_t *niv_egress_array)
   5950 {
   5951     int vp;
   5952     _bcm_trident_niv_egress_t *curr_ptr, *next_ptr;
   5953     bcm_pbmp_t pbmp;
   5954     bcm_module_t mod_out;
   5955     bcm_port_t port_out;
   5956     bcm_trunk_t tgid_out;
   5957     int id_out;
   5958     bcm_port_t local_member_array[SOC_MAX_NUM_PORTS];
   5959     int local_member_count;
   5960     int i;
   5961     int mod_local = FALSE;
   5962     bcm_gport_t gport;
   5963     bcm_port_t local_port;
   5964     bcm_if_t intf;
   5965     int      bkt_idx, bkt_size;
   5966     int      vp_mc = 0;
   5967 #if defined(BCM_HGPROXY_COE_SUPPORT)
   5968     int is_local_subport = FALSE;
   5969 #endif
   5970 
   5971     /* Verify niv_port is a valid NIV port with no match criteria */
   5972     if (!BCM_GPORT_IS_NIV_PORT(niv_port)) {
   5973         return BCM_E_PARAM;
   5974     }
   5975     vp = BCM_GPORT_NIV_PORT_ID_GET(niv_port);
   5976     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   5977         return BCM_E_NOT_FOUND;
   5978     }
   5979     if (!(NIV_PORT_INFO(unit, vp)->flags & BCM_NIV_PORT_MATCH_NONE)) {
   5980         return BCM_E_PARAM;
   5981     }
   5982 
   5983     if ((array_size > 0) && (niv_egress_array == NULL)) {
   5984         return BCM_E_PARAM;
   5985     }
   5986 
   5987     /* Modify VP's next hop index to invalid next hop index */
   5988     intf = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit) + NIV_INFO(unit)->invalid_next_hop_index;
   5989     BCM_IF_ERROR_RETURN(_bcm_vp_ing_dvp_config(unit, _bcmVpIngDvpConfigUpdate,
   5990                         vp, ING_DVP_CONFIG_INVALID_VP_TYPE, intf, 
   5991                         ING_DVP_CONFIG_INVALID_PORT_TYPE));
   5992 
   5993     /* Delete the existing NIV egress objects attached to the given NIV port */
   5994     if (NIV_PORT_MC_NH_INFO(unit, vp) != NULL) {
   5995         /* The shared vp associates with mulicast egress objects. */
   5996         if (NIV_PORT_INFO(unit, vp)->egress_list == NULL) {
   5997             return BCM_E_INTERNAL;
   5998         }
   5999         vp_mc = 1;
   6000     }
   6001     BCM_PBMP_CLEAR(pbmp);
   6002     bkt_size = vp_mc ? TD_NIV_PORT_HASH_BKT_SIZE : 1;
   6003     for (bkt_idx = 0; bkt_idx < bkt_size; bkt_idx++) {
   6004         if (vp_mc) {
   6005             curr_ptr = NIV_PORT_HASH_BKT(unit, vp, bkt_idx)->next;
   6006         } else {
   6007             curr_ptr = NIV_PORT_INFO(unit, vp)->egress_list;
   6008         }
   6009         while (NULL != curr_ptr) {
   6010             /* Delete ingress VLAN translation entry */
   6011             if (!(curr_ptr->flags & BCM_NIV_EGRESS_MULTICAST)) {
   6012                 BCM_IF_ERROR_RETURN(_bcm_trident_niv_match_delete(unit,
   6013                             curr_ptr->port, curr_ptr->virtual_interface_id,
   6014                             curr_ptr->match_vlan, NULL));
   6015             }
   6016 
   6017             /* Decrement next hop's reference count. If count reaches zero,
   6018              * free the next hop index and clear next hop table entries.
   6019              */
   6020             BCM_IF_ERROR_RETURN
   6021                 (_bcm_trident_niv_nh_info_delete(unit, curr_ptr->next_hop_index));
   6022 
   6023             /* Add this NIV egress object's port(s) to the bitmap of physical ports
   6024              * on which the VP resides.
   6025              */
   6026             BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, curr_ptr->port,
   6027                         &mod_out, &port_out, &tgid_out, &id_out));
   6028             if (BCM_TRUNK_INVALID != tgid_out) {
   6029                 BCM_IF_ERROR_RETURN(_bcm_esw_trunk_local_members_get(unit,
   6030                             tgid_out, SOC_MAX_NUM_PORTS, local_member_array,
   6031                             &local_member_count));
   6032                 for (i = 0; i < local_member_count; i++) {
   6033                     BCM_PBMP_PORT_ADD(pbmp, local_member_array[i]);
   6034                 }
   6035             } else {
   6036 #if defined(BCM_HGPROXY_COE_SUPPORT)
   6037                 BCM_IF_ERROR_RETURN(
   6038                     _bcm_esw_port_is_local_subport(
   6039                         unit, curr_ptr->port, mod_out, port_out,
   6040                         &is_local_subport, &port_out));
   6041                 if (is_local_subport) {
   6042                     mod_local = TRUE;
   6043                 } else
   6044 #endif
   6045                 {
   6046                     BCM_IF_ERROR_RETURN(
   6047                         _bcm_esw_modid_is_local(unit, mod_out, &mod_local));
   6048                 }
   6049                 if (mod_local) {
   6050                     BCM_PBMP_PORT_ADD(pbmp, port_out);
   6051                 } else {
   6052                     return BCM_E_INTERNAL;
   6053                 }
   6054             }
   6055 
   6056             /* Free current NIV egress object and advance to the next one */
   6057             next_ptr = curr_ptr->next;
   6058             sal_free(curr_ptr);
   6059             curr_ptr = next_ptr;
   6060         }
   6061         
   6062         if (vp_mc) {
   6063             NIV_PORT_HASH_BKT(unit, vp, bkt_idx)->next = NULL;
   6064         } else {
   6065             NIV_PORT_INFO(unit, vp)->egress_list = NULL;
   6066         }
   6067     }
   6068     
   6069     if (vp_mc) {
   6070         sal_free(NIV_PORT_INFO(unit, vp)->egress_list);
   6071         NIV_PORT_INFO(unit, vp)->egress_list = NULL;
   6072         _bcm_trident_niv_egress_pbmp_clear(unit, vp);
   6073     }
   6074     
   6075     /* Decrement VP count on all the physical ports on which the VP resides */
   6076     BCM_PBMP_ITER(pbmp, local_port) {
   6077         BCM_IF_ERROR_RETURN
   6078             (bcm_esw_port_gport_get(unit, local_port, &gport));
   6079         BCM_IF_ERROR_RETURN
   6080             (_bcm_trident_niv_port_cnt_update(unit, gport, vp, FALSE, FALSE));
   6081     }
   6082 
   6083     /* Add new NIV egress objects to NIV port */
   6084     for (i = 0; i < array_size; i++) {
   6085         BCM_IF_ERROR_RETURN
   6086             (bcm_trident_niv_egress_add(unit, niv_port, &niv_egress_array[i]));
   6087     }
   6088 
   6089     return BCM_E_NONE;
   6090 }
   6091 
   6092 /* Function:
   6093  *      bcm_trident_niv_egress_get
   6094  * Purpose:
   6095  *      Get an array of NIV egress objects for a NIV port
   6096  * Parameters:
   6097  *      unit - (IN) SOC unit Number
   6098  *      niv_port - (IN) NIV port
   6099  *      array_size - (IN) Size of NIV egress objects array.
   6100  *      niv_egress_array - (OUT) Array of NIV egress objects.
   6101  *      count - (OUT) Number of NIV egress objects returned.
   6102  * Returns:
   6103  *      BCM_E_XXX
   6104  */
   6105 int
   6106 bcm_trident_niv_egress_get(
   6107     int unit, 
   6108     bcm_gport_t niv_port, 
   6109     int array_size, 
   6110     bcm_niv_egress_t *niv_egress_array,
   6111     int *count)
   6112 {
   6113     int vp;
   6114     _bcm_trident_niv_egress_t *curr_ptr;
   6115     int bkt_idx, bkt_size;
   6116     int vp_mc = 0;
   6117 
   6118     /* Verify niv_port is a valid NIV port with no match criteria */
   6119     if (!BCM_GPORT_IS_NIV_PORT(niv_port)) {
   6120         return BCM_E_PARAM;
   6121     }
   6122     vp = BCM_GPORT_NIV_PORT_ID_GET(niv_port);
   6123     if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   6124         return BCM_E_NOT_FOUND;
   6125     }
   6126     if (!(NIV_PORT_INFO(unit, vp)->flags & BCM_NIV_PORT_MATCH_NONE)) {
   6127         return BCM_E_PARAM;
   6128     }
   6129 
   6130     if (array_size > 0 && niv_egress_array == NULL) {
   6131         return BCM_E_PARAM;
   6132     }
   6133     if (count == NULL) {
   6134         return BCM_E_PARAM;
   6135     }
   6136 
   6137     /* Traverse NIV port's existing list of NIV egress objects */
   6138     *count = 0;
   6139     curr_ptr = NIV_PORT_INFO(unit, vp)->egress_list;
   6140 
   6141     if (NIV_PORT_MC_NH_INFO(unit, vp) != NULL) {
   6142         /* The shared vp associates with mulicast egress objects. */
   6143         if (NIV_PORT_INFO(unit, vp)->egress_list == NULL) {
   6144             return BCM_E_INTERNAL;
   6145         }
   6146         vp_mc = 1;
   6147     }
   6148     bkt_size = vp_mc ? TD_NIV_PORT_HASH_BKT_SIZE : 1;
   6149     if (array_size == BCM_NIV_GET_ONE_EGR_OBJECT) {
   6150         for (bkt_idx = 0; bkt_idx < bkt_size; bkt_idx++) {
   6151             if (vp_mc) {
   6152                 curr_ptr = NIV_PORT_HASH_BKT(unit, vp, bkt_idx)->next;
   6153             } else {
   6154                 curr_ptr = NIV_PORT_INFO(unit, vp)->egress_list;
   6155             }            
   6156             while (NULL != curr_ptr) {
   6157                 if ((niv_egress_array[0].port == curr_ptr->port) &&
   6158                     (niv_egress_array[0].virtual_interface_id ==
   6159                      curr_ptr->virtual_interface_id) &&
   6160                     (niv_egress_array[0].flags == curr_ptr->flags)) {
   6161                     niv_egress_array[0].port = curr_ptr->port;
   6162                     niv_egress_array[0].virtual_interface_id =
   6163                         curr_ptr->virtual_interface_id;
   6164                     niv_egress_array[0].match_vlan = curr_ptr->match_vlan;
   6165                     niv_egress_array[0].service_tpid = curr_ptr->service_tpid;
   6166                     niv_egress_array[0].service_vlan = curr_ptr->service_vlan;
   6167                     niv_egress_array[0].service_pri = curr_ptr->service_pri;
   6168                     niv_egress_array[0].service_cfi = curr_ptr->service_cfi;
   6169                     niv_egress_array[0].service_qos_map_id =
   6170                         curr_ptr->service_qos_map_id;
   6171                     niv_egress_array[0].intf = curr_ptr->intf;
   6172                     niv_egress_array[0].multicast_flags =
   6173                         curr_ptr->multicast_flags;
   6174                     
   6175                     niv_egress_array[0].egress_if = curr_ptr->next_hop_index +
   6176                                                     BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);                  
   6177                     *count = 1;
   6178                     return BCM_E_NONE;
   6179                 } else {
   6180                     curr_ptr = curr_ptr->next;
   6181                 }   
   6182             }
   6183         } 
   6184         return BCM_E_NOT_FOUND;
   6185     } 
   6186 
   6187     for (bkt_idx = 0; bkt_idx < bkt_size; bkt_idx++) {
   6188         if (vp_mc) {
   6189             curr_ptr = NIV_PORT_HASH_BKT(unit, vp, bkt_idx)->next;
   6190         } else {
   6191             curr_ptr = NIV_PORT_INFO(unit, vp)->egress_list;
   6192         }
   6193         while (NULL != curr_ptr) {
   6194             if (array_size > 0) {
   6195                 niv_egress_array[*count].flags = curr_ptr->flags;
   6196                 niv_egress_array[*count].port = curr_ptr->port;
   6197                 niv_egress_array[*count].virtual_interface_id =
   6198                     curr_ptr->virtual_interface_id;
   6199                 niv_egress_array[*count].match_vlan = curr_ptr->match_vlan;
   6200                 niv_egress_array[*count].service_tpid = curr_ptr->service_tpid;
   6201                 niv_egress_array[*count].service_vlan = curr_ptr->service_vlan;
   6202                 niv_egress_array[*count].service_pri = curr_ptr->service_pri;
   6203                 niv_egress_array[*count].service_cfi = curr_ptr->service_cfi;
   6204                 niv_egress_array[*count].service_qos_map_id =
   6205                     curr_ptr->service_qos_map_id;            
   6206                 niv_egress_array[*count].intf = curr_ptr->intf;
   6207                 niv_egress_array[*count].multicast_flags = 
   6208                     curr_ptr->multicast_flags;
   6209                 if (curr_ptr->flags & BCM_NIV_EGRESS_L3) {
   6210                     niv_egress_array[*count].egress_if =
   6211                         curr_ptr->next_hop_index + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit);
   6212                 } else {    
   6213                     niv_egress_array[*count].egress_if =
   6214                         curr_ptr->next_hop_index + BCM_XGS3_EGRESS_IDX_MIN(unit);
   6215                 }                
   6216             }
   6217             (*count)++;
   6218             if (*count == array_size) {
   6219                 break;
   6220             }
   6221             curr_ptr = curr_ptr->next;
   6222         }
   6223         if ((array_size != 0) && (*count == array_size)) {
   6224             break;
   6225         }
   6226     }
   6227     return BCM_E_NONE;
   6228 }
   6229 
   6230 #ifndef BCM_SW_STATE_DUMP_DISABLE
   6231 /*
   6232  * Function:
   6233  *     _bcm_niv_sw_dump
   6234  * Purpose:
   6235  *     Displays NIV information maintained by software.
   6236  * Parameters:
   6237  *     unit - Device unit number
   6238  * Returns:
   6239  *     None
   6240  */
   6241 void
   6242 bcm_trident_niv_sw_dump(int unit)
   6243 {
   6244     int i, num_vp;
   6245     _bcm_trident_niv_egress_t *curr_ptr;
   6246     int egr_obj_index;
   6247     char pfmt[SOC_PBMP_FMT_LEN];
   6248     int  bkt_idx, bkt_size;
   6249     int  vp_mc = 0;
   6250     bcm_pbmp_t pbmp;
   6251 
   6252     LOG_CLI((BSL_META_U(unit,
   6253                         "\nSW Information NIV - Unit %d\n"), unit));
   6254 
   6255     num_vp = soc_mem_index_count(unit, SOURCE_VPm);
   6256 
   6257     LOG_CLI((BSL_META_U(unit,
   6258                         "\n  Port Info    : \n")));
   6259     for (i = 0; i < num_vp; i++) {
   6260         if (!(NIV_PORT_INFO(unit, i)->flags & BCM_NIV_PORT_MATCH_NONE)) {
   6261             if (NIV_PORT_INFO(unit, i)->port == 0) {
   6262                 continue;
   6263             }
   6264             LOG_CLI((BSL_META_U(unit,
   6265                                 "\n  NIV port vp = %d\n"), i));
   6266             LOG_CLI((BSL_META_U(unit,
   6267                                 "    Flags = 0x%x\n"), NIV_PORT_INFO(unit, i)->flags));
   6268             LOG_CLI((BSL_META_U(unit,
   6269                                 "    Port = 0x%x\n"), NIV_PORT_INFO(unit, i)->port));
   6270             LOG_CLI((BSL_META_U(unit,
   6271                                 "    Trunk member bitmap = %s\n"), 
   6272                      SOC_PBMP_FMT(NIV_PORT_INFO(unit, i)->tp_pbmp, pfmt)));
   6273             LOG_CLI((BSL_META_U(unit,
   6274                                 "    Virtual Interface ID = 0x%x\n"),
   6275                      NIV_PORT_INFO(unit, i)->virtual_interface_id));
   6276             LOG_CLI((BSL_META_U(unit,
   6277                                 "    Match VLAN = 0x%x\n"),
   6278                      NIV_PORT_INFO(unit, i)->match_vlan));
   6279         } else {
   6280             LOG_CLI((BSL_META_U(unit,
   6281                                 "\n  NIV port vp = %d\n"), i));
   6282             LOG_CLI((BSL_META_U(unit,
   6283                                 "    Flags = 0x%x\n"), NIV_PORT_INFO(unit, i)->flags));
   6284 
   6285             egr_obj_index = 0;
   6286             vp_mc = 0;
   6287             if (NIV_PORT_MC_NH_INFO(unit, i) != NULL) {
   6288                 if (NIV_PORT_INFO(unit, i)->egress_list == NULL) {
   6289                     continue;
   6290                 }
   6291                 vp_mc = 1;
   6292             }
   6293             bkt_size = vp_mc ? TD_NIV_PORT_HASH_BKT_SIZE : 1;
   6294             for (bkt_idx = 0; bkt_idx < bkt_size; bkt_idx++) {
   6295                 /* The shared vp associates with mulicast egress objects. */
   6296                 if (vp_mc) {
   6297                     curr_ptr = NIV_PORT_HASH_BKT(unit, i, bkt_idx)->next;
   6298                     if (curr_ptr) {
   6299                         LOG_CLI((BSL_META_U(unit,
   6300                                             "\n  Bkt_idx = %d\n"), bkt_idx));
   6301                     }
   6302                 } else {
   6303                     curr_ptr = NIV_PORT_INFO(unit, i)->egress_list;
   6304                 }
   6305                 while (NULL != curr_ptr) {
   6306                     LOG_CLI((BSL_META_U(unit,
   6307                                         "    Egress object %d\n"),
   6308                                         egr_obj_index));
   6309                     LOG_CLI((BSL_META_U(unit,
   6310                                         "      Flags = 0x%x\n"),
   6311                                         curr_ptr->flags));
   6312                     LOG_CLI((BSL_META_U(unit,
   6313                                         "      Port = 0x%x\n"),
   6314                                         curr_ptr->port));
   6315                     LOG_CLI((BSL_META_U(unit,
   6316                                         "      Virtual Interface ID = 0x%x\n"),
   6317                              curr_ptr->virtual_interface_id));
   6318                     LOG_CLI((BSL_META_U(unit,
   6319                                         "      Match VLAN = 0x%x\n"),
   6320                              curr_ptr->match_vlan));
   6321                     LOG_CLI((BSL_META_U(unit,
   6322                                         "      Service TPID = 0x%x\n"),
   6323                              curr_ptr->service_tpid));
   6324                     LOG_CLI((BSL_META_U(unit,
   6325                                         "      Service VLAN = 0x%x\n"),
   6326                              curr_ptr->service_vlan));
   6327                     LOG_CLI((BSL_META_U(unit,
   6328                                         "      Service PRI = 0x%x\n"),
   6329                              curr_ptr->service_pri));
   6330                     LOG_CLI((BSL_META_U(unit,
   6331                                         "      Service CFI = 0x%x\n"),
   6332                              curr_ptr->service_cfi));
   6333                     LOG_CLI((BSL_META_U(unit,
   6334                                         "      Service Qos Map ID = 0x%x\n"),
   6335                              curr_ptr->service_qos_map_id));
   6336                     LOG_CLI((BSL_META_U(unit,
   6337                                         "      Next Hop Index = 0x%x\n"),
   6338                              curr_ptr->next_hop_index));
   6339                     LOG_CLI((BSL_META_U(unit,
   6340                                         "      L3 Intf = 0x%x\n"),
   6341                              curr_ptr->intf));
   6342                     LOG_CLI((BSL_META_U(unit,
   6343                                         "      Multicast_flags = 0x%x\n"),
   6344                              curr_ptr->multicast_flags));
   6345                     egr_obj_index++;
   6346                     curr_ptr = curr_ptr->next;
   6347                 }
   6348             }
   6349 
   6350             if (vp_mc) {
   6351                 BCM_PBMP_CLEAR(pbmp);
   6352                 _bcm_trident_niv_egress_pbmp_get(unit, i, &pbmp);
   6353                 LOG_CLI((BSL_META_U(unit,
   6354                                     "      pbmp = %s\n"),
   6355                          SOC_PBMP_FMT(pbmp, pfmt)));
   6356             }
   6357         }
   6358     }
   6359 
   6360     return;
   6361 }
   6362 #endif /* BCM_SW_STATE_DUMP_DISABLE */
   6363 
   6364 #ifdef BCM_TOMAHAWK_SUPPORT
   6365 bcm_error_t
   6366 _bcm_niv_gport_get(int unit, int is_trunk, int modid,
   6367                    int port, int dst_vif, bcm_gport_t *niv_gport)
   6368 {
   6369     int vp;
   6370     bcm_trunk_t trunk_id = -1;
   6371     bcm_port_t local_port_id;
   6372     bcm_module_t local_modid;
   6373     int id_out;
   6374     int dst_vif_match = 0;
   6375     _bcm_trident_niv_egress_t *curr_ptr = NULL;
   6376     if (NULL == niv_gport) {
   6377         return BCM_E_PARAM;
   6378     }
   6379     if (NULL == NIV_INFO(unit)->port_info) {
   6380         return BCM_E_INTERNAL;
   6381     }
   6382 
   6383     for (vp = soc_mem_index_min(unit, SOURCE_VPm);
   6384          vp <= soc_mem_index_max(unit, SOURCE_VPm);
   6385          vp++) {
   6386         if (_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) {
   6387             curr_ptr =  NIV_PORT_INFO(unit, vp)->egress_list;
   6388             dst_vif_match = 0;
   6389             if (!(NIV_PORT_INFO(unit, vp)->flags & BCM_NIV_PORT_MULTICAST)) {
   6390                 if (NULL != curr_ptr) {
   6391                     BCM_IF_ERROR_RETURN
   6392                         (_bcm_esw_gport_resolve(unit, curr_ptr->port, &local_modid,
   6393                                                 &local_port_id, &trunk_id,
   6394                                                 &id_out));
   6395                     if (curr_ptr->virtual_interface_id == dst_vif) {
   6396                         dst_vif_match = 1;
   6397                     }
   6398                 } else {
   6399                     BCM_IF_ERROR_RETURN
   6400                         (_bcm_esw_gport_resolve(unit, NIV_PORT_INFO(unit, vp)->port,
   6401                                                 &local_modid,
   6402                                                 &local_port_id,
   6403                                                 &trunk_id,
   6404                                                 &id_out));                    
   6405                     if (NIV_PORT_INFO(unit, vp)->virtual_interface_id == dst_vif) {
   6406                         dst_vif_match = 1;
   6407                     }
   6408                 }
   6409                 
   6410                 if (dst_vif_match) {
   6411                     if ((is_trunk == 1) && (trunk_id == port)) {
   6412                         BCM_GPORT_NIV_PORT_ID_SET(*niv_gport, vp);
   6413                         return BCM_E_NONE;
   6414                     } else if ((is_trunk != 1) && (trunk_id == -1)) {
   6415                         if ((local_port_id == port) &&
   6416                             (local_modid == modid )) {
   6417                             BCM_GPORT_NIV_PORT_ID_SET(*niv_gport, vp);
   6418                             return BCM_E_NONE;
   6419                         }
   6420                     }
   6421                  }
   6422              }
   6423          }
   6424      }
   6425     return BCM_E_NOT_FOUND;
   6426 }
   6427 #endif /* BCM_TOMAHAWK_SUPPORT */
   6428 #endif /* BCM_TRIDENT_SUPPORT && INCLUDE_L3 */