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

subport.c (107324B)


      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:    subport.c
      8  * Purpose: Triumph SUBPORT functions
      9  */
     10 
     11 #include <soc/defs.h>
     12 #include <sal/core/libc.h>
     13 #include <shared/bsl.h>
     14 #if defined(BCM_TRIUMPH2_SUPPORT) && defined(INCLUDE_L3)
     15 
     16 #include <soc/drv.h>
     17 #include <soc/scache.h>
     18 #include <soc/hash.h>
     19 #include <soc/util.h>
     20 
     21 #include <bcm/error.h>
     22 #include <bcm/subport.h>
     23 
     24 #include <bcm_int/esw/mbcm.h>
     25 #include <bcm_int/esw/firebolt.h>
     26 #include <bcm_int/esw/trx.h>
     27 #include <bcm_int/esw/triumph.h>
     28 #include <bcm_int/esw/stack.h>
     29 #include <bcm_int/esw/l3.h>
     30 #include <bcm_int/esw/virtual.h>
     31 #include <bcm_int/esw/triumph2.h>
     32 #include <bcm_int/esw/subport.h>
     33 
     34 #include <bcm_int/esw_dispatch.h>
     35 
     36 /* Usage bitmap of subport groups (1 group = 8 VPs) */
     37 STATIC SHR_BITDCL *_tr2_group_bitmap[BCM_MAX_NUM_UNITS] = { 0 };
     38 
     39 /* Array of L3_INTF IDs per VP (0xffff means unused) */
     40 STATIC uint16 *_tr2_subport_id[BCM_MAX_NUM_UNITS] = { 0 };
     41 
     42 /* Per-port count of all subports added */
     43 STATIC int _tr2_subport_group_count[BCM_MAX_NUM_UNITS][SOC_MAX_NUM_PORTS] = {{ 0 }};
     44 
     45 /*
     46  * Limited to 4K VPs (instead of actual table size of 8K)
     47  * since the IVID field (12-bits) in EGR_VLAN_XLATE table is 
     48  * used as the DVP value.
     49  */
     50 #define _TR2_SUBPORT_NUM_VP          (4096)
     51 #define _TR2_VP_PER_SUBPORT_GROUP    (8)
     52 #define _TR2_SUBPORT_NUM_GROUP (_TR2_SUBPORT_NUM_VP / _TR2_VP_PER_SUBPORT_GROUP)
     53 
     54 #define _TR2_SUBPORT_VP_MEM_LOCK(unit) \
     55    do { \
     56        if (SOC_IS_TRIUMPH2(unit) || SOC_MEM_IS_VALID(unit, SOURCE_VPm)) { \
     57            MEM_LOCK(unit, SOURCE_VPm); \
     58        } else { \
     59            sal_mutex_take(_tr2_subport_vp_mutex[unit], sal_mutex_FOREVER); \
     60        } \
     61      } while ((0))
     62 
     63 #define _TR2_SUBPORT_VP_MEM_UNLOCK(unit) \
     64    do { \
     65        if (SOC_IS_TRIUMPH2(unit) || SOC_MEM_IS_VALID(unit, SOURCE_VPm)) { \
     66           MEM_UNLOCK(unit, SOURCE_VPm); \
     67        } else { \
     68           sal_mutex_give(_tr2_subport_vp_mutex[unit]); \
     69        } \
     70       } while ((0))
     71 
     72 
     73 STATIC sal_mutex_t _tr2_subport_vp_mutex[BCM_MAX_NUM_UNITS] = {NULL};
     74 
     75 #define _TR2_SUBPORT_CHECK_INIT(_unit_) \
     76         if (!_tr2_group_bitmap[_unit_]) \
     77             return BCM_E_INIT
     78 
     79 STATIC int _bcm_tr2_subport_port_delete(int unit, int l3_idx, int vp);
     80 STATIC int _bcm_tr2_subport_group_destroy(int unit, int vp_base);
     81 
     82 /*
     83  * Subport group usage bitmap operations
     84  */
     85 #define _BCM_TR2_GROUP_USED_GET(_u_, _group_) \
     86         SHR_BITGET(_tr2_group_bitmap[_u_], (_group_))
     87 #define _BCM_TR2_GROUP_USED_SET(_u_, _group_) \
     88         SHR_BITSET(_tr2_group_bitmap[_u_], (_group_))
     89 #define _BCM_TR2_GROUP_USED_CLR(_u_, _group_) \
     90         SHR_BITCLR(_tr2_group_bitmap[_u_], (_group_))
     91 
     92 /*
     93  * Subport port usage bitmap operations
     94  */
     95 #define _BCM_TR2_SUBPORT_ID_GET(_u_, _subport_) \
     96         (_tr2_subport_id[_u_][_subport_])
     97 #define _BCM_TR2_SUBPORT_ID_SET(_u_, _subport_, _id_) \
     98         (_tr2_subport_id[_u_][_subport_] = _id_)
     99 #define _BCM_TR2_SUBPORT_ID_CLR(_u_, _subport_) \
    100         (_tr2_subport_id[_u_][_subport_] = 0xffff)
    101 
    102 #ifdef BCM_KATANA2_SUPPORT
    103 #define _BCM_QOS_MAP_TYPE_MASK                       0x3ff
    104 #define _BCM_QOS_MAP_SHIFT                           10
    105 #define _BCM_QOS_MAP_ING_QUEUE_OFFSET_MAX            7
    106 #define _BCM_QOS_MAP_TYPE_ING_QUEUE_OFFSET_MAP_TABLE 5
    107 #define _EH_TAG_TYPE_ING_QUEUE_MAP                   2
    108 #endif
    109 
    110 /*
    111  * Function Vector
    112  */
    113 static bcm_esw_subport_drv_t bcmi_tr2_subport_drv = {
    114 
    115     /* subport_init                */ bcm_tr2_subport_init,
    116     /* subport_group_create        */ bcm_tr2_subport_group_create,
    117     /* subport_group_get           */ bcm_tr2_subport_group_get,
    118     /* subport_group_traverse      */ NULL,
    119     /* subport_group_destroy       */ bcm_tr2_subport_group_destroy,
    120     /* subport_linkphy_config_set  */ NULL,
    121     /* subport_linkphy_config_get  */ NULL,
    122     /* subport_port_add            */ bcm_tr2_subport_port_add,
    123     /* subport_port_get            */ bcm_tr2_subport_port_get,
    124     /* subport_port_traverse       */ bcm_tr2_subport_port_traverse,
    125     /* subport_port_stat_set       */ NULL,
    126     /* subport_port_stat_get       */ NULL,
    127     /* subport_port_delete         */ bcm_tr2_subport_port_delete,
    128     /* subport_cleanup             */ bcm_tr2_subport_cleanup,
    129 
    130     /* coe_init                */ NULL,
    131     /* coe_group_create        */ NULL,
    132     /* coe_group_get           */ NULL,
    133     /* coe_group_traverse      */ NULL,
    134     /* coe_group_destroy       */ NULL,
    135     /* coe_linkphy_config_set  */ NULL,
    136     /* coe_linkphy_config_get  */ NULL,
    137     /* coe_port_add            */ NULL,
    138     /* coe_port_get            */ NULL,
    139     /* coe_port_traverse       */ NULL,
    140     /* coe_port_stat_set       */ NULL,
    141     /* coe_port_stat_get       */ NULL,
    142     /* coe_port_delete         */ NULL,
    143     /* coe_cleanup             */ NULL
    144 };
    145 
    146 /*
    147  * Function:
    148  *      _bcm_tr_subport_gport_used
    149  * Purpose:
    150  *      Internal function for testing if a gport is a configured subport type
    151  * Parameters:
    152  *      unit    -  (IN) Device number.
    153  *      port -  (IN) Gport
    154  * Returns:
    155  *      BCM_X_XXX
    156  */
    157 int
    158 _bcm_tr2_subport_gport_used(int unit, bcm_gport_t port)
    159 {
    160     int vp;
    161 
    162     _TR2_SUBPORT_VP_MEM_LOCK(unit);
    163     if (BCM_GPORT_IS_SUBPORT_GROUP(port)) {
    164         vp = BCM_GPORT_SUBPORT_GROUP_GET(port);
    165         if ((vp < 0) || (vp > (_TR2_SUBPORT_NUM_VP - 8))) {
    166             _TR2_SUBPORT_VP_MEM_UNLOCK(unit);
    167             return BCM_E_PARAM;
    168         }
    169         if (!_BCM_TR2_GROUP_USED_GET(unit, (vp / 8))) {
    170             _TR2_SUBPORT_VP_MEM_UNLOCK(unit);
    171             return BCM_E_NOT_FOUND;
    172         }
    173     } else if (BCM_GPORT_IS_SUBPORT_PORT(port)) {
    174         vp = BCM_GPORT_SUBPORT_PORT_GET(port);
    175         if (vp >= _TR2_SUBPORT_NUM_VP) {
    176             _TR2_SUBPORT_VP_MEM_UNLOCK(unit);
    177             return BCM_E_PARAM;
    178         }
    179         if (_BCM_TR2_SUBPORT_ID_GET(unit, vp) == 0xffff) {
    180             _TR2_SUBPORT_VP_MEM_UNLOCK(unit);
    181             return BCM_E_NOT_FOUND;
    182         }
    183     }
    184     _TR2_SUBPORT_VP_MEM_UNLOCK(unit);
    185     return BCM_E_NONE;
    186 }
    187 
    188 /*
    189  * Function:
    190  *      _bcm_tr_subport_vp_alloc
    191  * Purpose:
    192  *      Internal function for allocating a group of VPs
    193  * Parameters:
    194  *      unit    -  (IN) Device number.
    195  *      base_vp -  (OUT) Base VP index
    196  * Returns:
    197  *      BCM_X_XXX
    198  */
    199 STATIC int
    200 _bcm_tr2_subport_vp_alloc(int unit, int *base_vp)
    201 {
    202     int i;
    203 /*
    204  * VP allocation is normally done by the MPLS module. However,
    205  * for builds without MPLS support, the VP allocation is done here.
    206  */
    207     if (soc_feature(unit, soc_feature_subport_enhanced)) {
    208        int rv;
    209        _bcm_vp_info_t vp_info;
    210        /* 
    211         * Allocate a group of 8 consecutive VPs since 3-bit prio
    212         * is added to DVP-group to get the final DVP in the L2 lookup.
    213         * Only allocate from the 0 - 4k range since only 12-bits
    214         * are used in the EGR_VLAN_XLATE table key.
    215         * (the IVID field is used as the DVP in EGR_VLAN_XLATE)
    216         */
    217         _bcm_vp_info_init(&vp_info);
    218         vp_info.vp_type = _bcmVpTypeSubport;
    219         rv = _bcm_vp_alloc(unit, 0, 4095, 8, SOURCE_VPm, vp_info, base_vp);
    220         if (rv < 0) {
    221             return rv;
    222         }
    223         _BCM_TR2_GROUP_USED_SET(unit, *base_vp / 8);
    224         return BCM_E_NONE;
    225    }
    226 
    227     _TR2_SUBPORT_VP_MEM_LOCK(unit);
    228     for (i = 0; i < _TR2_SUBPORT_NUM_GROUP; i++) {
    229         if (!_BCM_TR2_GROUP_USED_GET(unit, i)) {
    230             break;
    231         }
    232     }
    233     if (i == _TR2_SUBPORT_NUM_GROUP) {
    234         _TR2_SUBPORT_VP_MEM_UNLOCK(unit);
    235         return BCM_E_RESOURCE;
    236     }
    237     *base_vp = i * 8;
    238 
    239     _BCM_TR2_GROUP_USED_SET(unit, i);
    240     _TR2_SUBPORT_VP_MEM_UNLOCK(unit);
    241     return BCM_E_NONE;
    242 }
    243 
    244 /*
    245  * Function:
    246  *      _bcm_tr_subport_vp_free
    247  * Purpose:
    248  *      Internal function for freeing a group of VPs
    249  * Parameters:
    250  *      unit    -  (IN) Device number.
    251  *      base_vp -  (IN) Base VP index
    252  * Returns:
    253  *      BCM_X_XXX
    254  */
    255 STATIC int
    256 _bcm_tr2_subport_vp_free(int unit, int base_vp)
    257 {
    258 /*
    259  * VP freeing is normally done by the MPLS module. However,
    260  * for builds without MPLS support, the VP free is done here.
    261  */
    262     if (soc_feature(unit, soc_feature_subport_enhanced)) {
    263         int rv;
    264 
    265         rv = _bcm_vp_free(unit, _bcmVpTypeSubport, 8, base_vp);
    266         BCM_IF_ERROR_RETURN (rv);
    267     }
    268 
    269     _BCM_TR2_GROUP_USED_CLR(unit, base_vp / 8);
    270 
    271     return BCM_E_NONE;
    272 }
    273 
    274 STATIC void
    275 _bcm_tr2_subport_free_resource(int unit)
    276 {
    277     if (_tr2_group_bitmap[unit]) {
    278         sal_free(_tr2_group_bitmap[unit]);
    279         _tr2_group_bitmap[unit] = NULL;
    280     }
    281     if (_tr2_subport_id[unit]) {
    282         sal_free(_tr2_subport_id[unit]);
    283         _tr2_subport_id[unit] = NULL;
    284     }
    285 
    286     if (_tr2_subport_vp_mutex[unit] != NULL) {
    287         sal_mutex_destroy(_tr2_subport_vp_mutex[unit]);
    288         _tr2_subport_vp_mutex[unit] = NULL;
    289     }
    290 }
    291 
    292 #ifdef BCM_WARM_BOOT_SUPPORT
    293 /* 
    294  * Function:
    295  *     _bcm_tr2_subport_reinit
    296  * Purpose:
    297  *     Reinit for warm boot.
    298  * Parameters:
    299  *      unit    : (IN) Device Unit Number
    300  * Returns:
    301  *      BCM_E_XXX
    302  */
    303 STATIC int 
    304 _bcm_tr2_subport_reinit(int unit)
    305 {
    306     int vpbase_gprtid, stable_size;
    307     int idx, grp_base_idx = 0, vp_count = 0, vp = 0;
    308     int num_vp = soc_mem_index_count(unit, SOURCE_VPm);
    309     int index_min, index_max, fs_index, tpid_enable, index;
    310     source_vp_entry_t svp_entry;
    311     egr_l3_intf_entry_t egr_l3_entry;
    312     _bcm_vp_info_t vp_info;
    313 
    314     _bcm_vp_info_init(&vp_info);
    315     vp_info.vp_type = _bcmVpTypeSubport;
    316     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
    317 
    318     /* Reconstruct s/w state: Subport IDs */
    319     index_min = soc_mem_index_min(unit, EGR_L3_INTFm);
    320     index_max = soc_mem_index_max(unit, EGR_L3_INTFm);
    321                                  
    322     for (idx = index_min; idx <= index_max; idx++) {
    323         SOC_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_INTFm, MEM_BLOCK_ANY,
    324                                       idx, &egr_l3_entry));
    325         if (soc_mem_field_valid(unit, EGR_L3_INTFm, IVID_VALIDf)) {
    326             if (0 == soc_EGR_L3_INTFm_field32_get(unit, &egr_l3_entry,
    327                                                   IVID_VALIDf)) {
    328                 continue;
    329             }
    330         } else {
    331             if (1 != soc_EGR_L3_INTFm_field32_get(unit, &egr_l3_entry,
    332                                                   IVID_PRESENT_ACTIONf) &&
    333                 1 != soc_EGR_L3_INTFm_field32_get(unit, &egr_l3_entry,
    334                                                   IVID_ABSENT_ACTIONf)) {
    335                 continue;
    336             }
    337         }
    338         if ((vp = soc_EGR_L3_INTFm_field32_get(unit, &egr_l3_entry, IVIDf)) == 0){
    339             continue;
    340         }
    341         if ((stable_size == 0) || SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) {
    342             BCM_IF_ERROR_RETURN(
    343                 _bcm_vp_used_set(unit, vp, vp_info));
    344             _BCM_TR2_SUBPORT_ID_SET(unit, vp, idx);
    345             BCM_L3_INTF_USED_SET(unit, idx);
    346         } else {
    347         /* Extended scache based (Level 2) recovery */
    348             if (_bcm_vp_used_get(unit, vp, _bcmVpTypeSubport)) {
    349                 _BCM_TR2_SUBPORT_ID_SET(unit, vp, idx);
    350                 BCM_L3_INTF_USED_SET(unit, idx);
    351             }
    352         }
    353     }
    354 
    355     /* Reconstruct s/w state: Subport Groups */
    356     index_min = soc_mem_index_min(unit, SOURCE_VPm);
    357     index_max = soc_mem_index_max(unit, SOURCE_VPm);
    358     for (idx = 0; idx < num_vp ; idx++) {
    359         SOC_IF_ERROR_RETURN(soc_mem_read(unit, SOURCE_VPm, MEM_BLOCK_ANY,
    360                                       idx, &svp_entry));
    361 
    362         if (0x3 != soc_SOURCE_VPm_field32_get(unit, &svp_entry, ENTRY_TYPEf)) {
    363             continue;
    364         }
    365 
    366         /* A Subport group consists of a contiguous chunk of eight VPs */
    367         if (0 == grp_base_idx) {
    368             grp_base_idx = idx;
    369         }
    370 
    371         if (_TR2_VP_PER_SUBPORT_GROUP == ++vp_count) {
    372             if((grp_base_idx + _TR2_VP_PER_SUBPORT_GROUP) ==
    373                 (idx + 1)) {/* if VP is the base VP of group */
    374                 _BCM_TR2_GROUP_USED_SET(unit, (idx/_TR2_VP_PER_SUBPORT_GROUP));
    375                 /* Update flex stats */
    376                 if (soc_feature(unit, soc_feature_gport_service_counters)) {
    377                     if (soc_mem_field_valid(unit, SOURCE_VPm, VINTF_CTR_IDXf)) {
    378                         fs_index = soc_SOURCE_VPm_field32_get(unit, &svp_entry,
    379                                                                 VINTF_CTR_IDXf);
    380                         if (fs_index) {
    381                             BCM_GPORT_SUBPORT_GROUP_SET(vpbase_gprtid,
    382                                                          grp_base_idx);
    383                             _bcm_esw_flex_stat_reinit_add(unit,
    384                                 _bcmFlexStatTypeGport, fs_index, vpbase_gprtid);
    385                         }
    386                     }
    387                 }
    388                 grp_base_idx = 0; vp_count = 0; /* Reset for next group */
    389             }
    390         }
    391 
    392         /* Recover TPID ref count */
    393         if (soc_SOURCE_VPm_field32_get(unit, &svp_entry, SD_TAG_MODEf) == 1) {
    394             tpid_enable = soc_SOURCE_VPm_field32_get(unit, &svp_entry,
    395                                                                   TPID_ENABLEf);
    396             for (index = 0; index < 4; index++) {
    397                 if (tpid_enable & (1 << index)) {
    398                     BCM_IF_ERROR_RETURN(_bcm_fb2_outer_tpid_tab_ref_count_add(
    399                                                                unit, index, 1));
    400                     break;
    401                 }
    402             }
    403         }
    404     }
    405 
    406     return BCM_E_NONE; 
    407 }
    408 #endif /* BCM_WARM_BOOT_SUPPORT */
    409 
    410 /*
    411  * Function:
    412  *      bcm_subport_init
    413  * Purpose:
    414  *      Initialize the SUBPORT software module
    415  * Parameters:
    416  *      unit - Device Number
    417  * Returns:
    418  *      BCM_E_XXX
    419  */
    420 int
    421 bcm_tr2_subport_init(int unit)
    422 {
    423     int i;
    424     int rv = BCM_E_NONE;
    425 
    426     /*  Make sure module was initialized. */
    427     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
    428         return (BCM_E_INIT);
    429     }
    430 
    431     /* 
    432      * Include hook to flex stats
    433      */
    434 
    435     if (_tr2_subport_id[unit] == NULL) {
    436         _tr2_subport_id[unit] = 
    437             sal_alloc(_TR2_SUBPORT_NUM_VP * sizeof(uint16), "subport_bitmap");
    438         if (_tr2_subport_id[unit] == NULL) {
    439             return BCM_E_MEMORY;
    440         }
    441     }
    442     for (i = 0; i < _TR2_SUBPORT_NUM_VP; i++) {
    443         _BCM_TR2_SUBPORT_ID_CLR(unit, i);
    444     }
    445 
    446     if (_tr2_group_bitmap[unit] == NULL) {
    447         _tr2_group_bitmap[unit] = 
    448             sal_alloc(SHR_BITALLOCSIZE(_TR2_SUBPORT_NUM_GROUP), "subport_group_bitmap");
    449         if (_tr2_group_bitmap[unit] == NULL) {
    450             _bcm_tr2_subport_free_resource(unit);
    451             return BCM_E_MEMORY;
    452         }
    453     }
    454     sal_memset(_tr2_group_bitmap[unit], 0, SHR_BITALLOCSIZE(_TR2_SUBPORT_NUM_GROUP));
    455     /* Don't use VP 0 (HW restriction) : mark group 0 as used */
    456     _BCM_TR2_GROUP_USED_SET(unit, 0);
    457 
    458     for (i = 0; i < SOC_MAX_NUM_PORTS; i++) {
    459         _tr2_subport_group_count[unit][i] = 0;
    460     }
    461 
    462     if (!SOC_MEM_IS_VALID(unit, SOURCE_VPm)) { 
    463         if (NULL == _tr2_subport_vp_mutex[unit]) {
    464             _tr2_subport_vp_mutex[unit] = sal_mutex_create("subport vp mutex");
    465             if (_tr2_subport_vp_mutex[unit] == NULL) {
    466                 _bcm_tr2_subport_free_resource(unit);
    467                 return BCM_E_MEMORY;
    468             }
    469         }
    470     } 
    471 #ifdef BCM_WARM_BOOT_SUPPORT
    472     if(SOC_WARM_BOOT(unit)) {
    473         rv = _bcm_tr2_subport_reinit(unit);
    474         if (rv != BCM_E_NONE) {
    475             _bcm_tr2_subport_free_resource(unit);
    476         }
    477     }
    478 #endif /* BCM_WARM_BOOT_SUPPORT */
    479 
    480     /* Initialize common SUBPORT module */
    481     BCM_IF_ERROR_RETURN
    482         (bcmi_subport_common_init(unit, &bcmi_tr2_subport_drv));
    483 
    484     return rv;
    485 }
    486 
    487 /*
    488  * Function:
    489  *      bcm_tr2_subport_hw_clear
    490  * Purpose:
    491  *      Cleanup the SUBPORT hw module.
    492  * Parameters:
    493  *      unit - Device Number
    494  * Returns:
    495  *      BCM_E_XXX
    496  */
    497 STATIC int
    498 _bcm_tr2_subport_hw_clear(int unit)
    499 {
    500     int i, rv, vp, l3_idx;
    501 
    502     
    503     /* _bcm_tr2_subport_port_delete() is taking VLAN_XLATEm lock. */
    504     _TR2_SUBPORT_VP_MEM_LOCK(unit);
    505     /* Delete all existing subports */
    506     for (vp = 0; vp < _TR2_SUBPORT_NUM_VP; vp++) {
    507         l3_idx = _BCM_TR2_SUBPORT_ID_GET(unit, vp);
    508         if (l3_idx != 0xffff) {
    509             rv = _bcm_tr2_subport_port_delete(unit, l3_idx, vp);
    510             if (rv < 0) {
    511                 _TR2_SUBPORT_VP_MEM_UNLOCK(unit);
    512                 return rv;
    513             }
    514         }
    515     }
    516 
    517     /* Delete all existing groups (Group 0 reserved).*/
    518     for (i = 1; i < _TR2_SUBPORT_NUM_GROUP; i++) {
    519         if (_BCM_TR2_GROUP_USED_GET(unit, i)) {
    520             rv = _bcm_tr2_subport_group_destroy(unit, (i * 8));
    521             if (rv < 0) {
    522                 _TR2_SUBPORT_VP_MEM_UNLOCK(unit);
    523                 return rv;
    524             }
    525         }
    526     }
    527     _TR2_SUBPORT_VP_MEM_UNLOCK(unit);
    528     return BCM_E_NONE;
    529 }
    530 
    531 /*
    532  * Function:
    533  *      bcm_tr2_subport_cleanup
    534  * Purpose:
    535  *      Cleanup the SUBPORT software module
    536  * Parameters:
    537  *      unit - Device Number
    538  * Returns:
    539  *      BCM_E_XXX
    540  */
    541 int
    542 bcm_tr2_subport_cleanup(int unit)
    543 {
    544     int rv; /* Operation return status. */
    545 
    546     if (NULL == _tr2_group_bitmap[unit]) {
    547         return (BCM_E_NONE);
    548     }
    549 
    550      if (0 == SOC_HW_ACCESS_DISABLE(unit)) {
    551         rv = _bcm_tr2_subport_hw_clear(unit);
    552         BCM_IF_ERROR_RETURN(rv);
    553     }
    554 
    555     _bcm_tr2_subport_free_resource(unit);
    556     return BCM_E_NONE;
    557 }
    558 
    559 /*
    560  * Function:
    561  *      bcm_subport_group_create
    562  * Purpose:
    563  *      Create a subport group
    564  * Parameters:
    565  *      unit   - (IN) Device Number
    566  *      config - (IN) Subport group config information
    567  *      group  - (OUT) GPORT (generic port) identifier
    568  * Returns:
    569  *      BCM_E_XXX
    570  */
    571 int
    572 bcm_tr2_subport_group_create(int unit, bcm_subport_group_config_t *config,
    573                              bcm_gport_t *group)
    574 {
    575     int gport_id, rv, vp_base = -1, nh_index = -1, nh_group = -1, nh_profile_idx=0, priority;
    576     initial_ing_l3_next_hop_entry_t initial_ing_nh;
    577     ing_l3_next_hop_entry_t ing_nh;
    578     egr_l3_next_hop_entry_t egr_nh;
    579     source_vp_entry_t svp;
    580     ing_dvp_table_entry_t dvp;
    581 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
    582     ing_dvp_2_table_entry_t dvp_2;
    583 #endif
    584     nhi_group_tc_profile_entry_t nhi_entry;
    585     bcm_l3_egress_t nh_info;
    586     uint32 nh_flags;
    587     bcm_module_t mod_out, my_modid;
    588     bcm_port_t port_out;
    589     bcm_trunk_t trunk_id;
    590 #ifdef BCM_KATANA2_SUPPORT
    591     int queue_base;
    592 #endif /* BCM_KATANA2_SUPPORT */
    593 
    594     _TR2_SUBPORT_CHECK_INIT(unit);
    595 
    596     if ((config == NULL) || (group == NULL) || (config->vlan > BCM_VLAN_MAX)) {
    597         return BCM_E_PARAM;
    598     }
    599 #ifdef BCM_KATANA2_SUPPORT
    600     queue_base = BCM_GPORT_UCAST_SUBSCRIBER_QUEUE_GROUP_QID_GET(config->queue_base);
    601     if (soc_feature(unit, soc_feature_extended_queueing)) {
    602         ing_queue_map_entry_t queue_map_entry;
    603         if (config->flags & BCM_SUBPORT_GROUP_QUEUE) {
    604             if (queue_base != -1) {
    605                 if ((((config->qos_map_id >> _BCM_QOS_MAP_SHIFT) !=
    606                     _BCM_QOS_MAP_TYPE_ING_QUEUE_OFFSET_MAP_TABLE)) ||
    607                     ((config->qos_map_id & _BCM_QOS_MAP_TYPE_MASK) >
    608                     _BCM_QOS_MAP_ING_QUEUE_OFFSET_MAX)) {
    609                     return BCM_E_PARAM;
    610                 }
    611             } else {
    612                 return BCM_E_PARAM;
    613             }
    614 
    615             /*  configure queue map: base queue and map index */
    616             sal_memset(&queue_map_entry, 0, sizeof(ing_queue_map_entry_t));
    617             soc_mem_field32_set(unit, ING_QUEUE_MAPm, &queue_map_entry,
    618                     QUEUE_SET_BASEf, queue_base);
    619             soc_mem_field32_set(unit, ING_QUEUE_MAPm, &queue_map_entry,
    620                     QUEUE_OFFSET_PROFILE_INDEXf,
    621                     (config->qos_map_id & _BCM_QOS_MAP_TYPE_MASK));
    622             /* take base queue number as ING_QUEUE_MAP entry index */
    623             BCM_IF_ERROR_RETURN(soc_mem_write(unit, ING_QUEUE_MAPm, MEM_BLOCK_ALL,
    624                     queue_base, &queue_map_entry));
    625         }
    626     }
    627 #endif /* BCM_KATANA2_SUPPORT */
    628     rv = _bcm_esw_gport_resolve(unit, config->port, &mod_out, &port_out, &trunk_id,
    629                                 &gport_id);
    630     BCM_IF_ERROR_RETURN(rv);
    631 
    632     BCM_IF_ERROR_RETURN (bcm_esw_stk_my_modid_get(unit, &my_modid));
    633 
    634     if (config->flags & BCM_SUBPORT_GROUP_WITH_ID) {
    635         vp_base = BCM_GPORT_SUBPORT_GROUP_GET(*group);
    636         _TR2_SUBPORT_VP_MEM_LOCK(unit);
    637         if ((vp_base < 0) || (vp_base > (4096 - 8))) {
    638             rv = BCM_E_PARAM;
    639         } else if (_BCM_TR2_GROUP_USED_GET(unit, (vp_base / 8))) {
    640             rv = BCM_E_EXISTS;
    641         } else {
    642             _BCM_TR2_GROUP_USED_SET(unit, vp_base / 8);
    643         }
    644         _TR2_SUBPORT_VP_MEM_UNLOCK(unit);
    645     } else {
    646         /* 
    647          * Allocate a group of 8 consecutive VPs since 3-bit prio
    648          * is added to DVP-group to get the final DVP in the L2 lookup.
    649          * Only allocate from the 0 - 4k range since only 12-bits
    650          * are used in the EGR_VLAN_XLATE table key.
    651          * (the IVID field is used as the DVP in EGR_VLAN_XLATE)
    652          */
    653         rv = _bcm_tr2_subport_vp_alloc(unit, &vp_base);
    654     }
    655     BCM_IF_ERROR_RETURN (rv);
    656 
    657     for (priority=0; priority < 8; priority++) {
    658          /* 
    659            * Allocate a next-hop entry. By calling bcm_xgs3_nh_add()
    660            * with _BCM_L3_SHR_WRITE_DISABLE flag, a next-hop index is
    661            * allocated but nothing is written to hardware. The "nh_info"
    662            * in this case is not used, so just set to all zeros.
    663           */
    664          sal_memset(&nh_info, 0, sizeof(nh_info));
    665          nh_flags = _BCM_L3_SHR_MATCH_DISABLE | _BCM_L3_SHR_WRITE_DISABLE;
    666          rv = bcm_xgs3_nh_add(unit, nh_flags, &nh_info, &nh_index);
    667          if (rv < 0) {
    668               goto cleanup;
    669          } 
    670          if (priority == 0) {
    671               nh_group = nh_index;       
    672          }
    673 
    674          /* 
    675            * The EGR_L3_NEXT_HOP is not actually used in the datapath.
    676            * Instead, the DVP value is passed through the MMU in the
    677            * IVID field. At the egress, the IVID (DVP) is used in the
    678            * egress vlan translate table key. Here we use the 
    679            * EGR_L3_NEXT_HOP just to store the subport group's vlan
    680            * for warm reboot purposes for Triumph.
    681           */
    682 
    683          if (soc_feature(unit, soc_feature_subport_enhanced)) {
    684               /* Write EGR_L3_NEXT_HOP entry */
    685              sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t));
    686              
    687              if ((config->flags == BCM_SUBPORT_GROUP_TYPE_SUBPORT_PKTTAG) &&
    688                 soc_feature(unit, soc_feature_lltag)){
    689                 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 
    690                             SD_TAG__SD_TAG_VIDf, config->vlan);
    691              } else {
    692                 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3__OVIDf))
    693                     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,  L3__OVIDf,
    694                             config->vlan);
    695                 else
    696                     soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,  OVIDf,
    697                             config->vlan);
    698              }
    699              rv = soc_mem_write(unit, EGR_L3_NEXT_HOPm,
    700                            MEM_BLOCK_ALL, nh_index, &egr_nh);
    701              if (rv < 0) {
    702                  goto cleanup;
    703              }
    704          } 
    705 
    706          /* Write ING_L3_NEXT_HOP entry */
    707          sal_memset(&ing_nh, 0, sizeof(ing_l3_next_hop_entry_t));
    708 
    709         /* Set module id. */
    710          if (soc_feature(unit, soc_feature_generic_dest)) {
    711              if (BCM_GPORT_IS_TRUNK(config->port)) {
    712                  soc_mem_field32_dest_set(unit, ING_L3_NEXT_HOPm, &ing_nh,
    713                      DESTINATIONf, SOC_MEM_FIF_DEST_LAG, trunk_id);
    714              } else {
    715                  soc_mem_field32_dest_set(unit, ING_L3_NEXT_HOPm, &ing_nh,
    716                      DESTINATIONf, SOC_MEM_FIF_DEST_DGPP, (mod_out <<
    717                      SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS | port_out));
    718              }
    719          } else  {
    720              if (BCM_GPORT_IS_TRUNK(config->port)) {
    721                  soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, Tf, 1);
    722                  soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    723                                      &ing_nh, TGIDf, trunk_id);
    724              } else {
    725                  soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    726                                      &ing_nh, PORT_NUMf, port_out);
    727                  soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    728                                      &ing_nh, MODULE_IDf, mod_out);
    729              }
    730          }
    731          /* Use all 8 DVPs in the group except lltag suport since it uses next hop profile table
    732                 *  to address the DVP
    733                 */
    734          if ((soc_feature(unit, soc_feature_lltag)) &&
    735             (config->flags & BCM_SUBPORT_GROUP_TYPE_SUBPORT_PKTTAG)) {
    736              soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    737                        &ing_nh, DVP_RES_INFOf, 0);              
    738          } else {
    739              soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    740                        &ing_nh, DVP_RES_INFOf, 0x7f);
    741          }
    742          
    743          if (soc_feature(unit, soc_feature_subport_enhanced)) {
    744              soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    745                             &ing_nh, ENTRY_TYPEf, 0x3); /* GPON DVP */
    746          }
    747 
    748 #ifdef BCM_KATANA2_SUPPORT
    749         if (soc_feature(unit, soc_feature_extended_queueing)) {
    750             if (config->flags & BCM_SUBPORT_GROUP_QUEUE) {
    751                 if (SOC_MEM_FIELD_VALID(unit, ING_L3_NEXT_HOPm,EH_QUEUE_TAGf)) {
    752                     soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh,
    753                                         EH_QUEUE_TAGf, queue_base);
    754                 }
    755                 if (SOC_MEM_FIELD_VALID(unit, ING_L3_NEXT_HOPm,EH_TAG_TYPEf)) {
    756                     soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh,
    757                                         EH_TAG_TYPEf, _EH_TAG_TYPE_ING_QUEUE_MAP);
    758                 }
    759             }
    760         }
    761 #endif /* BCM_KATANA2_SUPPORT */
    762 
    763          rv = soc_mem_write (unit, ING_L3_NEXT_HOPm,
    764                        MEM_BLOCK_ALL, nh_index, &ing_nh);
    765          if (rv < 0) {
    766             goto cleanup;
    767          }
    768 
    769          /* Write INITIAL_ING_L3_NEXT_HOP entry */
    770          sal_memset(&initial_ing_nh, 0, sizeof(initial_ing_l3_next_hop_entry_t));
    771 
    772          if (soc_feature(unit, soc_feature_generic_dest)) {
    773              if (BCM_GPORT_IS_TRUNK(config->port)) {
    774                  soc_mem_field32_dest_set(unit, INITIAL_ING_L3_NEXT_HOPm,
    775                      &initial_ing_nh,
    776                      DESTINATIONf, SOC_MEM_FIF_DEST_LAG, trunk_id);
    777              } else {
    778                  soc_mem_field32_dest_set(unit, INITIAL_ING_L3_NEXT_HOPm,
    779                      &initial_ing_nh,
    780                      DESTINATIONf, SOC_MEM_FIF_DEST_DGPP, (mod_out <<
    781                      SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS | port_out));
    782              }
    783          } else  {
    784              if (BCM_GPORT_IS_TRUNK(config->port)) {
    785                  soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm, &initial_ing_nh, Tf, 1);
    786                  soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm,
    787                                      &initial_ing_nh, TGIDf, trunk_id);
    788              } else {
    789                  soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm,
    790                                      &initial_ing_nh, PORT_NUMf, port_out);
    791                  soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm,
    792                                      &initial_ing_nh, MODULE_IDf, mod_out);
    793              }
    794          }
    795 
    796          rv = soc_mem_write(unit, INITIAL_ING_L3_NEXT_HOPm,
    797                        MEM_BLOCK_ALL, nh_index, &initial_ing_nh);
    798          if (rv < 0) {
    799              goto cleanup;
    800          }
    801 
    802          if (soc_feature(unit, soc_feature_subport_enhanced)) {
    803              /* Write ING_DVP_TABLE entry */
    804              sal_memset(&dvp, 0, sizeof(ing_dvp_table_entry_t));
    805 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
    806              if (soc_feature(unit, soc_feature_dvp_2_config_required)) {
    807                  sal_memset(&dvp_2, 0, sizeof(ing_dvp_2_table_entry_t));
    808              }
    809 #endif
    810              if ((soc_feature(unit, soc_feature_lltag)) &&
    811                 (config->flags & BCM_SUBPORT_GROUP_TYPE_SUBPORT_PKTTAG)) {
    812                 soc_ING_DVP_TABLEm_field32_set(unit, &dvp, NHI_GROUPf, nh_group);
    813                 soc_ING_DVP_TABLEm_field32_set(unit, &dvp, NHI_GROUP_ENf, 1);
    814                 soc_ING_DVP_TABLEm_field32_set(unit, &dvp, TC_PROFILE_INDEXf, 0);
    815              } else {
    816                 soc_ING_DVP_TABLEm_field32_set(unit, &dvp, NEXT_HOP_INDEXf, nh_index);
    817 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
    818                  if (soc_feature(unit, soc_feature_dvp_2_config_required)) {
    819                      soc_ING_DVP_2_TABLEm_field32_set(unit, &dvp_2, NEXT_HOP_INDEXf, nh_index);
    820                  }
    821 #endif
    822              }
    823              rv = WRITE_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, (vp_base+priority), &dvp);
    824              if (rv < 0) {
    825                  goto cleanup;
    826              }
    827 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
    828              if (soc_feature(unit, soc_feature_dvp_2_config_required)) {
    829                    rv = WRITE_ING_DVP_2_TABLEm(unit, MEM_BLOCK_ALL, (vp_base+priority), &dvp_2);
    830                    if (rv < 0) {
    831                        goto cleanup;
    832                    }
    833              }
    834 #endif
    835              /* Write SOURCE_VP table entry */
    836             sal_memset(&svp, 0, sizeof(svp));
    837             soc_SOURCE_VPm_field32_set(unit, &svp, ENTRY_TYPEf, 0x3); /* GPON */
    838             soc_SOURCE_VPm_field32_set(unit, &svp, CLASS_IDf, config->if_class);
    839             if (soc_feature(unit, soc_feature_generic_dest)) {
    840                 soc_mem_field32_dest_set(unit, SOURCE_VPm, &svp,
    841                          DESTINATIONf, SOC_MEM_FIF_DEST_DVP, vp_base);
    842             } else {
    843                 soc_SOURCE_VPm_field32_set(unit, &svp, DVPf, vp_base); /* DVP = vp_base */
    844             }
    845 
    846             /* Set the CML to PVP_CML_SWITCH by default (hw learn and forward) */
    847             
    848             soc_SOURCE_VPm_field32_set(unit, &svp, CML_FLAGS_NEWf, 0x8);
    849             soc_SOURCE_VPm_field32_set(unit, &svp, CML_FLAGS_MOVEf, 0x8);
    850             rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, (vp_base+priority), &svp);
    851             if (rv < 0) {
    852                 goto cleanup;
    853             }
    854         }
    855     }
    856 
    857     if (mod_out == my_modid) {
    858         if (_tr2_subport_group_count[unit][port_out]++ == 0) {
    859 
    860 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
    861         if (soc_feature(unit, soc_feature_egr_ipmc_cfg2_is_memory)) {
    862             SOC_IF_ERROR_RETURN
    863                 (soc_mem_field32_modify(unit, EGR_IPMC_CFG2m, port_out,
    864                                             DISABLE_TTL_CHECKf, 1));
    865         } else
    866 #endif
    867             if (SOC_REG_IS_VALID(unit, EGR_IPMC_CFG2r)) {
    868                SOC_IF_ERROR_RETURN
    869                 (soc_reg_field32_modify(unit, EGR_IPMC_CFG2r, port_out,
    870                                         DISABLE_TTL_CHECKf, 1));
    871             }
    872         }
    873     }
    874 
    875     BCM_GPORT_SUBPORT_GROUP_SET(*group, vp_base);
    876 
    877 #ifdef BCM_WARM_BOOT_SUPPORT
    878     SOC_CONTROL_LOCK(unit);
    879     SOC_CONTROL(unit)->scache_dirty = 1;
    880     SOC_CONTROL_UNLOCK(unit);
    881 #endif
    882 
    883     return BCM_E_NONE;
    884 
    885 cleanup:
    886 
    887     for (;priority >= 0; priority--) {
    888         (void) READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, (vp_base+priority), &dvp);
    889         if ((soc_feature(unit, soc_feature_lltag)) && 
    890             (config->flags & BCM_SUBPORT_GROUP_TYPE_SUBPORT_PKTTAG)) {
    891             if (soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NHI_GROUP_ENf)) {
    892                 nh_group =  soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NHI_GROUPf);
    893                 nh_profile_idx = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, 
    894                                     TC_PROFILE_INDEXf);
    895                 (void) READ_NHI_GROUP_TC_PROFILEm(unit, MEM_BLOCK_ALL, 
    896                                     nh_profile_idx*16 + priority, &nhi_entry);
    897                 nh_index = nh_group + soc_NHI_GROUP_TC_PROFILEm_field32_get(unit, 
    898                                     &nhi_entry, NHI_OFFSETf); 
    899             } else {
    900                 nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
    901             }
    902         } else {
    903             nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
    904         }
    905         
    906         if (nh_index != -1) {
    907             nh_flags = _BCM_L3_SHR_WRITE_DISABLE;
    908             (void) bcm_xgs3_nh_del(unit, nh_flags, nh_index);
    909         }
    910     }
    911     if (vp_base != -1) {
    912         (void) _bcm_tr2_subport_vp_free(unit, vp_base);
    913     }
    914     return rv;
    915 }
    916 
    917 STATIC int
    918 _bcm_tr2_subport_group_destroy(int unit, int vp_base)
    919 {
    920     int i, nh_index=-1, nh_group=-1, nh_profile_idx=0, rv;
    921     initial_ing_l3_next_hop_entry_t initial_ing_nh;
    922     ing_l3_next_hop_entry_t ing_nh;
    923     egr_l3_next_hop_entry_t egr_nh;
    924     ing_dvp_table_entry_t dvp;
    925 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
    926     ing_dvp_2_table_entry_t dvp_2;
    927 #endif
    928     source_vp_entry_t svp;
    929     nhi_group_tc_profile_entry_t nhi_entry;
    930     bcm_port_t port = 0;
    931     bcm_module_t my_modid, modid = -1;
    932 
    933     BCM_IF_ERROR_RETURN (bcm_esw_stk_my_modid_get(unit, &my_modid));
    934 
    935     if (soc_feature(unit, soc_feature_subport_enhanced)) {
    936         /* Get the next-hop index from the base VP */
    937         rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base, &dvp);
    938         BCM_IF_ERROR_RETURN(rv);
    939 
    940         if (soc_feature(unit, soc_feature_lltag)) {
    941             if (soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NHI_GROUP_ENf)) {
    942                 nh_group =  soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NHI_GROUPf);
    943                 nh_profile_idx = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, 
    944                                     TC_PROFILE_INDEXf);
    945                 rv = READ_NHI_GROUP_TC_PROFILEm(unit, MEM_BLOCK_ALL, 
    946                                     nh_profile_idx*16, &nhi_entry);
    947                 BCM_IF_ERROR_RETURN(rv);
    948                 nh_index = nh_group + soc_NHI_GROUP_TC_PROFILEm_field32_get(unit, 
    949                                     &nhi_entry, NHI_OFFSETf); 
    950             } else {
    951                 nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
    952             }
    953         } else {
    954             nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
    955         }
    956  
    957         BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
    958                                           nh_index, &ing_nh));
    959 
    960         if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, ENTRY_TYPEf) != 0x3) {
    961             /* Entry type is not GPON DVP */
    962             return BCM_E_NOT_FOUND;
    963         }
    964      }
    965 
    966     if (soc_feature(unit, soc_feature_subport_enhanced)) {
    967 
    968         for (i = 0; i < 8; i++) {
    969 
    970            /* Obtain nh_index from DVP_TABLE entry */
    971            rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, (vp_base + i), &dvp);
    972            BCM_IF_ERROR_RETURN(rv);	
    973            if (soc_feature(unit, soc_feature_lltag)) {
    974                 if (soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NHI_GROUP_ENf)) {
    975                     nh_group =  soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NHI_GROUPf);
    976                     nh_profile_idx = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, 
    977                                     TC_PROFILE_INDEXf);
    978                     rv = READ_NHI_GROUP_TC_PROFILEm(unit, MEM_BLOCK_ALL, 
    979                                     nh_profile_idx*16 + i, &nhi_entry);
    980                     BCM_IF_ERROR_RETURN(rv);
    981                     nh_index = nh_group + soc_NHI_GROUP_TC_PROFILEm_field32_get(unit, 
    982                                     &nhi_entry, NHI_OFFSETf); 
    983                 } else {
    984                     nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, 
    985                                 NEXT_HOP_INDEXf);
    986                 }
    987            } else {
    988                 nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
    989            }
    990            /* Clear EGR_L3_NEXT_HOP entry */
    991            sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t));
    992            rv = soc_mem_write(unit, EGR_L3_NEXT_HOPm,
    993                                   MEM_BLOCK_ALL, nh_index, &egr_nh);
    994            BCM_IF_ERROR_RETURN(rv);
    995 	   
    996            /* Get the modid/port number from ING_L3_NEXT_HOP entry */
    997            rv = soc_mem_read(unit, ING_L3_NEXT_HOPm,
    998                                   MEM_BLOCK_ALL, nh_index, &ing_nh);
    999            BCM_IF_ERROR_RETURN(rv);
   1000             if (soc_feature(unit, soc_feature_generic_dest)) {
   1001                 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID, dest = 0;
   1002                 dest = soc_mem_field32_dest_get(unit, ING_L3_NEXT_HOPm, &ing_nh,
   1003                                          DESTINATIONf, &dest_type);
   1004                 if (dest_type == SOC_MEM_FIF_DEST_DGPP) {
   1005                     port = (dest & SOC_MEM_FIF_DGPP_PORT_MASK);
   1006                     modid = (dest & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >>
   1007                              SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS;
   1008                 }
   1009             } else {
   1010                 modid = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm,
   1011                                             &ing_nh, MODULE_IDf);
   1012                 port = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm,
   1013                                            &ing_nh, PORT_NUMf);
   1014             }
   1015             if (modid == my_modid) {
   1016                 if (--_tr2_subport_group_count[unit][port] == 0) {
   1017 
   1018 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   1019                     if (soc_feature(unit, soc_feature_egr_ipmc_cfg2_is_memory)) {
   1020                         SOC_IF_ERROR_RETURN
   1021                             (soc_mem_field32_modify(unit, EGR_IPMC_CFG2m, port,
   1022                                                         DISABLE_TTL_CHECKf, 1));
   1023                     } else
   1024 #endif
   1025                     if (SOC_REG_IS_VALID(unit, EGR_IPMC_CFG2r)) {
   1026                         SOC_IF_ERROR_RETURN
   1027                             (soc_reg_field32_modify(unit, EGR_IPMC_CFG2r,
   1028                                 port, DISABLE_TTL_CHECKf, 0));
   1029                     }
   1030                 }
   1031             }
   1032 
   1033 #ifdef BCM_KATANA2_SUPPORT
   1034            if (soc_feature(unit, soc_feature_extended_queueing)) {
   1035                ing_queue_map_entry_t queue_map_entry;
   1036                int queue_base;
   1037                if (_EH_TAG_TYPE_ING_QUEUE_MAP == soc_mem_field32_get(unit,
   1038                    ING_L3_NEXT_HOPm, &ing_nh, EH_TAG_TYPEf)) {
   1039                    /*  Clear ING_QUEUE_MAP entry */
   1040                    sal_memset(&queue_map_entry, 0, sizeof(ing_queue_map_entry_t));
   1041                    queue_base = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm,
   1042                        &ing_nh, EH_QUEUE_TAGf);
   1043                    BCM_IF_ERROR_RETURN(soc_mem_write (unit, ING_QUEUE_MAPm,
   1044                                   MEM_BLOCK_ALL, queue_base, &queue_map_entry));
   1045                }
   1046            }
   1047 #endif /* BCM_KATANA2_SUPPORT */
   1048 
   1049            /* Clear ING_L3_NEXT_HOP entry */
   1050            sal_memset(&ing_nh, 0, sizeof(ing_l3_next_hop_entry_t));
   1051            rv = soc_mem_write (unit, ING_L3_NEXT_HOPm,
   1052                                   MEM_BLOCK_ALL, nh_index, &ing_nh);
   1053            BCM_IF_ERROR_RETURN(rv);
   1054 		   
   1055            /* Clear INITIAL_ING_L3_NEXT_HOP entry */
   1056            sal_memset(&initial_ing_nh, 0, sizeof(initial_ing_l3_next_hop_entry_t));
   1057            rv = soc_mem_write(unit, INITIAL_ING_L3_NEXT_HOPm,
   1058                                   MEM_BLOCK_ALL, nh_index, &initial_ing_nh);
   1059            BCM_IF_ERROR_RETURN(rv);
   1060 
   1061 		   		   
   1062            /* Free the next-hop index */
   1063            rv = bcm_xgs3_nh_del(unit, _BCM_L3_SHR_WRITE_DISABLE, nh_index);
   1064            BCM_IF_ERROR_RETURN(rv);
   1065 
   1066            /* Clear SOURCE_VP table entry */
   1067            sal_memset(&svp, 0, sizeof(svp));
   1068            rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, (vp_base+i), &svp);
   1069            BCM_IF_ERROR_RETURN(rv);
   1070 
   1071            /* Clear ING_DVP_TABLE entry */
   1072            sal_memset(&dvp, 0, sizeof(dvp));
   1073            rv = WRITE_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, (vp_base+i), &dvp);
   1074            BCM_IF_ERROR_RETURN(rv);
   1075 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
   1076            if (soc_feature(unit, soc_feature_dvp_2_config_required)) {
   1077                sal_memset(&dvp_2, 0, sizeof(dvp_2));
   1078                rv = WRITE_ING_DVP_2_TABLEm(unit, MEM_BLOCK_ALL, (vp_base+i), &dvp_2);
   1079                BCM_IF_ERROR_RETURN(rv);
   1080            }
   1081 #endif
   1082         }
   1083     }
   1084 
   1085     if (soc_feature(unit, soc_feature_gport_service_counters)) {
   1086         bcm_gport_t gport;
   1087 
   1088         /* Release Service counter, if any */
   1089         BCM_GPORT_SUBPORT_GROUP_SET(gport, vp_base);
   1090         _bcm_esw_flex_stat_handle_free(unit, _bcmFlexStatTypeGport, gport);
   1091     }
   1092 
   1093     /* Free the VP */
   1094     rv = _bcm_tr2_subport_vp_free(unit, vp_base);
   1095     BCM_IF_ERROR_RETURN(rv);
   1096 
   1097 #ifdef BCM_WARM_BOOT_SUPPORT
   1098     SOC_CONTROL_LOCK(unit);
   1099     SOC_CONTROL(unit)->scache_dirty = 1;
   1100     SOC_CONTROL_UNLOCK(unit);
   1101 #endif
   1102 
   1103     return rv;
   1104 }
   1105 
   1106 /*
   1107  * Function:
   1108  *      bcm_subport_group_destroy
   1109  * Purpose:
   1110  *      Destroy a subport group
   1111  * Parameters:
   1112  *      unit  - (IN) Device Number
   1113  *      group - (IN) GPORT (generic port) identifier
   1114  * Returns:
   1115  *      BCM_E_XXX
   1116  */
   1117 int
   1118 bcm_tr2_subport_group_destroy(int unit, bcm_gport_t group)
   1119 {   
   1120     int vp_base;
   1121 
   1122     _TR2_SUBPORT_CHECK_INIT(unit);
   1123 
   1124     vp_base = BCM_GPORT_SUBPORT_GROUP_GET(group); 
   1125     if (vp_base == -1) {
   1126         return BCM_E_PARAM;
   1127     }
   1128 
   1129     return _bcm_tr2_subport_group_destroy(unit, vp_base);
   1130 }
   1131 
   1132 /*
   1133  * Function:
   1134  *      bcm_subport_group_get
   1135  * Purpose:
   1136  *      Get a subport group
   1137  * Parameters:
   1138  *      unit   - (IN) Device Number
   1139  *      group  - (IN) GPORT (generic port) identifier
   1140  *      config - (OUT) Subport group config information
   1141  * Returns:
   1142  *      BCM_E_XXX
   1143  */
   1144 int
   1145 bcm_tr2_subport_group_get(int unit, bcm_gport_t group,
   1146                          bcm_subport_group_config_t *config)
   1147 {
   1148     int rv = BCM_E_NONE; 
   1149     egr_l3_next_hop_entry_t egr_nh;
   1150     ing_l3_next_hop_entry_t ing_nh;
   1151     ing_dvp_table_entry_t dvp;
   1152     source_vp_entry_t svp;
   1153     nhi_group_tc_profile_entry_t nhi_entry;
   1154     int nh_index = -1, nh_group = -1, nh_profile_idx = 0, vp_base;
   1155     bcm_port_t port_in, port_out;
   1156     bcm_module_t mod_in, mod_out;
   1157     bcm_trunk_t trunk_id;
   1158 
   1159     _TR2_SUBPORT_CHECK_INIT(unit);
   1160 
   1161     if (config == NULL) {
   1162         return BCM_E_PARAM;
   1163     }
   1164 
   1165     vp_base = BCM_GPORT_SUBPORT_GROUP_GET(group);
   1166     if (vp_base == -1) {
   1167         return BCM_E_PARAM;
   1168     }
   1169 
   1170     if (soc_feature(unit, soc_feature_subport_enhanced)) {
   1171         rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base, &dvp);
   1172         BCM_IF_ERROR_RETURN(rv);
   1173         if (soc_feature(unit, soc_feature_lltag)) {
   1174             if (soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NHI_GROUP_ENf)) {
   1175                 nh_group =  soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NHI_GROUPf);
   1176                 nh_profile_idx = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, 
   1177                                     TC_PROFILE_INDEXf);
   1178                 rv = READ_NHI_GROUP_TC_PROFILEm(unit, MEM_BLOCK_ALL, 
   1179                                     nh_profile_idx*16, &nhi_entry);
   1180                 BCM_IF_ERROR_RETURN(rv);
   1181                 nh_index = nh_group + soc_NHI_GROUP_TC_PROFILEm_field32_get(unit, 
   1182                                     &nhi_entry, NHI_OFFSETf); 
   1183                 config->flags |= BCM_SUBPORT_GROUP_TYPE_SUBPORT_PKTTAG;
   1184             } else {
   1185                 nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   1186             }
   1187         } else {
   1188             nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   1189         }
   1190         nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   1191         BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   1192                                           nh_index, &ing_nh));
   1193 
   1194         if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, ENTRY_TYPEf) != 0x3) {
   1195            /* Entry type is not GPON DVP */
   1196            return BCM_E_NOT_FOUND;
   1197         }
   1198     }
   1199 
   1200     /* Get the physical gport information from the ingress next-hop entry */
   1201     if (soc_feature(unit, soc_feature_generic_dest)) {
   1202         uint32 dest_type, dest;
   1203         dest = soc_mem_field32_dest_get(unit, ING_L3_NEXT_HOPm,
   1204                 &ing_nh, DESTINATIONf, &dest_type);
   1205         if (dest_type == SOC_MEM_FIF_DEST_LAG) {
   1206             trunk_id = (dest & SOC_MEM_FIF_DGPP_TGID_MASK);
   1207             BCM_GPORT_TRUNK_SET(config->port, trunk_id);
   1208         } else {
   1209             port_in = (dest & SOC_MEM_FIF_DGPP_PORT_MASK);
   1210             mod_in = (dest & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >>
   1211                      SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS;
   1212             BCM_IF_ERROR_RETURN(_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
   1213                                                        mod_in, port_in,
   1214                                                        &mod_out, &port_out));
   1215             BCM_GPORT_MODPORT_SET(config->port, mod_out, port_out);
   1216         }
   1217     } else {
   1218         if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) {
   1219             trunk_id = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, TGIDf);
   1220             BCM_GPORT_TRUNK_SET(config->port, trunk_id);
   1221         } else {
   1222             mod_in = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, MODULE_IDf);
   1223             port_in = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf);
   1224             BCM_IF_ERROR_RETURN(_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
   1225                                                        mod_in, port_in,
   1226                                                        &mod_out, &port_out));
   1227             BCM_GPORT_MODPORT_SET(config->port, mod_out, port_out);
   1228        }
   1229     }
   1230 
   1231     if (soc_feature(unit, soc_feature_subport_enhanced)) {
   1232         /* Get the group's OVID from the group's egress next-hop entry */
   1233         rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm,
   1234                           MEM_BLOCK_ALL, nh_index, &egr_nh);
   1235         BCM_IF_ERROR_RETURN(rv);
   1236         if ((config->flags & BCM_SUBPORT_GROUP_TYPE_SUBPORT_PKTTAG) &&
   1237             soc_feature(unit, soc_feature_lltag)) {
   1238             config->vlan = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, 
   1239                             SD_TAG__SD_TAG_VIDf);
   1240         } else {
   1241             if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3__OVIDf)) {
   1242                 config->vlan = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, L3__OVIDf);
   1243             } else {
   1244                 config->vlan = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, OVIDf);
   1245             }
   1246         }
   1247     }
   1248 
   1249     if (soc_feature(unit, soc_feature_subport_enhanced)) {
   1250         /* Get the class-ID from the SOURCE_VP table entry */
   1251         rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp_base, &svp);
   1252         BCM_IF_ERROR_RETURN(rv);
   1253         config->if_class = soc_SOURCE_VPm_field32_get(unit, &svp, CLASS_IDf);
   1254     }
   1255 
   1256 #ifdef BCM_KATANA2_SUPPORT
   1257     if (soc_feature(unit, soc_feature_extended_queueing)) {
   1258         ing_queue_map_entry_t queue_map_entry;
   1259         int queue_base;
   1260         if (_EH_TAG_TYPE_ING_QUEUE_MAP == soc_mem_field32_get(unit,
   1261             ING_L3_NEXT_HOPm, &ing_nh, EH_TAG_TYPEf)) {
   1262             config->flags |= BCM_SUBPORT_GROUP_QUEUE;
   1263             queue_base = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm,
   1264                 &ing_nh, EH_QUEUE_TAGf);
   1265             BCM_GPORT_UCAST_SUBSCRIBER_QUEUE_GROUP_SYSQID_SET(config->queue_base,
   1266                 config->port, queue_base);
   1267             BCM_IF_ERROR_RETURN(soc_mem_read(unit, ING_QUEUE_MAPm, MEM_BLOCK_ANY,
   1268                                               queue_base, &queue_map_entry));
   1269             config->qos_map_id = soc_mem_field32_get(unit, ING_QUEUE_MAPm,
   1270                 &queue_map_entry, QUEUE_OFFSET_PROFILE_INDEXf) |
   1271                 (_BCM_QOS_MAP_TYPE_ING_QUEUE_OFFSET_MAP_TABLE << _BCM_QOS_MAP_SHIFT);
   1272         }
   1273     }
   1274 #endif /* BCM_KATANA2_SUPPORT */
   1275 
   1276     return BCM_E_NONE;
   1277 }
   1278 
   1279 /*
   1280  * Function:
   1281  *      bcm_subport_port_add
   1282  * Purpose:
   1283  *      Add a subport to a subport group
   1284  * Parameters:
   1285  *      unit   - (IN) Device Number
   1286  *      config - (IN) Subport config information
   1287  *      port   - (OUT) GPORT (generic port) identifier
   1288  * Returns:
   1289  *      BCM_E_XXX
   1290  */
   1291 int
   1292 bcm_tr2_subport_port_add(int unit, bcm_subport_config_t *config,
   1293                          bcm_gport_t *port)
   1294 {
   1295     int rv, l3_idx = -1, nh_index=-1, vp_base, vp;
   1296     int nh_group=-1, nh_profile_idx=0; 
   1297     ing_dvp_table_entry_t dvp;
   1298     source_vp_entry_t svp;
   1299     egr_l3_next_hop_entry_t egr_nh;
   1300     ing_l3_next_hop_entry_t ing_nh;
   1301     egr_l3_intf_entry_t l3_intf;
   1302     nhi_group_tc_profile_entry_t nhi_entry;
   1303     port_tab_entry_t port_tab;
   1304     bcm_vlan_t ovid = 0;
   1305     bcm_port_t local_port = 0;
   1306     bcm_module_t my_modid, modid = 0;
   1307     bcm_vlan_action_set_t action;
   1308     uint32 egr_profile_idx = 0xffffffff; 
   1309     uint32 ing_profile_idx = 0xffffffff;
   1310     int key_type_value;
   1311     uint32              egr_vent[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer.     */
   1312     uint32              ing_vent[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer.     */
   1313     soc_mem_t egr_mem = EGR_VLAN_XLATEm, ing_mem = VLAN_XLATEm;
   1314 
   1315     sal_memset(egr_vent, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
   1316     sal_memset(ing_vent, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
   1317 
   1318 
   1319     _TR2_SUBPORT_CHECK_INIT(unit);
   1320 
   1321     if ((config->int_pri < 0) || (config->int_pri > 7)) {
   1322         return BCM_E_PARAM;
   1323     }
   1324 
   1325     /* Check Vlan range */
   1326     if ((config->pkt_vlan >= BCM_VLAN_INVALID) || ( config->pkt_vlan == BCM_VLAN_DEFAULT)) {
   1327          return BCM_E_PARAM;
   1328     }
   1329 
   1330     if ((config->criteria == BCM_SUBPORT_MATCH_PKT_VID_OUTER_VLAN) && 
   1331         ((config->outer_vlan >= BCM_VLAN_INVALID) || 
   1332          ( config->outer_vlan == BCM_VLAN_DEFAULT))) {
   1333         return BCM_E_PARAM;        
   1334     }
   1335 
   1336     if ((config->criteria == BCM_SUBPORT_MATCH_PKT_VID_INNER_VLAN) && 
   1337         ((config->inner_vlan >= BCM_VLAN_INVALID) || 
   1338          ( config->inner_vlan == BCM_VLAN_DEFAULT))) {
   1339         return BCM_E_PARAM;        
   1340     }
   1341 
   1342     BCM_IF_ERROR_RETURN (bcm_esw_stk_my_modid_get(unit, &my_modid));
   1343 
   1344     /* Make sure the group exists */
   1345     vp_base = BCM_GPORT_SUBPORT_GROUP_GET(config->group);
   1346     if (vp_base == -1) {
   1347         return BCM_E_PARAM;
   1348     }
   1349 
   1350     if (!_BCM_TR2_GROUP_USED_GET(unit, vp_base / 8)) {
   1351         return BCM_E_NOT_FOUND;
   1352     }
   1353 
   1354     /* See if this entry already exists */
   1355     vp = vp_base + config->int_pri;
   1356     if (_BCM_TR2_SUBPORT_ID_GET(unit, vp) != 0xffff) {
   1357         return BCM_E_EXISTS;
   1358     }
   1359 
   1360 
   1361     /* ***************************************************** */
   1362     /* --- Get the group's NHI from ING_DVP_TABLE--------------- */ 
   1363     /* ***************************************************** */
   1364     
   1365       
   1366     if (soc_feature(unit, soc_feature_subport_enhanced)) {
   1367         rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base, &dvp);
   1368         BCM_IF_ERROR_RETURN(rv);
   1369         if (soc_feature(unit, soc_feature_lltag)) {
   1370             if (soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NHI_GROUP_ENf)) {
   1371                 nh_group =  soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NHI_GROUPf);
   1372                 nh_profile_idx = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, 
   1373                                     TC_PROFILE_INDEXf);
   1374                 rv = READ_NHI_GROUP_TC_PROFILEm(unit, MEM_BLOCK_ALL, 
   1375                                     nh_profile_idx*16, &nhi_entry);
   1376                 BCM_IF_ERROR_RETURN(rv);
   1377                 nh_index = nh_group + soc_NHI_GROUP_TC_PROFILEm_field32_get(unit, 
   1378                                     &nhi_entry, NHI_OFFSETf); 
   1379             } else {
   1380                 nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   1381             }
   1382         } else {
   1383             nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   1384         }
   1385     }
   1386 
   1387     if (nh_index == -1) {
   1388         return BCM_E_INTERNAL;
   1389     }
   1390 
   1391     /* Get the modid and port_class for the destination port */
   1392     rv = soc_mem_read(unit, ING_L3_NEXT_HOPm,
   1393                       MEM_BLOCK_ALL, nh_index, &ing_nh);
   1394     if (rv < 0) {
   1395         goto cleanup;
   1396     }
   1397 
   1398     if (soc_feature(unit, soc_feature_generic_dest)) {
   1399         uint32 dt, dv;
   1400         dv = soc_mem_field32_dest_get(unit, ING_L3_NEXT_HOPm,
   1401                 &ing_nh, DESTINATIONf, &dt);
   1402         if (dt != SOC_MEM_FIF_DEST_LAG) {
   1403             modid = (dv & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >>
   1404                       SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS;
   1405             if (modid != my_modid) {
   1406             /* No local state is required for groups on remoted devices */
   1407                 return BCM_E_NONE;
   1408             }
   1409             local_port = dv & SOC_MEM_FIF_DGPP_PORT_MASK;
   1410         }
   1411     } else {
   1412         if (!soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, &ing_nh, Tf)) {
   1413             modid = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, &ing_nh, MODULE_IDf);
   1414             if (modid != my_modid) {
   1415             /* No local state is required for groups on remoted devices */
   1416                 return BCM_E_NONE;
   1417             }
   1418             local_port = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm,
   1419                                          &ing_nh, PORT_NUMf);
   1420         /* TBD:  Algorithm to compute DVP_RES_INFO */
   1421         }
   1422     }
   1423     /* Get the group's OVID from the group's egress next-hop entry */
   1424     rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm,
   1425                       MEM_BLOCK_ALL, nh_index, &egr_nh);
   1426     if (rv < 0) {
   1427          goto cleanup;
   1428     }
   1429 
   1430     if ((soc_feature(unit, soc_feature_lltag)) &&
   1431         (config->criteria > BCM_SUBPORT_MATCH_INVALID) &&
   1432         (config->criteria < BCM_SUBPORT_MATCH_COUNT)) {
   1433         ovid = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, 
   1434             SD_TAG__SD_TAG_VIDf);
   1435     } else {
   1436         if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3__OVIDf))
   1437             ovid = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, L3__OVIDf);
   1438         else
   1439             ovid = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, OVIDf);
   1440     }
   1441    /* *********************************************************** */
   1442    /* ---- For each Priority, Update the fields within EGR_L3_NEXT_HOP ---- */
   1443    /* *********************************************************** */
   1444    
   1445     if (soc_feature(unit, soc_feature_subport_enhanced)) {
   1446         /* Obtain the nh_index from DVP_Table for each Priority */
   1447         rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, (vp_base + config->int_pri), &dvp);
   1448         BCM_IF_ERROR_RETURN(rv);
   1449         if (soc_feature(unit, soc_feature_lltag)) {
   1450             if (soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NHI_GROUP_ENf)) {
   1451                 nh_group =  soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NHI_GROUPf);
   1452                 nh_profile_idx = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, 
   1453                                     TC_PROFILE_INDEXf);
   1454                 rv = READ_NHI_GROUP_TC_PROFILEm(unit, MEM_BLOCK_ALL, 
   1455                             nh_profile_idx*16 + config->int_pri, &nhi_entry);
   1456                 BCM_IF_ERROR_RETURN(rv);
   1457                 nh_index = nh_group + soc_NHI_GROUP_TC_PROFILEm_field32_get(unit, 
   1458                             &nhi_entry, NHI_OFFSETf); 
   1459             } else {
   1460                 nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   1461             }
   1462         } else {
   1463             nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   1464         }
   1465 
   1466         rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm,
   1467                           MEM_BLOCK_ALL, nh_index, &egr_nh);
   1468         BCM_IF_ERROR_RETURN(rv);
   1469 #if defined(BCM_TRIDENT3_SUPPORT)
   1470         if (SOC_MEM_FIELD_VALID(unit, EGR_L3_NEXT_HOPm, DATA_TYPEf)) {
   1471             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, DATA_TYPEf, 2);
   1472         } else
   1473 #endif
   1474         {
   1475             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm,
   1476                                 &egr_nh, ENTRY_TYPEf, 0x2);
   1477         }
   1478         if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, DVPf)) {
   1479             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm,
   1480                                 &egr_nh, DVPf, (vp_base + config->int_pri));
   1481         } else { /* use SD_TAG view becuase the ENTRY_TYPE is 2 */
   1482             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm,
   1483                                 &egr_nh, SD_TAG__DVPf,
   1484                                 (vp_base + config->int_pri));
   1485         }
   1486         if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, HG_HDR_SELf)) {
   1487             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, HG_HDR_SELf,
   1488                                 1);
   1489         } else { /* use SD_TAG view becuase the ENTRY_TYPE is 2 */
   1490             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh,
   1491                                 SD_TAG__HG_HDR_SELf, 1);
   1492         }
   1493 
   1494         if ((soc_feature(unit, soc_feature_lltag)) &&
   1495             (config->criteria > BCM_SUBPORT_MATCH_INVALID) &&
   1496             (config->criteria < BCM_SUBPORT_MATCH_COUNT)) {
   1497             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 
   1498                                 SD_TAG__SD_TAG_VIDf, ovid);   
   1499         } 
   1500 		
   1501         rv = soc_mem_write(unit, EGR_L3_NEXT_HOPm,
   1502                         MEM_BLOCK_ALL, nh_index, &egr_nh);
   1503         if (rv < 0) {
   1504              goto cleanup;
   1505         }
   1506     }
   1507 
   1508     /*
   1509      * For each subport, we need to allocate an L3_INTF entry.
   1510      * This is needed for multicast replication. MMU replicates
   1511      * multicast packets to each subport by sending a copy to 
   1512      * the subport's L3_INTF index.
   1513      */
   1514 
   1515     /* Search for unused index. */
   1516     MEM_LOCK(unit, EGR_L3_INTFm);
   1517     for (l3_idx = 0; l3_idx < BCM_XGS3_L3_IF_TBL_SIZE(unit); l3_idx++) {
   1518         /* Check if interface index is used. */
   1519         if (!BCM_L3_INTF_USED_GET(unit, l3_idx)) {
   1520             /* Free index found. */
   1521             BCM_L3_INTF_USED_SET(unit, l3_idx);
   1522             break;
   1523         }
   1524     }
   1525     if (l3_idx == BCM_XGS3_L3_IF_TBL_SIZE(unit)) {
   1526         MEM_UNLOCK(unit, EGR_L3_INTFm);
   1527         return BCM_E_FULL;
   1528     }
   1529 
   1530     /* Write EGR_L3_INTF entry */
   1531     sal_memset(&l3_intf, 0, sizeof(egr_l3_intf_entry_t));
   1532     soc_mem_field32_set(unit, EGR_L3_INTFm, &l3_intf, OVIDf, ovid);
   1533 
   1534     /* IVID field is used as the DVP */
   1535     if (soc_feature(unit, soc_feature_subport_enhanced)) {
   1536         soc_mem_field32_set(unit, EGR_L3_INTFm, &l3_intf, IVIDf, vp);
   1537     }
   1538 
   1539     if (soc_mem_field_valid(unit, EGR_L3_INTFm, IVID_VALIDf)) {
   1540         soc_mem_field32_set(unit, EGR_L3_INTFm, &l3_intf, IVID_VALIDf, 1);
   1541     } else {
   1542         soc_mem_field32_set(unit, EGR_L3_INTFm, &l3_intf, IVID_PRESENT_ACTIONf,
   1543                             1);
   1544         soc_mem_field32_set(unit, EGR_L3_INTFm, &l3_intf, IVID_ABSENT_ACTIONf,
   1545                             1);
   1546     }
   1547     rv = soc_mem_write(unit, EGR_L3_INTFm, MEM_BLOCK_ALL, l3_idx, &l3_intf);
   1548     if (rv < 0) {
   1549         MEM_UNLOCK(unit, EGR_L3_INTFm);
   1550         goto cleanup;
   1551     }
   1552     MEM_UNLOCK(unit, EGR_L3_INTFm);
   1553 
   1554     /* the LLTAG subport uses EGR_L3_NEXT_HOP table instead of EGR_VLAN_XLATE table
   1555          * to add LLTAG
   1556          */
   1557     if (soc_feature(unit, soc_feature_lltag) && 
   1558        ((config->criteria == BCM_SUBPORT_MATCH_PKT_VID) ||
   1559        (config->criteria == BCM_SUBPORT_MATCH_PKT_VID_INNER_VLAN) ||
   1560        (config->criteria == BCM_SUBPORT_MATCH_PKT_VID_OUTER_VLAN))) {
   1561         /* Obtain the nh_index from DVP_Table for each Priority */
   1562         rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm,
   1563                           MEM_BLOCK_ALL, nh_index, &egr_nh);
   1564         BCM_IF_ERROR_RETURN(rv);
   1565      
   1566         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, ENTRY_TYPEf, 0x2);
   1567               
   1568         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, SD_TAG__DVPf,
   1569                            (vp_base + config->int_pri));
   1570 
   1571         /* use SD_TAG view becuase the ENTRY_TYPE is 2 */
   1572         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 
   1573                             SD_TAG__HG_HDR_SELf, 1);
   1574 
   1575         /* Must set DVP to 0 to avoid the Entry type being forced to 0 */
   1576         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 
   1577                             SD_TAG__DVPf, 0);
   1578 
   1579         /* Add the LLTAG for outgoing packets */
   1580         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 
   1581                             SD_TAG__LLTAG_VIDf, config->pkt_vlan);
   1582         
   1583         /* Set the LLTAG ACTION as  ADDLLTAG */
   1584         soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 
   1585                             SD_TAG__LLTAG_ACTIONSf, 0x04);
   1586              
   1587         rv = soc_mem_write(unit, EGR_L3_NEXT_HOPm,
   1588                         MEM_BLOCK_ALL, nh_index, &egr_nh);
   1589         BCM_IF_ERROR_RETURN(rv);   
   1590         /*use DVP in SOURCE_VP table to store the match inner VLAN or outer VLAN. */
   1591         rv = soc_mem_read(unit, SOURCE_VPm, 
   1592                         MEM_BLOCK_ALL, vp_base + config->int_pri, &svp);
   1593         BCM_IF_ERROR_RETURN(rv);
   1594         if (config->criteria == BCM_SUBPORT_MATCH_PKT_VID_INNER_VLAN) {
   1595             soc_mem_field32_set(unit, SOURCE_VPm, &svp, 
   1596                             DVPf, config->inner_vlan);
   1597         } else if (config->criteria == BCM_SUBPORT_MATCH_PKT_VID_OUTER_VLAN) {
   1598             soc_mem_field32_set(unit, SOURCE_VPm, &svp, 
   1599                             DVPf, config->outer_vlan);
   1600         }
   1601         rv = soc_mem_write(unit, SOURCE_VPm,
   1602                         MEM_BLOCK_ALL, vp_base + config->int_pri, &svp); 
   1603         if (rv < 0) {
   1604             goto cleanup;
   1605         }
   1606     } else {
   1607         /* ************************* */
   1608         /* Write EGR_VLAN_XLATE table  */
   1609         /* ************************* */
   1610 
   1611         bcm_vlan_action_set_t_init(&action);
   1612         /* Create a profile entry that replaces the outer vid
   1613                * with the new 16-bit vlan tag.
   1614                */
   1615         action.ot_outer = bcmVlanActionReplace;
   1616         action.dt_outer = bcmVlanActionReplace;
   1617         action.dt_inner = bcmVlanActionDelete;
   1618         rv = _bcm_trx_egr_vlan_action_profile_entry_add(unit, &action, &egr_profile_idx);
   1619         if (rv < 0) {
   1620             goto cleanup;
   1621         }
   1622 #ifdef BCM_TRIDENT3_SUPPORT
   1623         if (SOC_MEM_IS_VALID(unit, EGR_VLAN_XLATE_1_DOUBLEm)) {
   1624            egr_mem = EGR_VLAN_XLATE_1_DOUBLEm;
   1625         } else
   1626 #endif
   1627         {
   1628            egr_mem = EGR_VLAN_XLATEm;
   1629         }
   1630 #ifdef BCM_TRIDENT3_SUPPORT
   1631         if (soc_feature(unit, soc_feature_base_valid)) {
   1632             soc_mem_field32_set(unit, egr_mem, egr_vent, BASE_VALID_0f, 3);
   1633             soc_mem_field32_set(unit, egr_mem, egr_vent, BASE_VALID_1f, 7);
   1634             soc_mem_field32_set(unit, egr_mem, egr_vent, KEY_TYPEf, 0x01);
   1635             soc_mem_field32_set(unit, egr_mem, egr_vent, DATA_TYPEf, 1);
   1636         } else
   1637 #endif
   1638         {
   1639             soc_mem_field32_set(unit, egr_mem, egr_vent, VALIDf, 1);
   1640 #ifdef BCM_TRIUMPH3_SUPPORT
   1641             if (SOC_IS_TRIUMPH3(unit)) {
   1642                 soc_mem_field32_set(unit, egr_mem, egr_vent, KEY_TYPEf, 0x01);
   1643             } else
   1644 #endif
   1645             {
   1646                soc_mem_field32_set(unit, egr_mem, egr_vent, ENTRY_TYPEf, 0x01);
   1647             }
   1648         }
   1649 
   1650         soc_mem_field32_set(unit, egr_mem, egr_vent, OVIDf, ovid);
   1651         soc_mem_field32_set(unit, egr_mem, egr_vent, DVPf, (vp_base + config->int_pri));
   1652 
   1653         soc_mem_field32_set(unit, egr_mem, egr_vent, TAG_ACTION_PROFILE_PTRf, egr_profile_idx);
   1654         soc_mem_field32_set(unit, egr_mem, egr_vent, NEW_OTAG_VPTAGf, config->pkt_vlan);
   1655         soc_mem_field32_set(unit, egr_mem, egr_vent, NEW_OTAG_VPTAG_SELf, 1);
   1656 
   1657         rv = soc_mem_insert_return_old(unit, egr_mem, MEM_BLOCK_ALL,
   1658                                       egr_vent, egr_vent);
   1659         if (rv == SOC_E_EXISTS) {
   1660             /* Delete the old vlan translate profile entry */
   1661 
   1662             egr_profile_idx = soc_mem_field32_get(unit, egr_mem, egr_vent,
   1663                                                   TAG_ACTION_PROFILE_PTRf);
   1664             rv = _bcm_trx_egr_vlan_action_profile_entry_delete(unit, egr_profile_idx);
   1665         }
   1666 
   1667         if (rv < 0) {
   1668             goto cleanup;
   1669         }
   1670     }
   1671     /* **************************   */
   1672     /* Write Ingress VLAN_XLATE table  */
   1673     /* **************************   */
   1674     bcm_vlan_action_set_t_init(&action);
   1675     switch (config->criteria) {
   1676         case BCM_SUBPORT_MATCH_PKT_VID:
   1677             action.ut_outer = bcmVlanActionAdd;
   1678             action.ut_outer_pkt_prio = bcmVlanActionAdd;
   1679             action.ot_outer = bcmVlanActionReplace;
   1680             action.ot_outer_prio = bcmVlanActionAdd;
   1681             action.ot_outer_pkt_prio = bcmVlanActionReplace;
   1682             action.dt_outer = bcmVlanActionReplace;
   1683             action.dt_outer_prio = bcmVlanActionAdd;
   1684             action.dt_outer_pkt_prio = bcmVlanActionReplace;
   1685             break;
   1686         case BCM_SUBPORT_MATCH_PKT_VID_INNER_VLAN:
   1687             action.ut_outer = bcmVlanActionAdd;
   1688             action.ut_outer_pkt_prio = bcmVlanActionAdd;
   1689             action.ot_outer = bcmVlanActionReplace;
   1690             action.ot_outer_prio = bcmVlanActionAdd;
   1691             action.ot_outer_pkt_prio = bcmVlanActionReplace;
   1692             action.dt_outer = bcmVlanActionReplace;
   1693             action.dt_outer_prio = bcmVlanActionAdd;
   1694             action.dt_outer_pkt_prio = bcmVlanActionReplace;
   1695             action.it_outer = bcmVlanActionAdd;
   1696             action.it_outer_pkt_prio = bcmVlanActionAdd;
   1697             action.it_inner = bcmVlanActionDelete;            
   1698             action.it_inner_prio = bcmVlanActionDelete;
   1699             action.dt_inner = bcmVlanActionDelete;            
   1700             action.dt_inner_prio = bcmVlanActionDelete;
   1701             break;
   1702         case BCM_SUBPORT_MATCH_PKT_VID_OUTER_VLAN:
   1703             action.ot_outer = bcmVlanActionReplace;
   1704             action.ot_outer_prio = bcmVlanActionAdd;
   1705             action.ot_outer_pkt_prio = bcmVlanActionReplace;
   1706             action.dt_outer = bcmVlanActionReplace;
   1707             action.dt_outer_prio = bcmVlanActionAdd;
   1708             action.dt_outer_pkt_prio = bcmVlanActionReplace;
   1709             break;
   1710         default:
   1711             action.ot_outer = bcmVlanActionReplace;
   1712             action.ot_outer_prio = bcmVlanActionReplace;
   1713             action.dt_outer = bcmVlanActionReplace;
   1714             action.dt_outer_prio = bcmVlanActionReplace;
   1715             break;
   1716     }
   1717     
   1718     rv = _bcm_trx_vlan_action_profile_entry_add(unit, &action, &ing_profile_idx);
   1719     if (rv < 0) {
   1720         goto cleanup;
   1721     }
   1722     rv = _bcm_esw_vlan_xlate_key_type_value_get(unit, 
   1723                              VLXLT_HASH_KEY_TYPE_OVID, &key_type_value);
   1724     if (rv < 0) {
   1725         goto cleanup;
   1726     }
   1727 #ifdef BCM_TRIDENT3_SUPPORT
   1728     if (SOC_MEM_IS_VALID(unit, VLAN_XLATE_1_DOUBLEm)) {
   1729         ing_mem = VLAN_XLATE_1_DOUBLEm;
   1730     } else
   1731 #endif
   1732     {
   1733         ing_mem = VLAN_XLATEm;
   1734     }
   1735 #ifdef BCM_TRIDENT3_SUPPORT
   1736     if (soc_feature(unit, soc_feature_base_valid)) {
   1737         soc_mem_field32_set(unit, ing_mem, ing_vent, BASE_VALID_0f, 3);
   1738         soc_mem_field32_set(unit, ing_mem, ing_vent, BASE_VALID_1f, 7);
   1739     } else
   1740 #endif
   1741     {
   1742         soc_mem_field32_set(unit, ing_mem, ing_vent, VALIDf, 1);
   1743     }
   1744 
   1745     if (SOC_MEM_FIELD_VALID(unit, ing_mem, VLAN_ACTION_VALIDf)) {
   1746         soc_mem_field32_set(unit, ing_mem, ing_vent, VLAN_ACTION_VALIDf, 1);
   1747     }
   1748 
   1749     if ((soc_feature(unit, soc_feature_lltag)) &&
   1750         ((BCM_SUBPORT_MATCH_PKT_VID == config->criteria) ||
   1751         (BCM_SUBPORT_MATCH_PKT_VID_INNER_VLAN == config->criteria) ||
   1752         (BCM_SUBPORT_MATCH_PKT_VID_OUTER_VLAN == config->criteria))) {
   1753         if (BCM_SUBPORT_MATCH_PKT_VID == config->criteria) {
   1754             soc_mem_field32_set(unit, ing_mem, ing_vent, KEY_TYPEf,
   1755                                         KT2_PT_XLT_KEY_TYPE_LLVID);   
   1756         } else if (BCM_SUBPORT_MATCH_PKT_VID_INNER_VLAN == config->criteria) {
   1757             soc_mem_field32_set(unit, ing_mem, ing_vent, KEY_TYPEf,
   1758                                         KT2_PT_XLT_KEY_TYPE_LLVID_IVID);
   1759             soc_mem_field32_set(unit, ing_mem, ing_vent, LLTAG__IVIDf,
   1760                                         config->inner_vlan);
   1761         } else if (BCM_SUBPORT_MATCH_PKT_VID_OUTER_VLAN == config->criteria) {
   1762             soc_mem_field32_set(unit, ing_mem, ing_vent, KEY_TYPEf,
   1763                                         KT2_PT_XLT_KEY_TYPE_LLVID_OVID);
   1764             soc_mem_field32_set(unit, ing_mem, ing_vent, LLTAG__OVIDf,
   1765                                         config->outer_vlan);
   1766         }   
   1767 
   1768         soc_mem_field32_set(unit, ing_mem, ing_vent, LLTAG__LLVIDf, config->pkt_vlan);
   1769         soc_mem_field32_set(unit, ing_mem, ing_vent, LLTAG__MODULE_IDf, modid);
   1770         soc_mem_field32_set(unit, ing_mem, ing_vent, LLTAG__PORT_NUMf, local_port);
   1771         soc_mem_field32_set(unit, ing_mem, ing_vent, LLTAG__TAG_ACTION_PROFILE_PTRf,
   1772                                     ing_profile_idx);
   1773         soc_mem_field32_set(unit, ing_mem, ing_vent, LLTAG__NEW_OVIDf, ovid);
   1774         soc_mem_field32_set(unit, ing_mem, ing_vent, LLTAG__NEW_OPRIf, config->int_pri);
   1775         /* Group VP */
   1776         soc_mem_field32_set(unit, ing_mem, ing_vent, LLTAG__SOURCE_VPf, vp_base);
   1777     } else {
   1778         soc_mem_field32_set(unit, ing_mem, ing_vent, KEY_TYPEf, key_type_value);
   1779         soc_mem_field32_set(unit, ing_mem, ing_vent, OVIDf, config->pkt_vlan);
   1780         soc_mem_field32_set(unit, ing_mem, ing_vent, MODULE_IDf, modid);
   1781         soc_mem_field32_set(unit, ing_mem, ing_vent, PORT_NUMf, local_port);
   1782         if (SOC_MEM_FIELD_VALID(unit, ing_mem, RPEf)) {
   1783             soc_mem_field32_set(unit, ing_mem, ing_vent, RPEf, 1);
   1784             soc_mem_field32_set(unit, ing_mem, ing_vent, PRIf, config->int_pri);
   1785         }
   1786         soc_mem_field32_set(unit, ing_mem, ing_vent, TAG_ACTION_PROFILE_PTRf, ing_profile_idx);
   1787         soc_mem_field32_set(unit, ing_mem, ing_vent, NEW_OVIDf, ovid);
   1788         soc_mem_field32_set(unit, ing_mem, ing_vent, SOURCE_VPf, vp_base); /* Group VP */
   1789     }
   1790     /* TD2 type of device indicating Source Field as SGLP */
   1791     if (SOC_MEM_FIELD_VALID(unit, ing_mem, SOURCE_TYPEf)) {
   1792         soc_mem_field32_set(unit, ing_mem, ing_vent, SOURCE_TYPEf, 1);
   1793     }
   1794 
   1795 #ifdef BCM_TRIUMPH3_SUPPORT
   1796     if (SOC_IS_TRIUMPH3(unit)) {
   1797         soc_mem_field32_set(unit, ing_mem, ing_vent, SVP_VALIDf, 1); /* L2 SVP */
   1798     } else 
   1799 #endif
   1800     {
   1801         soc_mem_field32_set(unit, ing_mem, ing_vent, MPLS_ACTIONf, 1); /* L2 SVP */
   1802     }
   1803 
   1804     rv = soc_mem_insert_return_old(unit, ing_mem, MEM_BLOCK_ALL,
   1805                                    ing_vent, ing_vent);
   1806     if (rv == SOC_E_EXISTS) {
   1807         /* Delete the old vlan translate profile entry */
   1808         ing_profile_idx = soc_mem_field32_get(unit, ing_mem,  ing_vent,
   1809                                                       TAG_ACTION_PROFILE_PTRf);
   1810         rv = _bcm_trx_vlan_action_profile_entry_delete(unit, ing_profile_idx);
   1811     }
   1812 
   1813     if (rv < 0) {
   1814         goto cleanup;
   1815     }
   1816 
   1817     _BCM_TR2_SUBPORT_ID_SET(unit, vp, l3_idx);
   1818     BCM_GPORT_SUBPORT_PORT_SET(*port, ((my_modid << 12) | l3_idx));
   1819     
   1820     /* we must set the VT_KEY the same as this subport's property, since the not API avaiable to change the VT_KEY
   1821         * wheh it involves LLTAG
   1822         */
   1823     if (soc_feature(unit, soc_feature_lltag)) {
   1824         rv = soc_mem_read(unit, PORT_TABm, MEM_BLOCK_ALL, local_port, &port_tab);
   1825         if (rv < 0) {
   1826             goto cleanup;
   1827         }
   1828         
   1829         if (BCM_SUBPORT_MATCH_PKT_VID == config->criteria) {
   1830             soc_mem_field32_set(unit, PORT_TABm, &port_tab, VT_KEY_TYPEf, 
   1831                                 KT2_PT_XLT_KEY_TYPE_LLVID);
   1832         } else if(BCM_SUBPORT_MATCH_PKT_VID_INNER_VLAN == config->criteria){
   1833             soc_mem_field32_set(unit, PORT_TABm, &port_tab, VT_KEY_TYPEf, 
   1834                                 KT2_PT_XLT_KEY_TYPE_LLVID_IVID);  
   1835         } else if(BCM_SUBPORT_MATCH_PKT_VID_OUTER_VLAN == config->criteria){
   1836             soc_mem_field32_set(unit, PORT_TABm, &port_tab, VT_KEY_TYPEf, 
   1837                                 KT2_PT_XLT_KEY_TYPE_LLVID_OVID);  
   1838         }
   1839 
   1840         rv = soc_mem_write(unit, PORT_TABm,
   1841                             MEM_BLOCK_ALL, local_port, &port_tab);
   1842         if (rv < 0) {
   1843             goto cleanup;
   1844         }
   1845     }
   1846     return BCM_E_NONE;
   1847 cleanup:
   1848     if (l3_idx != -1) {
   1849         BCM_L3_INTF_USED_CLR(unit, l3_idx);
   1850     }
   1851 
   1852 #ifdef BCM_WARM_BOOT_SUPPORT
   1853     SOC_CONTROL_LOCK(unit);
   1854     SOC_CONTROL(unit)->scache_dirty = 1;
   1855     SOC_CONTROL_UNLOCK(unit);
   1856 #endif
   1857 
   1858     return rv;
   1859 }
   1860 
   1861 STATIC int
   1862 _bcm_tr2_subport_port_get(int unit, int l3_idx,
   1863                          bcm_subport_config_t *config);
   1864 
   1865 STATIC int
   1866 _bcm_tr2_subport_port_delete(int unit, int l3_idx, int vp)
   1867 {
   1868     int rv, vp_base, vt_index, nh_index=-1,nhi_group_en=0;
   1869     int nh_group=-1, nh_profile_idx=0; 
   1870     egr_l3_intf_entry_t l3_intf;
   1871     ing_l3_next_hop_entry_t ing_nh;
   1872     egr_l3_next_hop_entry_t egr_nh;
   1873     ing_dvp_table_entry_t dvp;
   1874     nhi_group_tc_profile_entry_t nhi_entry;
   1875     bcm_port_t port = 0;
   1876     bcm_module_t modid = 0;
   1877     bcm_vlan_t pkt_vlan = 0, ovid = 0;
   1878     uint32 egr_profile_idx, ing_profile_idx, port_class = 0;
   1879     bcm_subport_config_t config;
   1880     int key_type_value;
   1881     uint32              egr_vent[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer.     */
   1882     uint32              ing_vent[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer.     */
   1883     soc_mem_t egr_mem = EGR_VLAN_XLATEm, ing_mem = VLAN_XLATEm;
   1884 
   1885     sal_memset(egr_vent, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
   1886     sal_memset(ing_vent, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
   1887 
   1888 
   1889     _TR2_SUBPORT_CHECK_INIT(unit);
   1890     
   1891     sal_memset(&config, 0x0, sizeof(bcm_subport_config_t));
   1892     rv = soc_mem_read(unit, EGR_L3_INTFm, MEM_BLOCK_ALL, l3_idx, &l3_intf);
   1893     BCM_IF_ERROR_RETURN(rv);
   1894 
   1895     /* Get the base group VP */
   1896     vp_base = vp & ~(0x7);
   1897 
   1898     if (soc_feature(unit, soc_feature_subport_enhanced)) {
   1899 #if defined(BCM_KATANA2_SUPPORT)
   1900         if (SOC_IS_KATANA2(unit)) {
   1901             vp_base = vp;
   1902         }
   1903 #endif /* defined(BCM_KATANA2_SUPPORT) */        
   1904         /* Get the group's next-hop index */
   1905         rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base, &dvp);
   1906         BCM_IF_ERROR_RETURN(rv);
   1907         if (soc_feature(unit, soc_feature_lltag)) {
   1908             if (soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NHI_GROUP_ENf)) {
   1909                 
   1910                 nhi_group_en = 1;
   1911                 nh_group =  soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NHI_GROUPf);
   1912                 nh_profile_idx = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, 
   1913                                     TC_PROFILE_INDEXf);
   1914                 rv = READ_NHI_GROUP_TC_PROFILEm(unit, MEM_BLOCK_ALL, 
   1915                             nh_profile_idx*16 + vp - vp_base, &nhi_entry);
   1916                 BCM_IF_ERROR_RETURN(rv);
   1917                 rv = _bcm_tr2_subport_port_get(unit, l3_idx, &config);
   1918                 BCM_IF_ERROR_RETURN(rv);
   1919                 nh_index = nh_group + soc_NHI_GROUP_TC_PROFILEm_field32_get(unit, 
   1920                             &nhi_entry, NHI_OFFSETf); 
   1921             } else {
   1922                 nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   1923             }
   1924         } else {
   1925             nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   1926         }
   1927         /* Get the group's OVID from the group's egress next-hop entry */
   1928         rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm,
   1929                           MEM_BLOCK_ALL, nh_index, &egr_nh);
   1930         BCM_IF_ERROR_RETURN(rv);
   1931         if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3__OVIDf)) {
   1932             ovid = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, L3__OVIDf);
   1933         } else {
   1934             ovid = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, OVIDf);
   1935         }
   1936     }
   1937 
   1938     if (nh_index == -1) {
   1939         return BCM_E_INTERNAL;
   1940     }
   1941 
   1942     /* Get the egress port class */
   1943     BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   1944                                       nh_index, &ing_nh));
   1945 
   1946     if (soc_feature(unit, soc_feature_generic_dest)) {
   1947         uint32 dt, dv;
   1948         dv = soc_mem_field32_dest_get(unit, ING_L3_NEXT_HOPm,
   1949                 &ing_nh, DESTINATIONf, &dt);
   1950         if (dt != SOC_MEM_FIF_DEST_LAG) {
   1951             modid = (dv & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >>
   1952                       SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS;
   1953             port  = dv & SOC_MEM_FIF_DGPP_PORT_MASK;
   1954             rv = bcm_esw_port_class_get(unit, port, bcmPortClassVlanTranslateEgress,
   1955                                     &port_class);
   1956             BCM_IF_ERROR_RETURN(rv);
   1957         }
   1958     } else {
   1959 
   1960         if (!soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) {
   1961             modid = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, MODULE_IDf);
   1962             port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf);
   1963             rv = bcm_esw_port_class_get(unit, port, bcmPortClassVlanTranslateEgress,
   1964                                     &port_class);
   1965             BCM_IF_ERROR_RETURN(rv);
   1966         } 
   1967     }
   1968 
   1969 #ifdef BCM_TRIDENT3_SUPPORT
   1970     if (SOC_MEM_IS_VALID(unit, EGR_VLAN_XLATE_1_DOUBLEm)) {
   1971         egr_mem = EGR_VLAN_XLATE_1_DOUBLEm;
   1972     } else
   1973 #endif
   1974     {
   1975         egr_mem = EGR_VLAN_XLATEm;
   1976     }
   1977 
   1978     /*We think only LLTAG subport uses NHI_GROUP_TC_PROFILE table*/
   1979     if (!(soc_feature(unit, soc_feature_lltag) && (nhi_group_en == 1))) {
   1980         /* Find the egress vlan translate entry */
   1981         soc_mem_field32_set(unit, egr_mem, egr_vent, OVIDf, ovid);
   1982         soc_mem_field32_set(unit, egr_mem, egr_vent, DVPf, vp);
   1983 #ifdef BCM_TRIDENT3_SUPPORT
   1984         if (soc_feature(unit, soc_feature_base_valid)) {
   1985             soc_mem_field32_set(unit, egr_mem, egr_vent, BASE_VALID_0f, 3);
   1986             soc_mem_field32_set(unit, egr_mem, egr_vent, BASE_VALID_1f, 7);
   1987             soc_mem_field32_set(unit, egr_mem, egr_vent, KEY_TYPEf, 0x01);
   1988             soc_mem_field32_set(unit, egr_mem, egr_vent, DATA_TYPEf, 1);
   1989         } else
   1990 #endif
   1991         {
   1992             soc_mem_field32_set(unit, egr_mem, egr_vent, VALIDf, 1);
   1993 #ifdef BCM_TRIUMPH3_SUPPORT
   1994             if (SOC_IS_TRIUMPH3(unit)) {
   1995                 soc_mem_field32_set(unit, egr_mem, egr_vent, KEY_TYPEf, 0x01);
   1996             } else
   1997 #endif
   1998             {
   1999                soc_mem_field32_set(unit, egr_mem, egr_vent, ENTRY_TYPEf, 0x01);
   2000             }
   2001         }
   2002 
   2003         MEM_LOCK(unit, egr_mem);
   2004         rv = soc_mem_search(unit, egr_mem, MEM_BLOCK_ALL, &vt_index,
   2005                             egr_vent, egr_vent, 0);
   2006         if (rv < 0) {
   2007             MEM_UNLOCK(unit, egr_mem);
   2008             return rv;
   2009         }
   2010 
   2011         /* Get the old vlan translate profile entry */
   2012         egr_profile_idx = soc_mem_field32_get(unit, egr_mem, egr_vent,
   2013                                                           TAG_ACTION_PROFILE_PTRf);
   2014 
   2015         /* Delete the egress vlan translate entry */
   2016         rv = soc_mem_delete(unit, egr_mem, MEM_BLOCK_ALL, &egr_vent);
   2017         MEM_UNLOCK(unit, egr_mem);
   2018         BCM_IF_ERROR_RETURN(rv);
   2019 
   2020         /* Delete the old vlan translate profile entry */
   2021         rv = _bcm_trx_egr_vlan_action_profile_entry_delete(unit, egr_profile_idx);
   2022         BCM_IF_ERROR_RETURN(rv);
   2023 
   2024         /* Find vlan translate entry */
   2025         pkt_vlan = soc_mem_field32_get(unit, egr_mem, egr_vent, NEW_OTAG_VPTAGf);
   2026         rv = _bcm_esw_vlan_xlate_key_type_value_get(unit, 
   2027                                  VLXLT_HASH_KEY_TYPE_OVID, &key_type_value);
   2028         BCM_IF_ERROR_RETURN(rv);
   2029     }
   2030     
   2031     sal_memset(ing_vent, 0, sizeof(ing_vent));
   2032 #ifdef BCM_TRIDENT3_SUPPORT
   2033     if (SOC_MEM_IS_VALID(unit, VLAN_XLATE_1_DOUBLEm)) {
   2034         ing_mem = VLAN_XLATE_1_DOUBLEm;
   2035     } else
   2036 #endif
   2037     {
   2038         ing_mem = VLAN_XLATEm;
   2039     }
   2040 #ifdef BCM_TRIDENT3_SUPPORT
   2041     if (soc_feature(unit, soc_feature_base_valid)) {
   2042         soc_mem_field32_set(unit, ing_mem, ing_vent, BASE_VALID_0f, 3);
   2043         soc_mem_field32_set(unit, ing_mem, ing_vent, BASE_VALID_1f, 7);
   2044     } else
   2045 #endif
   2046     {
   2047         soc_mem_field32_set(unit, ing_mem, ing_vent, VALIDf, 1);
   2048     }
   2049 
   2050     if ((soc_feature(unit, soc_feature_lltag)) &&
   2051         (config.criteria > BCM_SUBPORT_MATCH_INVALID) &&
   2052         (config.criteria < BCM_SUBPORT_MATCH_COUNT)) {
   2053         if (config.criteria == BCM_SUBPORT_MATCH_PKT_VID) {
   2054             soc_mem_field32_set(unit, ing_mem, ing_vent, KEY_TYPEf,
   2055                     KT2_PT_XLT_KEY_TYPE_LLVID);
   2056             soc_mem_field32_set(unit, ing_mem, ing_vent, LLTAG__LLVIDf,
   2057                     config.pkt_vlan);
   2058         } else if (config.criteria == BCM_SUBPORT_MATCH_PKT_VID_INNER_VLAN) {
   2059             soc_mem_field32_set(unit, ing_mem, ing_vent, KEY_TYPEf,
   2060                     KT2_PT_XLT_KEY_TYPE_LLVID_IVID);
   2061             soc_mem_field32_set(unit, ing_mem, ing_vent, LLTAG__LLVIDf,
   2062                     config.pkt_vlan);
   2063             soc_mem_field32_set(unit, ing_mem, ing_vent, LLTAG__IVIDf,
   2064                     config.inner_vlan);   
   2065         } else {
   2066             soc_mem_field32_set(unit, ing_mem, ing_vent, KEY_TYPEf,
   2067                     KT2_PT_XLT_KEY_TYPE_LLVID_OVID);
   2068             soc_mem_field32_set(unit, ing_mem, ing_vent, LLTAG__LLVIDf,
   2069                     config.pkt_vlan);
   2070             soc_mem_field32_set(unit, ing_mem, ing_vent, LLTAG__OVIDf,
   2071                     config.outer_vlan);
   2072         }
   2073     } else { 
   2074         soc_mem_field32_set(unit, ing_mem, ing_vent, KEY_TYPEf,
   2075                     key_type_value);
   2076         soc_mem_field32_set(unit, ing_mem, ing_vent, OVIDf, pkt_vlan);
   2077     }
   2078  
   2079     soc_mem_field32_set(unit, ing_mem, ing_vent, MODULE_IDf, modid);
   2080     soc_mem_field32_set(unit, ing_mem, ing_vent, PORT_NUMf, port);
   2081 
   2082     /* TD2 type of device indicating Source Field as SGLP */
   2083     if (SOC_MEM_FIELD_VALID(unit, ing_mem, SOURCE_TYPEf)) {
   2084         soc_mem_field32_set(unit, ing_mem, ing_vent, SOURCE_TYPEf, 1);
   2085     }
   2086 
   2087     MEM_LOCK(unit, ing_mem);
   2088     
   2089     rv = soc_mem_search(unit, ing_mem, MEM_BLOCK_ALL, &vt_index,
   2090                         ing_vent, ing_vent, 0);
   2091     if (rv < 0) {
   2092         MEM_UNLOCK(unit, ing_mem);
   2093         return rv;
   2094     }
   2095 
   2096     /* Get the old vlan translate profile entry */
   2097     ing_profile_idx = soc_mem_field32_get(unit, ing_mem, ing_vent,
   2098                                                   TAG_ACTION_PROFILE_PTRf);
   2099 
   2100     /* Delete the ingress vlan translate entry */
   2101     rv = soc_mem_delete(unit, ing_mem, MEM_BLOCK_ALL, ing_vent);
   2102     MEM_UNLOCK(unit, ing_mem);
   2103     BCM_IF_ERROR_RETURN(rv);
   2104 
   2105     /* Delete the old vlan translate profile entry */
   2106     rv = _bcm_trx_vlan_action_profile_entry_delete(unit, ing_profile_idx);
   2107     BCM_IF_ERROR_RETURN(rv);
   2108 
   2109     /* Clear the EGR_L3_INTF entry */
   2110     sal_memset(&l3_intf, 0, sizeof(egr_l3_intf_entry_t));
   2111     rv = soc_mem_write(unit, EGR_L3_INTFm, MEM_BLOCK_ALL, l3_idx, &l3_intf);
   2112 
   2113     /* Free the L3_INTF index */
   2114     BCM_L3_INTF_USED_CLR(unit, l3_idx);
   2115 
   2116     if (soc_feature(unit, soc_feature_gport_service_counters)) {
   2117         bcm_gport_t gport;
   2118 
   2119         /* Release Service counter, if any */
   2120         BCM_GPORT_SUBPORT_PORT_SET(gport, vp);
   2121         _bcm_esw_flex_stat_handle_free(unit, _bcmFlexStatTypeGport, gport);
   2122     }
   2123 
   2124     /* Clear the subport usage SW state */
   2125     _BCM_TR2_SUBPORT_ID_CLR(unit, vp);
   2126 
   2127 #ifdef BCM_WARM_BOOT_SUPPORT
   2128     SOC_CONTROL_LOCK(unit);
   2129     SOC_CONTROL(unit)->scache_dirty = 1;
   2130     SOC_CONTROL_UNLOCK(unit);
   2131 #endif
   2132 
   2133     return BCM_E_NONE;
   2134 }
   2135 
   2136 /*
   2137  * Function:
   2138  *      bcm_subport_port_delete
   2139  * Purpose:
   2140  *      Delete a subport 
   2141  * Parameters:
   2142  *      unit   - (IN) Device Number
   2143  *      port   - (IN) GPORT (generic port) identifier
   2144  * Returns:
   2145  *      BCM_E_XXX
   2146  */
   2147 int
   2148 bcm_tr2_subport_port_delete(int unit, bcm_gport_t port)
   2149 {
   2150     egr_l3_intf_entry_t l3_intf;
   2151     int l3_idx, vp=-1, rv;
   2152     bcm_module_t modid, my_modid;
   2153 
   2154     _TR2_SUBPORT_CHECK_INIT(unit);
   2155 
   2156     BCM_IF_ERROR_RETURN (bcm_esw_stk_my_modid_get(unit, &my_modid));
   2157     modid = (BCM_GPORT_SUBPORT_PORT_GET(port) >> 12) & SOC_MODID_MAX(unit);
   2158     if (modid != my_modid) {
   2159         return BCM_E_PORT;
   2160     }
   2161 
   2162     l3_idx = BCM_GPORT_SUBPORT_PORT_GET(port) & 0xfff;
   2163     if (l3_idx >= BCM_XGS3_L3_IF_TBL_SIZE(unit)) { 
   2164         return (BCM_E_PARAM);
   2165     }
   2166 
   2167     rv = soc_mem_read(unit, EGR_L3_INTFm, MEM_BLOCK_ALL, l3_idx, &l3_intf);
   2168     BCM_IF_ERROR_RETURN(rv);
   2169 
   2170     
   2171     vp = soc_mem_field32_get(unit, EGR_L3_INTFm, &l3_intf, IVIDf);
   2172     if (_BCM_TR2_SUBPORT_ID_GET(unit, vp) != l3_idx) {
   2173         return BCM_E_NOT_FOUND;
   2174     }
   2175 
   2176 
   2177     if (vp == -1) {
   2178         return BCM_E_INTERNAL;
   2179     }
   2180 
   2181     return _bcm_tr2_subport_port_delete(unit, l3_idx, vp);
   2182 }
   2183 
   2184 STATIC int
   2185 _bcm_tr2_subport_port_get(int unit, int l3_idx,
   2186                          bcm_subport_config_t *config)
   2187 {
   2188     int vp=-1, rv, vp_base = 0, vt_index, nh_index=-1, nh_group=-1,  group_en = 0, nh_profile_idx=0;
   2189     egr_l3_intf_entry_t l3_intf;
   2190     egr_l3_next_hop_entry_t egr_nh;
   2191     nhi_group_tc_profile_entry_t nhi_entry;
   2192     ing_dvp_table_entry_t dvp;
   2193     source_vp_entry_t svp;
   2194     bcm_vlan_t ovid = 0;
   2195     port_tab_entry_t port_tab;
   2196     ing_l3_next_hop_entry_t ing_nh;    
   2197     bcm_port_t local_port = 0;
   2198     uint32              egr_vent[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer.     */
   2199     soc_mem_t egr_mem = EGR_VLAN_XLATEm;
   2200     uint32 dest_type, dest_val;
   2201     
   2202     rv = soc_mem_read(unit, EGR_L3_INTFm, MEM_BLOCK_ALL, l3_idx, &l3_intf);
   2203     BCM_IF_ERROR_RETURN(rv);
   2204 
   2205     if (soc_feature(unit, soc_feature_subport_enhanced)) {
   2206         vp = soc_mem_field32_get(unit, EGR_L3_INTFm, &l3_intf, IVIDf);
   2207         if (_BCM_TR2_SUBPORT_ID_GET(unit, vp) != l3_idx) {
   2208             return BCM_E_NOT_FOUND;
   2209         }
   2210     }
   2211 
   2212     if (vp == -1) {
   2213         return BCM_E_INTERNAL;
   2214     }
   2215 
   2216     /* Get the base group VP */
   2217     rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp);
   2218     BCM_IF_ERROR_RETURN(rv);
   2219     if (soc_feature(unit, soc_feature_lltag)) {
   2220         rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp, &dvp);
   2221         BCM_IF_ERROR_RETURN(rv);
   2222         if (soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NHI_GROUP_ENf)) {
   2223             vp_base = vp - (vp%8);    
   2224         } else {
   2225             vp_base = soc_SOURCE_VPm_field32_get(unit, &svp, DVPf);
   2226         }
   2227     } else {
   2228         if (soc_feature(unit, soc_feature_generic_dest)) {
   2229             dest_val = soc_mem_field32_dest_get(unit, SOURCE_VPm,
   2230                        &svp, DESTINATIONf, &dest_type);
   2231             if (dest_type == SOC_MEM_FIF_DEST_DVP) {
   2232                 vp_base = dest_val;
   2233             }
   2234         } else {
   2235             vp_base = soc_SOURCE_VPm_field32_get(unit, &svp, DVPf);
   2236         }
   2237     }
   2238     /* Set the config data to be returned */
   2239     config->int_pri = vp - vp_base;
   2240 
   2241     /* Get the group's next-hop index */
   2242     if (soc_feature(unit, soc_feature_subport_enhanced)) {
   2243         rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base, &dvp);
   2244         BCM_IF_ERROR_RETURN(rv);
   2245         if (soc_feature(unit, soc_feature_lltag)) {
   2246             if (soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NHI_GROUP_ENf)) {
   2247                 group_en = 1;
   2248                 nh_group =  soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NHI_GROUPf);
   2249                 nh_profile_idx = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, 
   2250                                     TC_PROFILE_INDEXf);
   2251                 rv = READ_NHI_GROUP_TC_PROFILEm(unit, MEM_BLOCK_ALL, 
   2252                                     nh_profile_idx*16 + config->int_pri, &nhi_entry);
   2253                 BCM_IF_ERROR_RETURN(rv);
   2254                 nh_index = nh_group + soc_NHI_GROUP_TC_PROFILEm_field32_get(unit, 
   2255                                     &nhi_entry, NHI_OFFSETf); 
   2256             } else {
   2257                 nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   2258             }
   2259         } else {
   2260             nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   2261         }
   2262 
   2263         /* Get the group's OVID from the group's egress next-hop entry */
   2264         rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm,
   2265                           MEM_BLOCK_ALL, nh_index, &egr_nh);
   2266         BCM_IF_ERROR_RETURN(rv);
   2267 
   2268         if (soc_feature(unit, soc_feature_lltag) && (group_en == 1)) {
   2269              /* Get the modid and port_class for the destination port */
   2270             rv = soc_mem_read(unit, ING_L3_NEXT_HOPm,
   2271                       MEM_BLOCK_ALL, nh_index, &ing_nh);
   2272             BCM_IF_ERROR_RETURN(rv);
   2273             if (!soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, &ing_nh, Tf)) {
   2274                 local_port = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm,
   2275                                          &ing_nh, PORT_NUMf);
   2276             }
   2277 
   2278             rv = soc_mem_read(unit, PORT_TABm, MEM_BLOCK_ALL, local_port, &port_tab);
   2279             BCM_IF_ERROR_RETURN(rv);
   2280             switch (soc_PORT_TABm_field32_get(unit, &port_tab, VT_KEY_TYPEf)) {
   2281                 case KT2_PT_XLT_KEY_TYPE_LLVID:
   2282                     config->criteria = BCM_SUBPORT_MATCH_PKT_VID;
   2283                     config->pkt_vlan = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 
   2284                                     &egr_nh, SD_TAG__LLTAG_VIDf);
   2285                     break;
   2286                 case KT2_PT_XLT_KEY_TYPE_LLVID_IVID:
   2287                     config->criteria = BCM_SUBPORT_MATCH_PKT_VID_INNER_VLAN;
   2288                     config->pkt_vlan = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 
   2289                                     &egr_nh, SD_TAG__LLTAG_VIDf);
   2290                     config->inner_vlan= soc_SOURCE_VPm_field32_get(unit, &svp, DVPf);
   2291                     break;
   2292                 case KT2_PT_XLT_KEY_TYPE_LLVID_OVID:
   2293                     config->criteria = BCM_SUBPORT_MATCH_PKT_VID_OUTER_VLAN;
   2294                     config->pkt_vlan = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 
   2295                                     &egr_nh, SD_TAG__LLTAG_VIDf);
   2296                     config->outer_vlan = soc_SOURCE_VPm_field32_get(unit, &svp, DVPf);
   2297                     break;
   2298                 default:    
   2299                     break;
   2300             }
   2301         } else {
   2302             if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, L3__OVIDf)) {
   2303                 ovid = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, L3__OVIDf);
   2304             } else {
   2305                 ovid = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, OVIDf);
   2306             }
   2307             /* Find the egress vlan translate entry */
   2308 #ifdef BCM_TRIDENT3_SUPPORT
   2309             if (SOC_MEM_IS_VALID(unit, EGR_VLAN_XLATE_1_DOUBLEm)) {
   2310                 egr_mem = EGR_VLAN_XLATE_1_DOUBLEm;
   2311             } else
   2312 #endif
   2313             {
   2314                 egr_mem = EGR_VLAN_XLATEm;
   2315             }
   2316             sal_memset(egr_vent, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
   2317 #ifdef BCM_TRIDENT3_SUPPORT
   2318             if (soc_feature(unit, soc_feature_base_valid)) {
   2319                 soc_mem_field32_set(unit, egr_mem, egr_vent, BASE_VALID_0f, 3);
   2320                 soc_mem_field32_set(unit, egr_mem, egr_vent, BASE_VALID_1f, 7);
   2321                 soc_mem_field32_set(unit, egr_mem, egr_vent, KEY_TYPEf, 1);
   2322                 soc_mem_field32_set(unit, egr_mem, egr_vent, DATA_TYPEf, 1);
   2323             } else
   2324 #endif
   2325             {
   2326                 soc_mem_field32_set(unit, egr_mem, egr_vent, VALIDf, 1);
   2327 #ifdef BCM_TRIUMPH3_SUPPORT
   2328                 if (SOC_IS_TRIUMPH3(unit)) {
   2329                     soc_mem_field32_set(unit, egr_mem, egr_vent, KEY_TYPEf, 0x01);
   2330                 } else
   2331 #endif
   2332                 {
   2333                     soc_mem_field32_set(unit, egr_mem, egr_vent, ENTRY_TYPEf, 0x01);
   2334                 }
   2335             }
   2336             soc_mem_field32_set(unit, egr_mem, egr_vent, OVIDf, ovid);
   2337             soc_mem_field32_set(unit, egr_mem, egr_vent, DVPf, vp);
   2338 
   2339             rv = soc_mem_search(unit, egr_mem, MEM_BLOCK_ALL, &vt_index,
   2340                             egr_vent, egr_vent, 0);
   2341             if (rv < 0) {
   2342                 return rv;
   2343             }
   2344     
   2345             /* Find pkt_vlan from egress vlan translate entry */
   2346 
   2347             config->pkt_vlan = soc_mem_field32_get(unit, egr_mem, egr_vent,
   2348                                                 NEW_OTAG_VPTAGf);
   2349         }
   2350 	}	
   2351     /* Get the subport group ID */
   2352     BCM_GPORT_SUBPORT_GROUP_SET(config->group, vp_base); 
   2353 
   2354     return BCM_E_NONE;
   2355 }
   2356 
   2357 /*
   2358  * Function:
   2359  *      bcm_subport_port_get
   2360  * Purpose:
   2361  *      Get a subport
   2362  * Parameters:
   2363  *      unit   - (IN) Device Number
   2364  *      port   - (IN) GPORT (generic port) identifier
   2365  *      config - (OUT) Subport config information
   2366  * Returns:
   2367  *      BCM_E_XXX
   2368  */     
   2369 int
   2370 bcm_tr2_subport_port_get(int unit, bcm_gport_t port,
   2371                         bcm_subport_config_t *config)
   2372 {
   2373     int l3_idx;
   2374     bcm_module_t modid, my_modid;
   2375 
   2376     _TR2_SUBPORT_CHECK_INIT(unit);
   2377 
   2378     if (config == NULL) {
   2379         return BCM_E_PARAM;
   2380     }
   2381 
   2382     BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &my_modid));
   2383     modid = (BCM_GPORT_SUBPORT_PORT_GET(port) >> 12) & SOC_MODID_MAX(unit);
   2384     if (modid != my_modid) {
   2385         return BCM_E_PORT;
   2386     }
   2387 
   2388     l3_idx = BCM_GPORT_SUBPORT_PORT_GET(port) & 0xfff;
   2389     if (l3_idx >= BCM_XGS3_L3_IF_TBL_SIZE(unit)) {
   2390         return (BCM_E_PARAM);
   2391     }
   2392 
   2393     return _bcm_tr2_subport_port_get(unit, l3_idx, config);
   2394 }
   2395 
   2396 /*
   2397  * Function:
   2398  *      bcm_subport_port_traverse
   2399  * Purpose:
   2400  *      Traverse all valid subports and call the
   2401  *      supplied callback routine.
   2402  * Parameters:
   2403  *      unit      - Device Number
   2404  *      cb        - User callback function, called once per subport.
   2405  *      user_data - cookie
   2406  * Returns:
   2407  *      BCM_E_XXX
   2408  */
   2409 int
   2410 bcm_tr2_subport_port_traverse(int unit,
   2411                              bcm_subport_port_traverse_cb cb,
   2412                              void *user_data)
   2413 {
   2414     int rv, vp, l3_idx;
   2415     bcm_subport_config_t config;
   2416     bcm_gport_t gport;
   2417     bcm_module_t my_modid;
   2418 
   2419     _TR2_SUBPORT_CHECK_INIT(unit);
   2420 
   2421     BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &my_modid));
   2422 
   2423     for (vp = 0; vp < _TR2_SUBPORT_NUM_VP; vp++) {
   2424         l3_idx = _BCM_TR2_SUBPORT_ID_GET(unit, vp);
   2425         if (l3_idx != 0xffff) {
   2426             rv = _bcm_tr2_subport_port_get(unit, l3_idx, &config);
   2427             BCM_IF_ERROR_RETURN(rv);
   2428 
   2429             BCM_GPORT_SUBPORT_PORT_SET(gport, ((my_modid << 12) | l3_idx));
   2430             /* coverity[dead_error_begin] */
   2431             rv = cb(unit, gport, &config, user_data);
   2432             /* coverity[dead_error_begin] */
   2433 #ifdef BCM_CB_ABORT_ON_ERR
   2434             if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   2435                 return rv;
   2436             }
   2437 #endif
   2438         }
   2439     }
   2440     return BCM_E_NONE;
   2441 }
   2442 
   2443 /*
   2444  * Function:
   2445  *      _bcm_tr_subport_group_resolve
   2446  * Purpose:
   2447  *      Get the modid, port, trunk values for a subport group GPORT
   2448  * Returns:
   2449  *      BCM_E_XXX
   2450  */
   2451 int
   2452 _bcm_tr2_subport_group_resolve(int unit, bcm_gport_t gport,
   2453                               bcm_module_t *modid, bcm_port_t *port,
   2454                               bcm_trunk_t *trunk_id, int *id)
   2455 {
   2456     int rv = BCM_E_NONE; 
   2457     ing_l3_next_hop_entry_t ing_nh;
   2458     ing_dvp_table_entry_t dvp;
   2459     int nh_index, vp_base;
   2460 
   2461     _TR2_SUBPORT_CHECK_INIT(unit);
   2462     
   2463     vp_base = BCM_GPORT_SUBPORT_GROUP_GET(gport);
   2464     if (vp_base == -1) {
   2465         return BCM_E_PARAM;
   2466     }
   2467 
   2468     if (soc_feature(unit, soc_feature_subport_enhanced)) {
   2469         rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base, &dvp);
   2470         BCM_IF_ERROR_RETURN(rv);
   2471         nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   2472         BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   2473                                       nh_index, &ing_nh));
   2474         if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, ENTRY_TYPEf) != 0x3) {
   2475             /* Entry type is not GPON DVP */
   2476             return BCM_E_NOT_FOUND;
   2477         }
   2478     }
   2479 
   2480     if (soc_feature(unit, soc_feature_generic_dest)) {
   2481         uint32 dest_type, dest;
   2482         dest = soc_mem_field32_dest_get(unit, ING_L3_NEXT_HOPm,
   2483                 &ing_nh, DESTINATIONf, &dest_type);
   2484         if (dest_type == SOC_MEM_FIF_DEST_LAG) {
   2485             *trunk_id = (dest & SOC_MEM_FIF_DGPP_TGID_MASK);
   2486         } else {
   2487             *port = (dest & SOC_MEM_FIF_DGPP_PORT_MASK);
   2488             *modid = (dest & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >>
   2489                      SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS;
   2490         }
   2491     } else {
   2492         if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) {
   2493             *trunk_id = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, TGIDf);
   2494         } else {
   2495             *modid = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, MODULE_IDf);
   2496             *port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf);
   2497         }
   2498     }
   2499     *id = vp_base;
   2500     return rv;
   2501 }
   2502 
   2503 /*
   2504  * Function:
   2505  *      _bcm_tr_subport_port_resolve
   2506  * Purpose:
   2507  *      Get the modid, port, trunk values for a subport port GPORT
   2508  * Returns:                  
   2509  *      BCM_E_XXX
   2510  */                          
   2511 int 
   2512 _bcm_tr2_subport_port_resolve(int unit, bcm_gport_t gport,
   2513                              bcm_module_t *modid, bcm_port_t *port,
   2514                              bcm_trunk_t *trunk_id, int *id)
   2515 {
   2516     int rv = BCM_E_NONE, l3_idx; 
   2517     ing_l3_next_hop_entry_t ing_nh;
   2518     egr_l3_intf_entry_t l3_intf;
   2519     ing_dvp_table_entry_t dvp;
   2520     int nh_index, vp, vp_base;
   2521     bcm_module_t my_modid;
   2522 
   2523     _TR2_SUBPORT_CHECK_INIT(unit);
   2524 
   2525     BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &my_modid));
   2526 
   2527     *id = BCM_GPORT_SUBPORT_PORT_GET(gport);
   2528     *modid = (*id >> 12) & SOC_MODID_MAX(unit);
   2529     if (*modid != my_modid) {
   2530         return (BCM_E_PORT);
   2531     }
   2532 
   2533     l3_idx = BCM_GPORT_SUBPORT_PORT_GET(gport) & 0xfff;
   2534     if (l3_idx >= BCM_XGS3_L3_IF_TBL_SIZE(unit)) {
   2535         return (BCM_E_PARAM);
   2536     }
   2537     rv = soc_mem_read(unit, EGR_L3_INTFm, MEM_BLOCK_ALL, l3_idx, &l3_intf);
   2538     BCM_IF_ERROR_RETURN(rv);
   2539 
   2540     
   2541     if (soc_feature(unit, soc_feature_subport_enhanced)) {
   2542         vp = soc_mem_field32_get(unit, EGR_L3_INTFm, &l3_intf, IVIDf);
   2543         vp_base = vp & ~(0x7);
   2544         rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base, &dvp);
   2545         BCM_IF_ERROR_RETURN(rv);
   2546         nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   2547         BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   2548                                       nh_index, &ing_nh));
   2549         if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, ENTRY_TYPEf) != 0x3) {
   2550             /* Entry type is not GPON DVP */
   2551             return BCM_E_NOT_FOUND;
   2552         }
   2553     }
   2554 
   2555     if (soc_feature(unit, soc_feature_generic_dest)) {
   2556         uint32 dest_type, dest;
   2557         dest = soc_mem_field32_dest_get(unit, ING_L3_NEXT_HOPm,
   2558                 &ing_nh, DESTINATIONf, &dest_type);
   2559         if (dest_type == SOC_MEM_FIF_DEST_LAG) {
   2560             *trunk_id = (dest & SOC_MEM_FIF_DGPP_TGID_MASK);
   2561         } else {
   2562             *port = (dest & SOC_MEM_FIF_DGPP_PORT_MASK);
   2563         }
   2564     } else {
   2565         if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) {
   2566             *trunk_id = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, TGIDf);
   2567         } else {
   2568             *port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf);
   2569         }
   2570     }
   2571     return rv;
   2572 }
   2573 
   2574 /*
   2575  * Function:
   2576  *      bcm_tr_subport_learn_set
   2577  * Purpose:
   2578  *      Set the CML bits for a subport group.
   2579  * Returns:
   2580  *      BCM_E_XXX
   2581  */
   2582 int
   2583 bcm_tr2_subport_learn_set(int unit, bcm_gport_t group, uint32 flags)
   2584 {
   2585     int vp_base, cml = 0, rv = BCM_E_NONE;
   2586     source_vp_entry_t svp;
   2587 
   2588     _TR2_SUBPORT_CHECK_INIT(unit);
   2589 
   2590     cml = 0;
   2591     if (!(flags & BCM_PORT_LEARN_FWD)) {
   2592        cml |= (1 << 0);
   2593     }
   2594     if (flags & BCM_PORT_LEARN_CPU) {
   2595        cml |= (1 << 1);
   2596     }
   2597     if (flags & BCM_PORT_LEARN_PENDING) {
   2598        cml |= (1 << 2);
   2599     }
   2600     if (flags & BCM_PORT_LEARN_ARL) {
   2601        cml |= (1 << 3);
   2602     }
   2603 
   2604     vp_base = BCM_GPORT_SUBPORT_GROUP_GET(group); 
   2605     if (vp_base == -1) {
   2606         return BCM_E_PARAM;
   2607     }
   2608 
   2609     if (!_BCM_TR2_GROUP_USED_GET(unit, vp_base / 8)) {
   2610         return BCM_E_NOT_FOUND;
   2611     }
   2612     MEM_LOCK(unit, SOURCE_VPm);
   2613     rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp_base, &svp);
   2614     if (soc_SOURCE_VPm_field32_get(unit, &svp, ENTRY_TYPEf) != 0x3) {
   2615         MEM_UNLOCK(unit, SOURCE_VPm);
   2616         return BCM_E_INTERNAL;
   2617     }
   2618     soc_SOURCE_VPm_field32_set(unit, &svp, CML_FLAGS_MOVEf, cml);
   2619     soc_SOURCE_VPm_field32_set(unit, &svp, CML_FLAGS_NEWf, cml);
   2620     rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp_base, &svp);
   2621     MEM_UNLOCK(unit, SOURCE_VPm);
   2622     return rv;
   2623 }
   2624 
   2625 /*
   2626  * Function:
   2627  *      bcm_tr_subport_learn_get
   2628  * Purpose:
   2629  *      Get the CML bits for a subport group.
   2630  * Returns: 
   2631  *      BCM_E_XXX
   2632  */     
   2633 int
   2634 bcm_tr2_subport_learn_get(int unit, bcm_gport_t group, uint32 *flags)
   2635 {
   2636     int vp_base, cml;
   2637     source_vp_entry_t svp; 
   2638     
   2639     _TR2_SUBPORT_CHECK_INIT(unit);
   2640 
   2641     vp_base = BCM_GPORT_SUBPORT_GROUP_GET(group);
   2642     if (vp_base == -1) {
   2643         return BCM_E_PARAM;
   2644     }
   2645 
   2646     if (!_BCM_TR2_GROUP_USED_GET(unit, vp_base / 8)) {
   2647         return BCM_E_NOT_FOUND;
   2648     }
   2649     BCM_IF_ERROR_RETURN
   2650         (READ_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp_base, &svp));
   2651     if (soc_SOURCE_VPm_field32_get(unit, &svp, ENTRY_TYPEf) != 0x3) {
   2652         return BCM_E_INTERNAL;
   2653     }
   2654     cml = soc_SOURCE_VPm_field32_get(unit, &svp, CML_FLAGS_NEWf);
   2655 
   2656     *flags = 0;
   2657     if (!(cml & (1 << 0))) {
   2658        *flags |= BCM_PORT_LEARN_FWD;
   2659     }
   2660     if (cml & (1 << 1)) {
   2661        *flags |= BCM_PORT_LEARN_CPU;
   2662     }
   2663     if (cml & (1 << 2)) {
   2664        *flags |= BCM_PORT_LEARN_PENDING;
   2665     }
   2666     if (cml & (1 << 3)) {
   2667        *flags |= BCM_PORT_LEARN_ARL;
   2668     }
   2669 
   2670     return BCM_E_NONE;
   2671 }
   2672 
   2673 STATIC int
   2674 _bcm_esw_subport_port_flex_stat_index_set(int unit, bcm_gport_t gport,
   2675                                           int fs_idx, uint32 flags)
   2676 {
   2677     int rv, vp, vp_base, vt_index, nh_index=-1;
   2678     ing_l3_next_hop_entry_t ing_nh;
   2679     egr_l3_next_hop_entry_t egr_nh;
   2680     ing_dvp_table_entry_t dvp;
   2681     bcm_port_t port = 0;
   2682     bcm_vlan_t ovid = 0;
   2683     uint32 port_class = 0;
   2684     uint32              egr_vent[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer. */
   2685     soc_mem_t egr_mem = EGR_VLAN_XLATEm;
   2686 
   2687 
   2688     /* Subport ports only make sense on egress */
   2689     if (!(flags & _BCM_FLEX_STAT_HW_EGRESS)) {
   2690         return BCM_E_PARAM;
   2691     }
   2692 
   2693     vp = BCM_GPORT_SUBPORT_PORT_GET(gport);
   2694 
   2695     /* Get the base group VP */
   2696     vp_base = vp & ~(0x7);
   2697 
   2698     /* Get the group's next-hop index */
   2699     rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base, &dvp);
   2700     BCM_IF_ERROR_RETURN(rv);
   2701     nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   2702     /* Get the group's OVID from the group's egress next-hop entry */
   2703     rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm,
   2704                       MEM_BLOCK_ALL, nh_index, &egr_nh);
   2705     BCM_IF_ERROR_RETURN(rv);
   2706     ovid = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, OVIDf);
   2707 
   2708     /* Get the egress port class */
   2709     BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   2710                                       nh_index, &ing_nh));
   2711 
   2712     if (soc_feature(unit, soc_feature_generic_dest)) {
   2713         uint32 dt, dv;
   2714         dv = soc_mem_field32_dest_get(unit, ING_L3_NEXT_HOPm,
   2715                 &ing_nh, DESTINATIONf, &dt);
   2716         if (dt != SOC_MEM_FIF_DEST_LAG) {
   2717             port  = dv & SOC_MEM_FIF_DGPP_PORT_MASK;
   2718             rv = bcm_esw_port_class_get(unit, port, bcmPortClassVlanTranslateEgress,
   2719                                         &port_class);
   2720             BCM_IF_ERROR_RETURN(rv);
   2721         }
   2722     } else {
   2723         if (!soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) {
   2724             port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf);
   2725             rv = bcm_esw_port_class_get(unit, port, bcmPortClassVlanTranslateEgress,
   2726                                         &port_class);
   2727             BCM_IF_ERROR_RETURN(rv);
   2728         } 
   2729     }
   2730     /* Find the egress vlan translate entry */
   2731 #ifdef BCM_TRIDENT3_SUPPORT
   2732     if (SOC_MEM_IS_VALID(unit, EGR_VLAN_XLATE_1_DOUBLEm)) {
   2733         egr_mem = EGR_VLAN_XLATE_1_DOUBLEm;
   2734     } else
   2735 #endif
   2736     {
   2737         egr_mem = EGR_VLAN_XLATEm;
   2738     }
   2739     sal_memset(egr_vent, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32));
   2740 #ifdef BCM_TRIDENT3_SUPPORT
   2741     if (soc_feature(unit, soc_feature_base_valid)) {
   2742         soc_mem_field32_set(unit, egr_mem, egr_vent, BASE_VALID_0f, 3);
   2743         soc_mem_field32_set(unit, egr_mem, egr_vent, BASE_VALID_1f, 7);
   2744     } else
   2745 #endif
   2746     {
   2747         soc_mem_field32_set(unit, egr_mem, egr_vent, VALIDf, 1);
   2748     }
   2749     soc_mem_field32_set(unit, egr_mem, egr_vent, OVIDf, ovid);
   2750     if (soc_feature(unit, soc_feature_subport_enhanced)) {
   2751         soc_mem_field32_set(unit, egr_mem, egr_vent, IVIDf, vp);
   2752     }
   2753     soc_mem_field32_set(unit, egr_mem, egr_vent, PORT_GROUP_IDf, port_class);
   2754 
   2755     MEM_LOCK(unit, egr_mem);
   2756     rv = soc_mem_search(unit, egr_mem, MEM_BLOCK_ALL, &vt_index,
   2757                         egr_vent, egr_vent, 0);
   2758     if (rv < 0) {
   2759         MEM_UNLOCK(unit, egr_mem);
   2760         return rv;
   2761     }
   2762 
   2763     /* Subport ports only make sense on egress */
   2764     if (soc_mem_field_valid(unit, egr_mem, USE_VINTF_CTR_IDXf)) {
   2765         soc_mem_field32_set(unit, egr_mem, egr_vent,
   2766                             USE_VINTF_CTR_IDXf, fs_idx > 0 ? 1 : 0);
   2767     }
   2768     soc_mem_field32_set(unit, egr_mem, egr_vent, VINTF_CTR_IDXf,
   2769                         fs_idx);
   2770     rv = soc_mem_write(unit, egr_mem, MEM_BLOCK_ALL, vt_index,
   2771                        egr_vent);
   2772     MEM_UNLOCK(unit, egr_mem);
   2773     return rv;
   2774 }
   2775 
   2776 STATIC int
   2777 _bcm_esw_subport_group_flex_stat_index_set(int unit, bcm_gport_t port,
   2778                                           int fs_idx, uint32 flags)
   2779 {
   2780     int vp_base, rv;
   2781     source_vp_entry_t vp_ent;
   2782 
   2783     vp_base = BCM_GPORT_SUBPORT_GROUP_GET(port);
   2784     if (vp_base == -1) {
   2785         return BCM_E_PARAM;
   2786     }
   2787 
   2788     if (!_BCM_TR2_GROUP_USED_GET(unit, (vp_base / 8))) {
   2789         return BCM_E_NOT_FOUND;
   2790     }
   2791 
   2792     if (!(flags & _BCM_FLEX_STAT_HW_INGRESS)) {
   2793         return BCM_E_PARAM;
   2794     }
   2795 
   2796     /* Subport groups only make sense on ingress */
   2797     /* Write stat index to SOURCE_VP table entry */
   2798     rv = soc_mem_read(unit, SOURCE_VPm, MEM_BLOCK_ALL, vp_base, &vp_ent);
   2799     if (BCM_SUCCESS(rv)) {
   2800         if (soc_mem_field_valid(unit, SOURCE_VPm, USE_VINTF_CTR_IDXf)) {
   2801             soc_mem_field32_set(unit, SOURCE_VPm, &vp_ent, USE_VINTF_CTR_IDXf,
   2802                                 fs_idx > 0 ? 1 : 0);
   2803         }
   2804         soc_mem_field32_set(unit, SOURCE_VPm, &vp_ent, VINTF_CTR_IDXf, fs_idx);
   2805         rv = soc_mem_write(unit, SOURCE_VPm, MEM_BLOCK_ALL, vp_base, &vp_ent);
   2806     }
   2807     return rv;
   2808 }
   2809 
   2810 int
   2811 _bcm_esw_subport_flex_stat_index_set(int unit, bcm_gport_t port,
   2812                                           int fs_idx,uint32 flags)
   2813 {
   2814     int rv = BCM_E_NONE;
   2815 
   2816     
   2817 
   2818     _TR2_SUBPORT_VP_MEM_LOCK(unit);
   2819 
   2820     if (BCM_GPORT_IS_SUBPORT_PORT(port)) {
   2821         rv = _bcm_esw_subport_port_flex_stat_index_set(unit, port, fs_idx,flags);
   2822     } else if (BCM_GPORT_IS_SUBPORT_GROUP(port)) {
   2823         rv = _bcm_esw_subport_group_flex_stat_index_set(unit, port, fs_idx,flags);
   2824     }
   2825 
   2826     _TR2_SUBPORT_VP_MEM_UNLOCK(unit);
   2827     return rv;
   2828 }
   2829 
   2830 #ifdef BCM_WARM_BOOT_SUPPORT_SW_DUMP
   2831 /*
   2832  * Function:
   2833  *      _bcm_tr2_subport_sw_dump
   2834  * Purpose:
   2835  *      Print Subport module s/w state
   2836  * Returns: 
   2837  *      void
   2838  */     
   2839 void
   2840 _bcm_tr2_subport_sw_dump(int unit)
   2841 {
   2842     int idx, sub_prt;
   2843 
   2844     if (_tr2_subport_id[unit] == NULL || _tr2_group_bitmap[unit] == NULL) {
   2845         LOG_CLI((BSL_META_U(unit,
   2846                             "\nSubport feature is not initialized\n")));
   2847         return;
   2848     }
   2849 
   2850 
   2851     LOG_CLI((BSL_META_U(unit,
   2852                         "SOC Feature: Subport Enhanced.\n")));
   2853     LOG_CLI((BSL_META_U(unit,
   2854                         "Subport Groups:\n")));
   2855     for(idx = 0; idx < _TR2_SUBPORT_NUM_GROUP; idx++) {
   2856         if(_BCM_TR2_GROUP_USED_GET(unit, idx)) {
   2857             LOG_CLI((BSL_META_U(unit,
   2858                                 "%d "), idx));
   2859         }
   2860     }
   2861 
   2862     LOG_CLI((BSL_META_U(unit,
   2863                         "\n----\n")));
   2864 
   2865     LOG_CLI((BSL_META_U(unit,
   2866                         "Subport IDs used:\n")));
   2867     for(idx = 0; idx < _TR2_SUBPORT_NUM_VP; idx++) {
   2868         if((sub_prt = _BCM_TR2_SUBPORT_ID_GET(unit, idx)) != 0xffff) {
   2869             LOG_CLI((BSL_META_U(unit,
   2870                                 "Subport ID=%d, VP=%d \n"), sub_prt, idx));
   2871         }
   2872     }
   2873 }
   2874 #endif /* BCM_WARM_BOOT_SUPPORT_SW_DUMP */
   2875 
   2876 #else  /* INCLUDE_L3 && BCM_TRIUMPH2_SUPPORT */
   2877 int bcm_esw_triumph2_subport_not_empty;
   2878 #endif /* INCLUDE_L3 && BCM_TRIUMPH2_SUPPORT */