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


      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_TRX_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 #include <soc/debug.h>
     21 
     22 #include <bcm/error.h>
     23 #include <bcm/subport.h>
     24 
     25 #include <bcm_int/esw/mbcm.h>
     26 #include <bcm_int/esw/firebolt.h>
     27 #include <bcm_int/esw/trx.h>
     28 #include <bcm_int/esw/triumph.h>
     29 #include <bcm_int/esw/l3.h>
     30 #include <bcm_int/esw/virtual.h>
     31 #include <bcm_int/esw/stack.h>
     32 #include <bcm_int/esw/subport.h>
     33 #ifdef BCM_TRIUMPH2_SUPPORT
     34 #include <bcm_int/esw/triumph2.h>
     35 #endif
     36 
     37 #include <bcm_int/esw_dispatch.h>
     38 
     39 /* Usage bitmap of subport groups (1 group = 8 VPs) */
     40 STATIC SHR_BITDCL *_tr_group_bitmap[BCM_MAX_NUM_UNITS] = { 0 };
     41 
     42 /* Array of L3_INTF IDs per VP (0xffff means unused) */
     43 STATIC uint16 *_tr_subport_id[BCM_MAX_NUM_UNITS] = { 0 };
     44 
     45 /* Per-port count of all subports added */
     46 STATIC int _tr_subport_group_count[BCM_MAX_NUM_UNITS][SOC_MAX_NUM_PORTS] = {{ 0 }};
     47 
     48 /*
     49  * Limited to 4K VPs (instead of actual table size of 8K)
     50  * since the IVID field (12-bits) in EGR_VLAN_XLATE table is 
     51  * used as the DVP value.
     52  */
     53 #define SUBPORT_NUM_VP          (4096)
     54 #define VP_PER_SUBPORT_GROUP    (8)
     55 #define SUBPORT_NUM_GROUP       (SUBPORT_NUM_VP / VP_PER_SUBPORT_GROUP)
     56 
     57 #define SUBPORT_VP_MEM_LOCK(unit) \
     58    do { \
     59        if (SOC_IS_TR_VL(unit) || SOC_MEM_IS_VALID(unit, SOURCE_VPm)) { \
     60            MEM_LOCK(unit, SOURCE_VPm); \
     61        } else { \
     62            sal_mutex_take(_subport_vp_mutex[unit], sal_mutex_FOREVER); \
     63        } \
     64      } while ((0))
     65 
     66 #define SUBPORT_VP_MEM_UNLOCK(unit) \
     67    do { \
     68        if (SOC_IS_TR_VL(unit) || SOC_MEM_IS_VALID(unit, SOURCE_VPm)) { \
     69           MEM_UNLOCK(unit, SOURCE_VPm); \
     70        } else { \
     71           sal_mutex_give(_subport_vp_mutex[unit]); \
     72        } \
     73       } while ((0))
     74 
     75 /* Index to ING_L3_NEXT_HOP for VPG */
     76 int16 * _sc_subport_group_index[BCM_MAX_NUM_UNITS] = {NULL};
     77 /* L3 index */
     78 int16 * _sc_subport_port_l3idx_map[BCM_MAX_NUM_UNITS] = {NULL};
     79 /* Vp base */
     80 int16 * _sc_subport_group_vp_base[BCM_MAX_NUM_UNITS] = {NULL};
     81 /* OVID for subport groups */
     82 STATIC int16 * _sc_subport_group_ovid[BCM_MAX_NUM_UNITS] = {NULL};
     83 STATIC sal_mutex_t _subport_vp_mutex[BCM_MAX_NUM_UNITS] = {NULL};
     84 
     85 #define _TR_SUBPORT_CHECK_INIT(_unit_) \
     86         if (!_tr_group_bitmap[_unit_]) \
     87             return BCM_E_INIT
     88 
     89 STATIC int _bcm_tr_subport_port_delete(int unit, int l3_idx, int vp);
     90 STATIC int _bcm_tr_subport_group_destroy(int unit, int vp_base);
     91 
     92 /*
     93  * Subport group usage bitmap operations
     94  */
     95 #define _BCM_GROUP_USED_GET(_u_, _group_) \
     96         SHR_BITGET(_tr_group_bitmap[_u_], (_group_))
     97 #define _BCM_GROUP_USED_SET(_u_, _group_) \
     98         SHR_BITSET(_tr_group_bitmap[_u_], (_group_))
     99 #define _BCM_GROUP_USED_CLR(_u_, _group_) \
    100         SHR_BITCLR(_tr_group_bitmap[_u_], (_group_))
    101 
    102 /*
    103  * Subport port usage bitmap operations
    104  */
    105 #define _BCM_SUBPORT_ID_GET(_u_, _subport_) \
    106         (_tr_subport_id[_u_][_subport_])
    107 #define _BCM_SUBPORT_ID_SET(_u_, _subport_, _id_) \
    108         (_tr_subport_id[_u_][_subport_] = _id_)
    109 #define _BCM_SUBPORT_ID_CLR(_u_, _subport_) \
    110         (_tr_subport_id[_u_][_subport_] = 0xffff)
    111 
    112 /*
    113  * Function Vector
    114  */
    115 static bcm_esw_subport_drv_t bcmi_tr_subport_drv = {
    116 
    117     /* subport_init                */ bcm_tr_subport_init,
    118     /* subport_group_create        */ bcm_tr_subport_group_create,
    119     /* subport_group_get           */ bcm_tr_subport_group_get,
    120     /* subport_group_traverse      */ NULL,
    121     /* subport_group_destroy       */ bcm_tr_subport_group_destroy,
    122     /* subport_linkphy_config_set  */ NULL,
    123     /* subport_linkphy_config_get  */ NULL,
    124     /* subport_port_add            */ bcm_tr_subport_port_add,
    125     /* subport_port_get            */ bcm_tr_subport_port_get,
    126     /* subport_port_traverse       */ bcm_tr_subport_port_traverse,
    127     /* subport_port_stat_set       */ NULL,
    128     /* subport_port_stat_get       */ NULL,
    129     /* subport_port_delete         */ bcm_tr_subport_port_delete,
    130     /* subport_cleanup             */ bcm_tr_subport_cleanup,
    131 
    132     /* coe_init                */ NULL,
    133     /* coe_group_create        */ NULL,
    134     /* coe_group_get           */ NULL,
    135     /* coe_group_traverse      */ NULL,
    136     /* coe_group_destroy       */ NULL,
    137     /* coe_linkphy_config_set  */ NULL,
    138     /* coe_linkphy_config_get  */ NULL,
    139     /* coe_port_add            */ NULL,
    140     /* coe_port_get            */ NULL,
    141     /* coe_port_traverse       */ NULL,
    142     /* coe_port_stat_set       */ NULL,
    143     /* coe_port_stat_get       */ NULL,
    144     /* coe_port_delete         */ NULL,
    145     /* coe_cleanup             */ NULL
    146 };
    147 
    148 /*
    149  * Function:
    150  *      _bcm_tr_subport_gport_used
    151  * Purpose:
    152  *      Internal function for testing if a gport is a configured subport type
    153  * Parameters:
    154  *      unit    -  (IN) Device number.
    155  *      port -  (IN) Gport
    156  * Returns:
    157  *      BCM_X_XXX
    158  */
    159 int
    160 _bcm_tr_subport_gport_used(int unit, bcm_gport_t port)
    161 {
    162     int vp;
    163 
    164     if (BCM_GPORT_IS_SUBPORT_GROUP(port)) {
    165         vp = BCM_GPORT_SUBPORT_GROUP_GET(port);
    166         if (!_BCM_GROUP_USED_GET(unit, (vp / 8))) {
    167             return BCM_E_NOT_FOUND;
    168         }
    169     } else if (BCM_GPORT_IS_SUBPORT_PORT(port)) {
    170         vp = BCM_GPORT_SUBPORT_PORT_GET(port);
    171         if (_BCM_SUBPORT_ID_GET(unit, vp) == 0xffff) {
    172             return BCM_E_NOT_FOUND;
    173         }
    174     }
    175     return BCM_E_NONE;
    176 }
    177 
    178 /*
    179  * Function:
    180  *      _bcm_tr_subport_group_find
    181  * Purpose:
    182  *      Internal function to determine the subport group
    183  * Parameters:
    184  *      unit    -  (IN) Device number.
    185  *      port -  (IN) Gport
    186  * Returns:
    187  *      BCM_X_XXX
    188  */
    189 
    190 int
    191 _bcm_tr_subport_group_find(int unit, int vp, int *grp)
    192 {
    193 #ifdef BCM_SCORPION_SUPPORT
    194      int ix;
    195 
    196      if (NULL == _sc_subport_group_index[unit]) {
    197          /* Not initialized, not applicable on this unit. */
    198          return BCM_E_UNAVAIL;
    199      }
    200 
    201      *grp = -1;
    202      for (ix = 0; ix < SUBPORT_NUM_GROUP; ix++) { 
    203          if (_sc_subport_group_index[unit][ix] == vp) { 
    204              *grp = ix * 8; 
    205              return BCM_E_NONE;
    206          } 
    207      }
    208      return BCM_E_UNAVAIL;
    209 #else
    210      *grp = -1;
    211      return BCM_E_NONE;
    212 #endif
    213 }
    214 /*
    215  * Function:
    216  *      _bcm_tr_subport_vp_alloc
    217  * Purpose:
    218  *      Internal function for allocating a group of VPs
    219  * Parameters:
    220  *      unit    -  (IN) Device number.
    221  *      base_vp -  (OUT) Base VP index
    222  * Returns:
    223  *      BCM_X_XXX
    224  */
    225 STATIC int
    226 _bcm_tr_subport_vp_alloc(int unit, int *base_vp)
    227 {
    228     int i;
    229 /*
    230  * VP allocation is normally done by the MPLS module. However,
    231  * for builds without MPLS support, the VP allocation is done here.
    232  */
    233 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT) && \
    234     defined(INCLUDE_L3)
    235     if (SOC_IS_TR_VL(unit)) {
    236        int rv;
    237        _bcm_vp_info_t vp_info;
    238        /* 
    239         * Allocate a group of 8 consecutive VPs since 3-bit prio
    240         * is added to DVP-group to get the final DVP in the L2 lookup.
    241         * Only allocate from the 0 - 4k range since only 12-bits
    242         * are used in the EGR_VLAN_XLATE table key.
    243         * (the IVID field is used as the DVP in EGR_VLAN_XLATE)
    244         */
    245         _bcm_vp_info_init(&vp_info);
    246         vp_info.vp_type = _bcmVpTypeSubport;
    247         rv = _bcm_vp_alloc(unit, 0, 4095, 8, SOURCE_VPm, vp_info, base_vp);
    248         if (rv < 0) {
    249             return rv;
    250         }
    251         _BCM_GROUP_USED_SET(unit, *base_vp / 8);
    252         return BCM_E_NONE;
    253    }
    254 #endif
    255 
    256     SUBPORT_VP_MEM_LOCK(unit);
    257     for (i = 0; i < SUBPORT_NUM_GROUP; i++) {
    258         if (!_BCM_GROUP_USED_GET(unit, i)) {
    259             break;
    260         }
    261     }
    262     if (i == SUBPORT_NUM_GROUP) {
    263         SUBPORT_VP_MEM_UNLOCK(unit);
    264         return BCM_E_RESOURCE;
    265     }
    266     *base_vp = i * 8;
    267 
    268     _BCM_GROUP_USED_SET(unit, i);
    269     SUBPORT_VP_MEM_UNLOCK(unit);
    270     return BCM_E_NONE;
    271 }
    272 
    273 /*
    274  * Function:
    275  *      _bcm_tr_subport_vp_free
    276  * Purpose:
    277  *      Internal function for freeing a group of VPs
    278  * Parameters:
    279  *      unit    -  (IN) Device number.
    280  *      base_vp -  (IN) Base VP index
    281  * Returns:
    282  *      BCM_X_XXX
    283  */
    284 STATIC int
    285 _bcm_tr_subport_vp_free(int unit, int base_vp)
    286 {
    287 /*
    288  * VP freeing is normally done by the MPLS module. However,
    289  * for builds without MPLS support, the VP free is done here.
    290  */
    291 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT) && \
    292     defined(INCLUDE_L3)
    293     if (SOC_IS_TR_VL(unit)) {
    294         int rv;
    295 
    296         rv = _bcm_vp_free(unit, _bcmVpTypeSubport, 8, base_vp);
    297         BCM_IF_ERROR_RETURN (rv);
    298     }
    299 #endif
    300 
    301     _BCM_GROUP_USED_CLR(unit, base_vp / 8);
    302 
    303 #ifdef BCM_SCORPION_SUPPORT
    304     if (SOC_IS_SC_CQ(unit)) {
    305         _sc_subport_group_index[unit][base_vp/8] = ~0;
    306         _sc_subport_group_ovid[unit][base_vp/8] = ~0;
    307     }
    308 #endif
    309 
    310     return BCM_E_NONE;
    311 }
    312 
    313 STATIC int 
    314 _bcm_tr_subport_hw_clear(int unit)
    315 {
    316     int i;                 /* Subport groups iterator. */
    317     int l3_idx;            /* Port id.                 */ 
    318     int vp;                /* VP iterator.             */
    319     int rv = BCM_E_NONE;   /* Operation return status. */ 
    320 
    321     
    322     /* _bcm_tr_subport_port_delete() is taking VLAN_XLATEm lock. */
    323     SUBPORT_VP_MEM_LOCK(unit);
    324     /* Delete all existing subports */
    325     for (vp = 0; vp < SUBPORT_NUM_VP; vp++) {
    326         l3_idx = _BCM_SUBPORT_ID_GET(unit, vp);
    327         if (l3_idx != 0xffff) {
    328             rv = _bcm_tr_subport_port_delete(unit, l3_idx, vp);
    329             if (rv < 0) {
    330                 SUBPORT_VP_MEM_UNLOCK(unit);
    331                 return rv;
    332             }
    333         }
    334     }
    335 
    336     /* Delete all existing groups  (Group 0 reserved.)*/
    337     for (i = 1; i < SUBPORT_NUM_GROUP; i++) {
    338         if (_BCM_GROUP_USED_GET(unit, i)) {
    339             rv = _bcm_tr_subport_group_destroy(unit, (i * 8));
    340             if (rv < 0) {
    341                 SUBPORT_VP_MEM_UNLOCK(unit);
    342                 return rv;
    343             }
    344         }
    345     }
    346     SUBPORT_VP_MEM_UNLOCK(unit);
    347     return (rv);
    348 }
    349 
    350 STATIC void
    351 _bcm_tr_subport_free_resource(int unit)
    352 {
    353     if (_tr_group_bitmap[unit]) {
    354         sal_free(_tr_group_bitmap[unit]);
    355         _tr_group_bitmap[unit] = NULL;
    356     }
    357     if (_tr_subport_id[unit]) {
    358         sal_free(_tr_subport_id[unit]);
    359         _tr_subport_id[unit] = NULL;
    360     }
    361 
    362     if (_subport_vp_mutex[unit] != NULL) {
    363         sal_mutex_destroy(_subport_vp_mutex[unit]);
    364         _subport_vp_mutex[unit] = NULL;
    365     }
    366 #ifdef BCM_SCORPION_SUPPORT
    367     if (SOC_IS_SC_CQ(unit)){
    368         if (_sc_subport_group_index[unit] != NULL) {
    369             sal_free(_sc_subport_group_index[unit]);
    370             _sc_subport_group_index[unit] = NULL;
    371         }
    372         if (_sc_subport_group_ovid[unit] != NULL) {
    373             sal_free(_sc_subport_group_ovid[unit]);
    374             _sc_subport_group_ovid[unit] = NULL;
    375         }
    376         if (_sc_subport_port_l3idx_map[unit] != NULL) {
    377             sal_free(_sc_subport_port_l3idx_map[unit]);
    378             _sc_subport_port_l3idx_map[unit] = NULL;
    379         }
    380         if (_sc_subport_group_vp_base[unit] != NULL) {
    381             sal_free(_sc_subport_group_vp_base[unit]);
    382             _sc_subport_group_vp_base[unit] = NULL;
    383         }
    384     }
    385 #endif
    386 }
    387 
    388 #ifdef BCM_WARM_BOOT_SUPPORT
    389 /* 
    390  * Function:
    391  *     _bcm_tr_subport_reinit
    392  * Purpose:
    393  *     Reinit for warm boot.
    394  * Parameters:
    395  *      unit    : (IN) Device Unit Number
    396  * Returns:
    397  *      BCM_E_XXX
    398  */
    399 STATIC int 
    400 _bcm_tr_subport_reinit(int unit)
    401 {
    402     int stable_size;
    403     int idx, vp = 0;
    404     int num_vp;
    405     int index_min, index_max, tpid_enable, index;
    406     source_vp_entry_t svp_entry;
    407     egr_l3_intf_entry_t egr_l3_entry;
    408     _bcm_vp_info_t vp_info;
    409 
    410     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
    411 
    412     /* Reconstruct s/w state: Subport IDs */
    413     index_min = soc_mem_index_min(unit, EGR_L3_INTFm);
    414     index_max = soc_mem_index_max(unit, EGR_L3_INTFm);
    415                                  
    416     for (idx = index_min; idx <= index_max; idx++) {
    417         SOC_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_INTFm, MEM_BLOCK_ANY,
    418                                       idx, &egr_l3_entry));
    419         if (0 == soc_EGR_L3_INTFm_field32_get(unit, &egr_l3_entry,
    420                                          IVID_VALIDf)) {
    421             continue;
    422         }
    423         if ((vp = soc_EGR_L3_INTFm_field32_get(unit, &egr_l3_entry,
    424                                                        IVIDf)) == 0){
    425             continue;
    426         }
    427 
    428         if (soc_feature(unit, soc_feature_virtual_switching)) {
    429             if ((stable_size == 0) || SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) {
    430                 _bcm_vp_info_init(&vp_info);
    431                 vp_info.vp_type = _bcmVpTypeSubport;
    432                 BCM_IF_ERROR_RETURN(
    433                     _bcm_vp_used_set(unit, vp, vp_info));
    434                 _BCM_SUBPORT_ID_SET(unit, vp, idx);
    435             } else {
    436             /* Extended scache based (Level 2) recovery */
    437                 if (_bcm_vp_used_get(unit, vp, _bcmVpTypeSubport)) {
    438                     _BCM_SUBPORT_ID_SET(unit, vp, idx);
    439                 }
    440             }
    441         } else { /* SC and CQ devices */
    442             _BCM_SUBPORT_ID_SET(unit, vp, idx);
    443         }
    444 
    445         BCM_L3_INTF_USED_SET(unit, idx);
    446     }
    447 
    448     if (soc_feature(unit, soc_feature_virtual_switching)) {
    449         num_vp = soc_mem_index_count(unit, SOURCE_VPm);
    450         /* Reconstruct s/w state: Subport Groups */
    451         index_min = soc_mem_index_min(unit, SOURCE_VPm);
    452         index_max = soc_mem_index_max(unit, SOURCE_VPm);
    453         for (idx = 0; idx < num_vp ; idx++) {
    454             SOC_IF_ERROR_RETURN(soc_mem_read(unit, SOURCE_VPm, MEM_BLOCK_ANY,
    455                                           idx, &svp_entry));
    456     
    457             if (0x3 != soc_SOURCE_VPm_field32_get(unit, &svp_entry,
    458                                                        ENTRY_TYPEf)) {
    459                 continue;
    460             }
    461     
    462             _BCM_GROUP_USED_SET(unit, (idx/VP_PER_SUBPORT_GROUP));
    463     
    464             /* Recover TPID ref count */
    465             if (soc_SOURCE_VPm_field32_get(unit, &svp_entry,
    466                                                  SD_TAG_MODEf) == 1) {
    467                 tpid_enable = soc_SOURCE_VPm_field32_get(unit, &svp_entry,
    468                                                             TPID_ENABLEf);
    469                 for (index = 0; index < 4; index++) {
    470                     if (tpid_enable & (1 << index)) {
    471                         BCM_IF_ERROR_RETURN(
    472                         _bcm_fb2_outer_tpid_tab_ref_count_add( unit, index, 1));
    473                         break;
    474                     }
    475                 }
    476             }
    477         }
    478     }
    479 
    480     return BCM_E_NONE; 
    481 }
    482 #endif /* BCM_WARM_BOOT_SUPPORT */
    483 
    484 /*
    485  * Function:
    486  *      bcm_subport_init
    487  * Purpose:
    488  *      Initialize the SUBPORT software module
    489  * Parameters:
    490  *      unit - Device Number
    491  * Returns:
    492  *      BCM_E_XXX
    493  */
    494 int
    495 bcm_tr_subport_init(int unit)
    496 {
    497     int i;
    498     int rv = BCM_E_NONE;
    499 
    500     /*  Make sure module was initialized. */
    501     if (!BCM_XGS3_L3_INITIALIZED(unit)) {
    502         return (BCM_E_INIT);
    503     }
    504 
    505     /* 
    506      * Include hook to flex stats
    507      */
    508      
    509     if (_tr_subport_id[unit] == NULL) {
    510         _tr_subport_id[unit] = 
    511             sal_alloc(SUBPORT_NUM_VP * sizeof(uint16), "subport_bitmap");
    512         if (_tr_subport_id[unit] == NULL) {
    513             return BCM_E_MEMORY;
    514         }
    515     }
    516     for (i = 0; i < SUBPORT_NUM_VP; i++) {
    517         _BCM_SUBPORT_ID_CLR(unit, i);
    518     }
    519 
    520     if (_tr_group_bitmap[unit] == NULL) {
    521         _tr_group_bitmap[unit] = 
    522             sal_alloc(SHR_BITALLOCSIZE(SUBPORT_NUM_GROUP), "subport_group_bitmap");
    523         if (_tr_group_bitmap[unit] == NULL) {
    524             _bcm_tr_subport_free_resource(unit);
    525             return BCM_E_MEMORY;
    526         }
    527     }
    528     sal_memset(_tr_group_bitmap[unit], 0, SHR_BITALLOCSIZE(SUBPORT_NUM_GROUP));
    529     /* Don't use VP 0 (HW restriction) : mark group 0 as used */
    530     _BCM_GROUP_USED_SET(unit, 0);
    531 
    532     for (i = 0; i < SOC_MAX_NUM_PORTS; i++) {
    533         _tr_subport_group_count[unit][i] = 0;
    534     }
    535 
    536     if (!SOC_MEM_IS_VALID(unit, SOURCE_VPm)) { 
    537         if (NULL == _subport_vp_mutex[unit]) {
    538             _subport_vp_mutex[unit] = sal_mutex_create("subport vp mutex");
    539             if (_subport_vp_mutex[unit] == NULL) {
    540                 _bcm_tr_subport_free_resource(unit);
    541                 return BCM_E_MEMORY;
    542             }
    543         }
    544     } 
    545 #ifdef BCM_SCORPION_SUPPORT
    546     if (SOC_IS_SC_CQ(unit)) {
    547         if (NULL == _sc_subport_group_index[unit]) {
    548             _sc_subport_group_index[unit] =
    549                 sal_alloc(SUBPORT_NUM_GROUP * sizeof(int16), "sc subport grp idx");
    550             if (_sc_subport_group_index[unit] == NULL) {
    551                 _bcm_tr_subport_free_resource(unit);
    552                 return BCM_E_MEMORY;
    553             }
    554         }
    555         for (i = 0; i < SUBPORT_NUM_GROUP; i++) {
    556              /* Mark invalid index */
    557              _sc_subport_group_index[unit][i] = ~0; 
    558         }
    559         if (NULL == _sc_subport_group_ovid[unit]) {
    560             _sc_subport_group_ovid[unit] =
    561                 sal_alloc(SUBPORT_NUM_GROUP * sizeof(int16), "sc subport grp ovid");
    562             if (_sc_subport_group_ovid[unit] == NULL) {
    563                 _bcm_tr_subport_free_resource(unit);
    564                 return BCM_E_MEMORY;
    565             }
    566         }
    567         for (i = 0; i < SUBPORT_NUM_GROUP; i++) {
    568              /* Mark invalid ovid */
    569              _sc_subport_group_ovid[unit][i] = ~0; 
    570         }
    571         if (NULL == _sc_subport_port_l3idx_map[unit]) {
    572             _sc_subport_port_l3idx_map[unit] =
    573                 sal_alloc(SUBPORT_NUM_VP * sizeof(int16), "sc subport l3 idx");
    574             if (_sc_subport_port_l3idx_map[unit] == NULL) {
    575                 _bcm_tr_subport_free_resource(unit);
    576                 return BCM_E_MEMORY;
    577             }
    578         }
    579         for (i = 0; i < SUBPORT_NUM_VP; i++) {
    580              /* Mark invalid l3_idx */
    581              _sc_subport_port_l3idx_map[unit][i] = ~0; 
    582         }
    583         if (NULL == _sc_subport_group_vp_base[unit]) {
    584             _sc_subport_group_vp_base[unit] =
    585                 sal_alloc(SUBPORT_NUM_VP * sizeof(int16), "sc subport vp base");
    586             if (_sc_subport_group_vp_base[unit] == NULL) {
    587                 _bcm_tr_subport_free_resource(unit);
    588                 return BCM_E_MEMORY;
    589             }
    590         }
    591         for (i = 0; i < SUBPORT_NUM_VP ; i++) {
    592              /* Mark invalid vp base*/
    593              _sc_subport_group_vp_base[unit][i] = ~0; 
    594         }
    595     }
    596 #endif /* BCM_SCORPION_SUPPORT */
    597 
    598 #ifdef BCM_WARM_BOOT_SUPPORT
    599     if(SOC_WARM_BOOT(unit)) {
    600         rv = _bcm_tr_subport_reinit(unit);
    601         if (rv != BCM_E_NONE) {
    602             _bcm_tr_subport_free_resource(unit);
    603         }
    604     }
    605 #endif /* BCM_WARM_BOOT_SUPPORT */
    606 
    607 
    608     /* Initialize common SUBPORT module */
    609     BCM_IF_ERROR_RETURN
    610         (bcmi_subport_common_init(unit, &bcmi_tr_subport_drv));
    611 
    612     return rv;
    613 }
    614 
    615 /*
    616  * Function:
    617  *      bcm_subport_cleanup
    618  * Purpose:
    619  *      Cleanup the SUBPORT software module
    620  * Parameters:
    621  *      unit - Device Number
    622  * Returns:
    623  *      BCM_E_XXX
    624  */
    625 int
    626 bcm_tr_subport_cleanup(int unit)
    627 {
    628     int rv; /* Operation return status. */
    629 
    630     if (NULL == _tr_group_bitmap[unit]) {
    631         return (BCM_E_NONE);
    632     }
    633 
    634     if (0 == SOC_HW_ACCESS_DISABLE(unit)) { 
    635         rv = _bcm_tr_subport_hw_clear(unit);
    636         BCM_IF_ERROR_RETURN(rv);
    637     }
    638 
    639     _bcm_tr_subport_free_resource(unit);
    640     return BCM_E_NONE;
    641 }
    642 
    643 /*
    644  * Function:
    645  *      bcm_subport_group_create
    646  * Purpose:
    647  *      Create a subport group
    648  * Parameters:
    649  *      unit   - (IN) Device Number
    650  *      config - (IN) Subport group config information
    651  *      group  - (OUT) GPORT (generic port) identifier
    652  * Returns:
    653  *      BCM_E_XXX
    654  */
    655 int
    656 bcm_tr_subport_group_create(int unit, bcm_subport_group_config_t *config,
    657                              bcm_gport_t *group)
    658 {
    659     int gport_id, rv, vp_base = -1, nh_index = -1, is_local_modid, priority;
    660     int i = 0, early_exit_flag = 0;
    661     initial_ing_l3_next_hop_entry_t initial_ing_nh;
    662     ing_l3_next_hop_entry_t ing_nh;
    663     egr_l3_next_hop_entry_t egr_nh;
    664     source_vp_entry_t svp;
    665     ing_dvp_table_entry_t dvp;
    666     bcm_l3_egress_t nh_info;
    667     uint32 nh_flags;
    668     bcm_module_t mod_out;
    669     bcm_port_t port_out;
    670     bcm_trunk_t trunk_id;
    671 
    672     _TR_SUBPORT_CHECK_INIT(unit);
    673 
    674     if ((config == NULL) || (group == NULL) || (config->vlan > BCM_VLAN_MAX)) {
    675         return BCM_E_PARAM;
    676     }
    677     rv = _bcm_esw_gport_resolve(unit, config->port, &mod_out, &port_out, &trunk_id,
    678                                 &gport_id);
    679     BCM_IF_ERROR_RETURN(rv);
    680 
    681     if (config->flags & BCM_SUBPORT_GROUP_WITH_ID) {
    682         vp_base = BCM_GPORT_SUBPORT_GROUP_GET(*group);
    683         SUBPORT_VP_MEM_LOCK(unit);
    684         if ((vp_base < 0) || (vp_base > (4096 - 8))) {
    685             rv = BCM_E_PARAM;
    686         } else if (_BCM_GROUP_USED_GET(unit, (vp_base / 8))) {
    687             rv = BCM_E_EXISTS;
    688         } else {
    689             _BCM_GROUP_USED_SET(unit, vp_base / 8);
    690         }
    691         SUBPORT_VP_MEM_UNLOCK(unit);
    692     } else {
    693         /* 
    694          * Allocate a group of 8 consecutive VPs since 3-bit prio
    695          * is added to DVP-group to get the final DVP in the L2 lookup.
    696          * Only allocate from the 0 - 4k range since only 12-bits
    697          * are used in the EGR_VLAN_XLATE table key.
    698          * (the IVID field is used as the DVP in EGR_VLAN_XLATE)
    699          */
    700         rv = _bcm_tr_subport_vp_alloc(unit, &vp_base);
    701     }
    702     BCM_IF_ERROR_RETURN (rv);
    703 
    704     /* 
    705      * Allocate a next-hop entry. By calling bcm_xgs3_nh_add()
    706      * with _BCM_L3_SHR_WRITE_DISABLE flag, a next-hop index is
    707      * allocated but nothing is written to hardware. The "nh_info"
    708      * in this case is not used, so just set to all zeros.
    709      */
    710     for (priority = 0; priority < 8; priority ++) {
    711         sal_memset(&nh_info, 0, sizeof(nh_info));
    712         nh_flags = _BCM_L3_SHR_MATCH_DISABLE | _BCM_L3_SHR_WRITE_DISABLE;
    713 #ifdef BCM_SCORPION_SUPPORT
    714         
    715         if (SOC_IS_SC_CQ(unit)) {
    716             nh_flags |= _BCM_L3_SHR_SKIP_INDEX_ZERO;
    717         }
    718 #endif
    719         rv = bcm_xgs3_nh_add(unit, nh_flags, &nh_info, &nh_index);
    720         if (rv < 0) {
    721             early_exit_flag = 1;
    722             goto cleanup;
    723         }
    724 
    725 #ifdef BCM_SCORPION_SUPPORT
    726         /* Only (0 - 4k) can be used */
    727         if (SOC_IS_SC_CQ(unit)) {
    728             if (priority == 0) {
    729                 _sc_subport_group_index[unit][vp_base/8] = nh_index;
    730             }
    731             if (nh_index >= 4096) {
    732                 rv = BCM_E_RESOURCE;
    733                 goto cleanup;
    734             }
    735         }
    736 #endif
    737 
    738         /* 
    739         * The EGR_L3_NEXT_HOP is not actually used in the datapath.
    740         * Instead, the DVP value is passed through the MMU in the
    741         * IVID field. At the egress, the IVID (DVP) is used in the
    742         * egress vlan translate table key. Here we use the 
    743         * EGR_L3_NEXT_HOP just to store the subport group's vlan
    744         * for warm reboot purposes for Triumph.
    745         */
    746         if (SOC_IS_TR_VL(unit)) {
    747             /* Write EGR_L3_NEXT_HOP entry */
    748             sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t));
    749             soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, OVIDf, 
    750                                 config->vlan);
    751             rv = soc_mem_write(unit, EGR_L3_NEXT_HOPm,
    752                             MEM_BLOCK_ALL, nh_index, &egr_nh);
    753             if (rv < 0) {
    754                 goto cleanup;
    755             }
    756         } else if (SOC_IS_SC_CQ(unit)) {
    757             _sc_subport_group_ovid[unit][vp_base/8] = config->vlan;
    758         }
    759 
    760         /* Write ING_L3_NEXT_HOP entry */
    761         sal_memset(&ing_nh, 0, sizeof(ing_l3_next_hop_entry_t));
    762         if (BCM_GPORT_IS_TRUNK(config->port)) {
    763             soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, Tf, 1);
    764             soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    765                                 &ing_nh, TGIDf, trunk_id);
    766         } else {
    767             soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    768                                 &ing_nh, PORT_NUMf, port_out);
    769             soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    770                                 &ing_nh, MODULE_IDf, mod_out);
    771         }
    772         /* Use all 8 DVPs in the group. */
    773         soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    774                             &ing_nh, DVP_RES_INFOf, 0x7f);
    775 
    776         if (SOC_IS_TR_VL(unit)) {
    777             soc_mem_field32_set(unit, ING_L3_NEXT_HOPm,
    778                                 &ing_nh, ENTRY_TYPEf, 0x3); /* GPON DVP */
    779         }
    780 
    781         rv = soc_mem_write (unit, ING_L3_NEXT_HOPm,
    782                             MEM_BLOCK_ALL, nh_index, &ing_nh);
    783         if (rv < 0) {
    784             goto cleanup;
    785         }
    786 
    787         /* Write INITIAL_ING_L3_NEXT_HOP entry */
    788         sal_memset(&initial_ing_nh, 0, sizeof(initial_ing_l3_next_hop_entry_t));
    789         if (BCM_GPORT_IS_TRUNK(config->port)) {
    790             soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm,
    791                                 &initial_ing_nh, Tf, 1);
    792             soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm,
    793                                 &initial_ing_nh, TGIDf, trunk_id);
    794         } else {
    795             soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm,
    796                                 &initial_ing_nh, PORT_NUMf, port_out);
    797             soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm,
    798                                 &initial_ing_nh, MODULE_IDf, mod_out);
    799         }
    800         rv = soc_mem_write(unit, INITIAL_ING_L3_NEXT_HOPm,
    801                            MEM_BLOCK_ALL, nh_index, &initial_ing_nh);
    802         if (rv < 0) {
    803             goto cleanup;
    804         }
    805 
    806         if (SOC_IS_TR_VL(unit)) {
    807             /* Write ING_DVP_TABLE entry */
    808             sal_memset(&dvp, 0, sizeof(ing_dvp_table_entry_t));
    809             soc_ING_DVP_TABLEm_field32_set(unit, &dvp, NEXT_HOP_INDEXf, nh_index);
    810             rv = WRITE_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, (vp_base + priority), &dvp);
    811             if (rv < 0) {
    812                 goto cleanup;
    813             }
    814 
    815             /* Write SOURCE_VP table entry */
    816             sal_memset(&svp, 0, sizeof(svp));
    817             soc_SOURCE_VPm_field32_set(unit, &svp, ENTRY_TYPEf, 0x3); /* GPON */
    818             soc_SOURCE_VPm_field32_set(unit, &svp, CLASS_IDf, config->if_class);
    819 
    820             /* Set the CML to PVP_CML_SWITCH by default (hw learn and forward) */
    821             
    822             soc_SOURCE_VPm_field32_set(unit, &svp, CML_FLAGS_NEWf, 0x8);
    823             soc_SOURCE_VPm_field32_set(unit, &svp, CML_FLAGS_MOVEf, 0x8);
    824             rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, (vp_base + priority), &svp);
    825             if (rv < 0) {
    826                 goto cleanup;
    827             }
    828         }
    829         BCM_IF_ERROR_RETURN(
    830             _bcm_esw_modid_is_local(unit, mod_out, &is_local_modid));
    831 
    832         if (TRUE == is_local_modid) {
    833             if (_tr_subport_group_count[unit][port_out]++ == 0) {
    834                 SOC_IF_ERROR_RETURN
    835                     (soc_reg_field32_modify(unit, EGR_IPMC_CFG2r, port_out,
    836                                             DISABLE_TTL_CHECKf, 1));
    837             }
    838         }
    839     }
    840     BCM_GPORT_SUBPORT_GROUP_SET(*group, vp_base);
    841 
    842 #ifdef BCM_WARM_BOOT_SUPPORT
    843     SOC_CONTROL_LOCK(unit);
    844     SOC_CONTROL(unit)->scache_dirty = 1;
    845     SOC_CONTROL_UNLOCK(unit);
    846 #endif
    847 
    848     return BCM_E_NONE;
    849 
    850 cleanup:
    851     /* For Scorpion, if cleanup happened before nh_index can be stored then
    852      * reduce priority by 1 to clean right number of next hop indexes.
    853      */
    854     if (SOC_IS_SC_CQ(unit)) {
    855         if(early_exit_flag) {
    856             priority -= 1;
    857         }
    858     }
    859     for (;priority >= 0; priority --) {
    860         if (SOC_IS_TR_VL(unit)) {
    861             (void) READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, (vp_base + priority), &dvp);
    862             nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
    863         } else if (SOC_IS_SC_CQ(unit)) {
    864             nh_index =  _sc_subport_group_index[unit][vp_base/8];
    865             nh_index = nh_index - i;
    866         }
    867         if (nh_index != -1) {
    868             nh_flags = _BCM_L3_SHR_WRITE_DISABLE;
    869             (void) bcm_xgs3_nh_del(unit, nh_flags, nh_index);
    870         }
    871         i++;
    872     }
    873     if (vp_base != -1) {
    874         (void) _bcm_tr_subport_vp_free(unit, vp_base);
    875     }
    876     return rv;
    877 }
    878 
    879 STATIC int
    880 _bcm_tr_subport_group_destroy(int unit, int vp_base)
    881 {
    882     int i, l3_idx, nh_index=-1, rv, is_local_modid;
    883     initial_ing_l3_next_hop_entry_t initial_ing_nh;
    884     ing_l3_next_hop_entry_t ing_nh;
    885     egr_l3_next_hop_entry_t egr_nh;
    886     ing_dvp_table_entry_t dvp;
    887     source_vp_entry_t svp;
    888     bcm_port_t port;
    889     bcm_module_t modid;
    890    
    891     if (SOC_IS_TR_VL(unit)) {
    892         /* Get the next-hop index from the base VP */
    893         rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base, &dvp);
    894         BCM_IF_ERROR_RETURN(rv);
    895 
    896         nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
    897         BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
    898                                           nh_index, &ing_nh));
    899 
    900         if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, ENTRY_TYPEf) != 0x3) {
    901             /* Entry type is not GPON DVP */
    902             return BCM_E_NOT_FOUND;
    903         }
    904      } else if (SOC_IS_SC_CQ(unit)) {
    905         nh_index = _sc_subport_group_index[unit][vp_base/8];
    906         if (nh_index == ~0) {
    907             return BCM_E_NOT_FOUND;
    908         }
    909         BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
    910                                           nh_index, &ing_nh));
    911      }
    912 
    913     /* Delete any ports that were added to the group */
    914     for (i = 0; i < 8; i++) {
    915         l3_idx = _BCM_SUBPORT_ID_GET(unit, (vp_base + i));
    916         if (l3_idx != 0xffff) {
    917             rv = _bcm_tr_subport_port_delete(unit, l3_idx, (vp_base + i));
    918             BCM_IF_ERROR_RETURN(rv);
    919         }    
    920 
    921         if (SOC_IS_TR_VL(unit)) {
    922             rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, (vp_base + i), &dvp);
    923             BCM_IF_ERROR_RETURN(rv);
    924             nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
    925 
    926             /* Clear SOURCE_VP table entry */
    927             sal_memset(&svp, 0, sizeof(svp));
    928             rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp_base + i, &svp);
    929             BCM_IF_ERROR_RETURN(rv);
    930 
    931             /* Clear ING_DVP_TABLE entry */
    932             sal_memset(&dvp, 0, sizeof(dvp));
    933             rv = WRITE_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base + i, &dvp);
    934             BCM_IF_ERROR_RETURN(rv);
    935 
    936 
    937             /* Clear EGR_L3_NEXT_HOP entry */
    938             sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t));
    939             rv = soc_mem_write(unit, EGR_L3_NEXT_HOPm,
    940                     MEM_BLOCK_ALL, nh_index, &egr_nh);
    941             BCM_IF_ERROR_RETURN(rv);
    942         } else if (SOC_IS_SC_CQ(unit)) {
    943             nh_index = _sc_subport_group_index[unit][vp_base/8];
    944             nh_index = nh_index + i;
    945         }
    946 
    947         /* Get the modid/port number from ING_L3_NEXT_HOP entry */
    948         /* coverity[negative_returns : FALSE] */
    949         rv = soc_mem_read(unit, ING_L3_NEXT_HOPm,
    950                           MEM_BLOCK_ALL, nh_index, &ing_nh);
    951         BCM_IF_ERROR_RETURN(rv);
    952         modid = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm,
    953                                     &ing_nh, MODULE_IDf);
    954         port = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm,
    955                                    &ing_nh, PORT_NUMf);
    956 
    957         /* Clear ING_L3_NEXT_HOP entry */
    958         sal_memset(&ing_nh, 0, sizeof(ing_l3_next_hop_entry_t));
    959         rv = soc_mem_write (unit, ING_L3_NEXT_HOPm,
    960                             MEM_BLOCK_ALL, nh_index, &ing_nh);
    961         BCM_IF_ERROR_RETURN(rv);
    962 
    963         /* Clear INITIAL_ING_L3_NEXT_HOP entry */
    964         sal_memset(&initial_ing_nh, 0, sizeof(initial_ing_l3_next_hop_entry_t));
    965         rv = soc_mem_write(unit, INITIAL_ING_L3_NEXT_HOPm,
    966                            MEM_BLOCK_ALL, nh_index, &initial_ing_nh);
    967         BCM_IF_ERROR_RETURN(rv);
    968 
    969         /* Free the next-hop index */
    970         rv = bcm_xgs3_nh_del(unit, _BCM_L3_SHR_WRITE_DISABLE, nh_index);
    971         BCM_IF_ERROR_RETURN(rv);
    972     }
    973 #ifdef BCM_TRIUMPH2_SUPPORT
    974     if (soc_feature(unit, soc_feature_gport_service_counters)) {
    975         bcm_gport_t gport;
    976 
    977         /* Release Service counter, if any */
    978         BCM_GPORT_SUBPORT_GROUP_SET(gport, vp_base);
    979         _bcm_esw_flex_stat_handle_free(unit, _bcmFlexStatTypeGport, gport);
    980     }
    981 #endif
    982 
    983     /* Free the VP */
    984     rv = _bcm_tr_subport_vp_free(unit, vp_base);
    985     BCM_IF_ERROR_RETURN(rv);
    986 
    987     BCM_IF_ERROR_RETURN(
    988         _bcm_esw_modid_is_local(unit, modid, &is_local_modid));
    989 
    990     if (TRUE == is_local_modid) {
    991         if (--_tr_subport_group_count[unit][port] == 0) {
    992             SOC_IF_ERROR_RETURN
    993                 (soc_reg_field32_modify(unit, EGR_IPMC_CFG2r, port,
    994                                         DISABLE_TTL_CHECKf, 0));
    995         }
    996     }
    997 
    998 #ifdef BCM_WARM_BOOT_SUPPORT
    999     SOC_CONTROL_LOCK(unit);
   1000     SOC_CONTROL(unit)->scache_dirty = 1;
   1001     SOC_CONTROL_UNLOCK(unit);
   1002 #endif
   1003 
   1004     return rv;
   1005 }
   1006 
   1007 /*
   1008  * Function:
   1009  *      bcm_subport_group_destroy
   1010  * Purpose:
   1011  *      Destroy a subport group
   1012  * Parameters:
   1013  *      unit  - (IN) Device Number
   1014  *      group - (IN) GPORT (generic port) identifier
   1015  * Returns:
   1016  *      BCM_E_XXX
   1017  */
   1018 int
   1019 bcm_tr_subport_group_destroy(int unit, bcm_gport_t group)
   1020 {   
   1021     int vp_base;
   1022 
   1023     _TR_SUBPORT_CHECK_INIT(unit);
   1024 
   1025     vp_base = BCM_GPORT_SUBPORT_GROUP_GET(group); 
   1026     if (vp_base == -1) {
   1027         return BCM_E_PARAM;
   1028     }
   1029 
   1030     return _bcm_tr_subport_group_destroy(unit, vp_base);
   1031 }
   1032 
   1033 /*
   1034  * Function:
   1035  *      bcm_subport_group_get
   1036  * Purpose:
   1037  *      Get a subport group
   1038  * Parameters:
   1039  *      unit   - (IN) Device Number
   1040  *      group  - (IN) GPORT (generic port) identifier
   1041  *      config - (OUT) Subport group config information
   1042  * Returns:
   1043  *      BCM_E_XXX
   1044  */
   1045 int
   1046 bcm_tr_subport_group_get(int unit, bcm_gport_t group,
   1047                          bcm_subport_group_config_t *config)
   1048 {
   1049     int rv = BCM_E_NONE; 
   1050     egr_l3_next_hop_entry_t egr_nh;
   1051     ing_l3_next_hop_entry_t ing_nh;
   1052     ing_dvp_table_entry_t dvp;
   1053     source_vp_entry_t svp;
   1054     int nh_index = -1, vp_base;
   1055     bcm_port_t port_in, port_out;
   1056     bcm_module_t mod_in, mod_out;
   1057     bcm_trunk_t trunk_id;
   1058 
   1059     _TR_SUBPORT_CHECK_INIT(unit);
   1060 
   1061     if (config == NULL) {
   1062         return BCM_E_PARAM;
   1063     }
   1064 
   1065     vp_base = BCM_GPORT_SUBPORT_GROUP_GET(group);
   1066     if (vp_base == -1) {
   1067         return BCM_E_PARAM;
   1068     }
   1069 
   1070     if (SOC_IS_TR_VL(unit)) {
   1071         rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base, &dvp);
   1072         BCM_IF_ERROR_RETURN(rv);
   1073     
   1074         nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   1075         BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   1076                                           nh_index, &ing_nh));
   1077 
   1078         if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, ENTRY_TYPEf) != 0x3) {
   1079            /* Entry type is not GPON DVP */
   1080            return BCM_E_NOT_FOUND;
   1081         }
   1082     } else if (SOC_IS_SC_CQ(unit)) {
   1083         nh_index = _sc_subport_group_index[unit][vp_base/8];
   1084         if (nh_index == ~0) {
   1085             return BCM_E_NOT_FOUND;
   1086         }
   1087         BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   1088                                           nh_index, &ing_nh));
   1089     }
   1090 
   1091     /* Get the physical gport information from the ingress next-hop entry */
   1092     if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) {
   1093         trunk_id = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, TGIDf);
   1094         BCM_GPORT_TRUNK_SET(config->port, trunk_id);
   1095     } else {
   1096         mod_in = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, MODULE_IDf);
   1097         port_in = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf);
   1098         BCM_IF_ERROR_RETURN(_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
   1099                                                    mod_in, port_in,
   1100                                                    &mod_out, &port_out));
   1101         BCM_GPORT_MODPORT_SET(config->port, mod_out, port_out);
   1102     }
   1103 
   1104     if (SOC_IS_TR_VL(unit)) {
   1105         /* Get the group's OVID from the group's egress next-hop entry */
   1106         rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm,
   1107                           MEM_BLOCK_ALL, nh_index, &egr_nh);
   1108         BCM_IF_ERROR_RETURN(rv);
   1109         config->vlan = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, OVIDf);
   1110     } else if (SOC_IS_SC_CQ(unit)) {
   1111         config->vlan =  _sc_subport_group_ovid[unit][vp_base/8];
   1112     }
   1113 
   1114     if (SOC_IS_TR_VL(unit)) {
   1115         /* Get the class-ID from the SOURCE_VP table entry */
   1116         rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp_base, &svp);
   1117         BCM_IF_ERROR_RETURN(rv);
   1118         config->if_class = soc_SOURCE_VPm_field32_get(unit, &svp, CLASS_IDf);
   1119     }
   1120     return BCM_E_NONE;
   1121 }
   1122 
   1123 /*
   1124  * Function:
   1125  *      bcm_subport_port_add
   1126  * Purpose:
   1127  *      Add a subport to a subport group
   1128  * Parameters:
   1129  *      unit   - (IN) Device Number
   1130  *      config - (IN) Subport config information
   1131  *      port   - (OUT) GPORT (generic port) identifier
   1132  * Returns:
   1133  *      BCM_E_XXX
   1134  */
   1135 int
   1136 bcm_tr_subport_port_add(int unit, bcm_subport_config_t *config,
   1137                          bcm_gport_t *port)
   1138 {
   1139     int rv, l3_idx = -1, nh_index=-1, vp_base, vp, is_modid_local;
   1140     ing_dvp_table_entry_t dvp;
   1141     egr_l3_next_hop_entry_t egr_nh;
   1142     ing_l3_next_hop_entry_t ing_nh;
   1143     egr_l3_intf_entry_t l3_intf;
   1144     egr_vlan_xlate_entry_t egr_vent;
   1145     vlan_xlate_entry_t ing_vent;
   1146     bcm_vlan_t ovid = 0;
   1147     bcm_port_t local_port = 0;
   1148     bcm_module_t modid = 0;
   1149     bcm_vlan_action_set_t action;
   1150     uint32 egr_profile_idx = 0xffffffff; 
   1151     uint32 ing_profile_idx = 0xffffffff, port_class = 0;
   1152 
   1153     _TR_SUBPORT_CHECK_INIT(unit);
   1154 
   1155     if ((config->int_pri < 0) || (config->int_pri > 7)) {
   1156         return BCM_E_PARAM;
   1157     }
   1158 	
   1159     /* Check Vlan range */
   1160     if ((config->pkt_vlan >= BCM_VLAN_INVALID) || ( config->pkt_vlan == BCM_VLAN_DEFAULT)) {
   1161          return BCM_E_PARAM;
   1162     }
   1163 
   1164     /* Make sure the group exists */
   1165     vp_base = BCM_GPORT_SUBPORT_GROUP_GET(config->group);
   1166     if (vp_base == -1) {
   1167         return BCM_E_PARAM;
   1168     }
   1169 
   1170     if (!_BCM_GROUP_USED_GET(unit, vp_base / 8)) {
   1171         return BCM_E_NOT_FOUND;
   1172     }
   1173 
   1174     /* See if this entry already exists */
   1175     if (SOC_IS_SC_CQ(unit)) {
   1176         nh_index = _sc_subport_group_index[unit][vp_base/8];
   1177         vp = nh_index + config->int_pri;
   1178         if(_BCM_SUBPORT_ID_GET(unit, vp) != 0xffff){
   1179                return BCM_E_EXISTS;
   1180         }
   1181         _sc_subport_group_vp_base[unit][vp] = vp_base;
   1182     } else {
   1183         vp = vp_base + config->int_pri; 
   1184         if (_BCM_SUBPORT_ID_GET(unit, vp) != 0xffff) {
   1185             return BCM_E_EXISTS;
   1186         }
   1187     }
   1188 
   1189     /* Get the group's next-hop index */
   1190     if (SOC_IS_TR_VL(unit)) {
   1191         rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp, &dvp);
   1192         BCM_IF_ERROR_RETURN(rv);
   1193         nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   1194     } else if (SOC_IS_SC_CQ(unit)) {
   1195         nh_index = _sc_subport_group_index[unit][vp_base/8];
   1196         if (nh_index == ~0) {
   1197             return BCM_E_NOT_FOUND;
   1198         }
   1199     }
   1200 
   1201     if (nh_index == -1) {
   1202         return BCM_E_INTERNAL;
   1203     }
   1204 
   1205     /* Get the modid and port_class for the destination port */
   1206     rv = soc_mem_read(unit, ING_L3_NEXT_HOPm,
   1207                       MEM_BLOCK_ALL, nh_index, &ing_nh);
   1208     if (rv < 0) {
   1209         goto cleanup;
   1210     }
   1211     if (!soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, &ing_nh, Tf)) {
   1212         modid = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, &ing_nh, MODULE_IDf);
   1213 
   1214         BCM_IF_ERROR_RETURN(
   1215             _bcm_esw_modid_is_local(unit, modid, &is_modid_local));
   1216 			
   1217         if (TRUE != is_modid_local ) {
   1218             /* No local state is required for groups on remoted devices */
   1219             return BCM_E_NONE;
   1220         }
   1221         local_port = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm,
   1222                                          &ing_nh, PORT_NUMf);
   1223         rv = bcm_esw_port_class_get(unit, local_port, bcmPortClassVlanTranslateEgress, 
   1224                                     &port_class);
   1225         if (rv < 0) {
   1226             goto cleanup;
   1227         }
   1228     }
   1229 
   1230     if (SOC_IS_TR_VL(unit)) {
   1231         /* Get the group's OVID from the group's egress next-hop entry */
   1232         rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm,
   1233                           MEM_BLOCK_ALL, nh_index, &egr_nh);
   1234         BCM_IF_ERROR_RETURN(rv);
   1235         ovid = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, OVIDf);
   1236     } else if (SOC_IS_SC_CQ(unit)) {
   1237         ovid =  _sc_subport_group_ovid[unit][vp_base/8];
   1238     }
   1239 
   1240     /*
   1241      * For each subport, we need to allocate an L3_INTF entry.
   1242      * This is needed for multicast replication. MMU replicates
   1243      * multicast packets to each subport by sending a copy to 
   1244      * the subport's L3_INTF index.
   1245      */
   1246 
   1247     /* Search for unused index. */
   1248     MEM_LOCK(unit, EGR_L3_INTFm);
   1249     for (l3_idx = 0; l3_idx < BCM_XGS3_L3_IF_TBL_SIZE(unit); l3_idx++) {
   1250         /* Check if interface index is used. */
   1251         if (!BCM_L3_INTF_USED_GET(unit, l3_idx)) {
   1252             /* Free index found. */
   1253             BCM_L3_INTF_USED_SET(unit, l3_idx);
   1254             break;
   1255         }
   1256     }
   1257     if (l3_idx == BCM_XGS3_L3_IF_TBL_SIZE(unit)) {
   1258         MEM_UNLOCK(unit, EGR_L3_INTFm);
   1259         return BCM_E_FULL;
   1260     }
   1261 
   1262     /* Write EGR_L3_INTF entry */
   1263     sal_memset(&l3_intf, 0, sizeof(egr_l3_intf_entry_t));
   1264     soc_mem_field32_set(unit, EGR_L3_INTFm, &l3_intf, OVIDf, ovid);
   1265 
   1266     /* IVID field is used as the DVP */
   1267     if (SOC_IS_TR_VL(unit)) {
   1268         soc_mem_field32_set(unit, EGR_L3_INTFm, &l3_intf, IVIDf, vp);
   1269     } else if (SOC_IS_SC_CQ(unit)) {
   1270         soc_mem_field32_set(unit, EGR_L3_INTFm, &l3_intf, IVIDf, 
   1271                             (nh_index + config->int_pri));
   1272     }
   1273     soc_mem_field32_set(unit, EGR_L3_INTFm, &l3_intf, IVID_VALIDf, 1);
   1274     rv = soc_mem_write(unit, EGR_L3_INTFm, MEM_BLOCK_ALL, l3_idx, &l3_intf);
   1275     if (rv < 0) {
   1276         MEM_UNLOCK(unit, EGR_L3_INTFm);
   1277         goto cleanup;
   1278     }
   1279     MEM_UNLOCK(unit, EGR_L3_INTFm);
   1280 
   1281     /* Write EGR_VLAN_XLATE table */
   1282     bcm_vlan_action_set_t_init(&action);
   1283     /* Create a profile entry that replaces the outer vid
   1284      * with the new 16-bit vlan tag.
   1285      */
   1286     action.ot_outer = bcmVlanActionReplace;
   1287     action.dt_outer = bcmVlanActionReplace;
   1288     action.dt_inner = bcmVlanActionDelete;
   1289     rv = _bcm_trx_egr_vlan_action_profile_entry_add(unit, &action, &egr_profile_idx);
   1290     if (rv < 0) {
   1291         goto cleanup;
   1292     }
   1293     sal_memset(&egr_vent, 0, sizeof(egr_vent));
   1294     soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, VALIDf, 1);
   1295     soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, OVIDf, ovid);
   1296     if (SOC_IS_TR_VL(unit)) {
   1297         soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, IVIDf, vp);
   1298     } else if (SOC_IS_SC_CQ(unit)) {
   1299         soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, IVIDf, 
   1300                                         (nh_index + config->int_pri));
   1301     }
   1302 
   1303     soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, PORT_GROUP_IDf, port_class);
   1304     soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, TAG_ACTION_PROFILE_PTRf,
   1305                                     egr_profile_idx);
   1306     soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, NEW_OTAG_VPTAGf, config->pkt_vlan);
   1307     soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, NEW_OTAG_VPTAG_SELf, 1);
   1308     rv = soc_mem_insert_return_old(unit, EGR_VLAN_XLATEm, MEM_BLOCK_ALL, 
   1309                                    &egr_vent, &egr_vent);
   1310     if (rv == SOC_E_EXISTS) {
   1311         /* Delete the old vlan translate profile entry */
   1312         egr_profile_idx = soc_EGR_VLAN_XLATEm_field32_get(unit, &egr_vent,
   1313                                                           TAG_ACTION_PROFILE_PTRf);
   1314         rv = _bcm_trx_egr_vlan_action_profile_entry_delete(unit, egr_profile_idx);
   1315     }
   1316     if (rv < 0) {
   1317         goto cleanup;
   1318     }
   1319 
   1320     /* Write ingress VLAN_XLATE table */
   1321     bcm_vlan_action_set_t_init(&action);
   1322     action.ot_outer = bcmVlanActionReplace;
   1323     action.ot_outer_prio = bcmVlanActionReplace;
   1324     action.dt_outer = bcmVlanActionReplace;
   1325     action.dt_outer_prio = bcmVlanActionReplace;
   1326     rv = _bcm_trx_vlan_action_profile_entry_add(unit, &action, &ing_profile_idx);
   1327     if (rv < 0) {
   1328         goto cleanup;
   1329     }
   1330     sal_memset(&ing_vent, 0, sizeof(ing_vent));
   1331     soc_VLAN_XLATEm_field32_set(unit, &ing_vent, VALIDf, 1);
   1332     soc_VLAN_XLATEm_field32_set(unit, &ing_vent, KEY_TYPEf,
   1333                                 TR_VLXLT_HASH_KEY_TYPE_OTAG);
   1334     soc_VLAN_XLATEm_field32_set(unit, &ing_vent, OTAGf, config->pkt_vlan);
   1335     soc_VLAN_XLATEm_field32_set(unit, &ing_vent, MODULE_IDf, modid);
   1336     soc_VLAN_XLATEm_field32_set(unit, &ing_vent, PORT_NUMf, local_port);
   1337     soc_VLAN_XLATEm_field32_set(unit, &ing_vent, RPEf, 1);
   1338     soc_VLAN_XLATEm_field32_set(unit, &ing_vent, PRIf, config->int_pri);
   1339     soc_VLAN_XLATEm_field32_set(unit, &ing_vent, TAG_ACTION_PROFILE_PTRf,
   1340                                 ing_profile_idx);
   1341     soc_VLAN_XLATEm_field32_set(unit, &ing_vent, NEW_OVIDf, ovid);
   1342 
   1343     if (SOC_IS_TR_VL(unit)) {
   1344         soc_VLAN_XLATEm_field32_set(unit, &ing_vent, SOURCE_VPf, vp_base); /* group VP */
   1345         soc_VLAN_XLATEm_field32_set(unit, &ing_vent, MPLS_ACTIONf, 1); /* L2 SVP */
   1346     } else if (SOC_IS_SC_CQ(unit)) {
   1347         /* next hop index gets to L3 next hop directly */
   1348         soc_VLAN_XLATEm_field32_set(unit, &ing_vent, NEW_IVID_SVPGf, nh_index);
   1349         soc_VLAN_XLATEm_field32_set(unit, &ing_vent, NEW_IVID_SVPG_SELf, 1); 
   1350     }
   1351 
   1352     rv = soc_mem_insert_return_old(unit, VLAN_XLATEm, MEM_BLOCK_ALL, 
   1353                                    &ing_vent, &ing_vent);
   1354     if (rv == SOC_E_EXISTS) {
   1355         /* Delete the old vlan translate profile entry */
   1356         ing_profile_idx = soc_VLAN_XLATEm_field32_get(unit, &ing_vent,
   1357                                                       TAG_ACTION_PROFILE_PTRf);
   1358         rv = _bcm_trx_vlan_action_profile_entry_delete(unit, ing_profile_idx);
   1359     }
   1360     if (rv < 0) {
   1361         goto cleanup;
   1362     }
   1363 
   1364     if (SOC_IS_TR_VL(unit)) {
   1365         _BCM_SUBPORT_ID_SET(unit, vp, l3_idx);
   1366     } else if (SOC_IS_SC_CQ(unit)) {
   1367         _BCM_SUBPORT_ID_SET(unit, (nh_index + config->int_pri), l3_idx);
   1368        /*store the l3_idx for vp */ 
   1369         _sc_subport_port_l3idx_map[unit][nh_index + config->int_pri] = l3_idx;
   1370     }
   1371 
   1372     BCM_GPORT_SUBPORT_PORT_SET(*port, ((modid << 12) | l3_idx));
   1373 
   1374 #ifdef BCM_WARM_BOOT_SUPPORT
   1375     SOC_CONTROL_LOCK(unit);
   1376     SOC_CONTROL(unit)->scache_dirty = 1;
   1377     SOC_CONTROL_UNLOCK(unit);
   1378 #endif
   1379 
   1380     return BCM_E_NONE;
   1381 cleanup:
   1382     if (l3_idx != -1) {
   1383         BCM_L3_INTF_USED_CLR(unit, l3_idx);
   1384     }
   1385     return rv;
   1386 }
   1387 
   1388 STATIC int
   1389 _bcm_tr_subport_port_delete(int unit, int l3_idx, int vp)
   1390 {
   1391     int rv, vp_base, vt_index, nh_index=-1;
   1392     egr_l3_intf_entry_t l3_intf;
   1393     ing_l3_next_hop_entry_t ing_nh;
   1394     egr_l3_next_hop_entry_t egr_nh;
   1395     egr_vlan_xlate_entry_t egr_vent;
   1396     vlan_xlate_entry_t ing_vent;
   1397     ing_dvp_table_entry_t dvp;
   1398     bcm_port_t port = 0;
   1399     bcm_module_t modid = 0;
   1400     bcm_vlan_t pkt_vlan, ovid = 0;
   1401     uint32 egr_profile_idx, ing_profile_idx, port_class = 0;
   1402 
   1403     _TR_SUBPORT_CHECK_INIT(unit);
   1404 
   1405     rv = soc_mem_read(unit, EGR_L3_INTFm, MEM_BLOCK_ALL, l3_idx, &l3_intf);
   1406     BCM_IF_ERROR_RETURN(rv);
   1407 
   1408     /* Get the base group VP */
   1409     if (SOC_IS_SC_CQ(unit)) {
   1410        vp_base = _sc_subport_group_vp_base[unit][vp];
   1411      } else {
   1412        vp_base = vp & ~(0x7);
   1413      }
   1414 
   1415     if (SOC_IS_TR_VL(unit)) {
   1416         /* Get the group's next-hop index */
   1417         rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base, &dvp);
   1418         BCM_IF_ERROR_RETURN(rv);
   1419         nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   1420         /* Get the group's OVID from the group's egress next-hop entry */
   1421         rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm,
   1422                           MEM_BLOCK_ALL, nh_index, &egr_nh);
   1423         BCM_IF_ERROR_RETURN(rv);
   1424         ovid = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, OVIDf);
   1425     } else if (SOC_IS_SC_CQ(unit)) {
   1426         int idx = vp_base / 8;
   1427         nh_index = _sc_subport_group_index[unit][idx];
   1428         ovid = _sc_subport_group_ovid[unit][idx];
   1429     }    
   1430 
   1431     if (nh_index == -1) {
   1432         return BCM_E_INTERNAL;
   1433     }
   1434 
   1435     /* Get the egress port class */
   1436     BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   1437                                       nh_index, &ing_nh));
   1438     if (!soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) {
   1439         modid = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, MODULE_IDf);
   1440         port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf);
   1441         rv = bcm_esw_port_class_get(unit, port, bcmPortClassVlanTranslateEgress,
   1442                                     &port_class);
   1443         BCM_IF_ERROR_RETURN(rv);
   1444     } 
   1445 
   1446     /* Find the egress vlan translate entry */
   1447     sal_memset(&egr_vent, 0, sizeof(egr_vent));
   1448     soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, VALIDf, 1);
   1449     soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, OVIDf, ovid);
   1450     if (SOC_IS_TR_VL(unit)) {
   1451         soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, IVIDf, vp);
   1452     } else if (SOC_IS_SC_CQ(unit)) {
   1453         soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, IVIDf, vp);
   1454     }
   1455 
   1456     soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, PORT_GROUP_IDf, port_class);
   1457 
   1458     MEM_LOCK(unit, EGR_VLAN_XLATEm);
   1459     rv = soc_mem_search(unit, EGR_VLAN_XLATEm, MEM_BLOCK_ALL, &vt_index, 
   1460                         &egr_vent, &egr_vent, 0);
   1461     if (rv < 0) {
   1462         MEM_UNLOCK(unit, EGR_VLAN_XLATEm);
   1463         return rv;
   1464     }
   1465 
   1466     /* Get the old vlan translate profile entry */
   1467     egr_profile_idx = soc_EGR_VLAN_XLATEm_field32_get(unit, &egr_vent,
   1468                                                       TAG_ACTION_PROFILE_PTRf);
   1469 
   1470     /* Delete the egress vlan translate entry */
   1471     rv = soc_mem_delete(unit, EGR_VLAN_XLATEm, MEM_BLOCK_ALL, &egr_vent);
   1472     MEM_UNLOCK(unit, EGR_VLAN_XLATEm);
   1473     BCM_IF_ERROR_RETURN(rv);
   1474 
   1475     /* Delete the old vlan translate profile entry */
   1476     rv = _bcm_trx_egr_vlan_action_profile_entry_delete(unit, egr_profile_idx);
   1477     BCM_IF_ERROR_RETURN(rv);
   1478 
   1479     /* Find vlan translate entry */
   1480     pkt_vlan = soc_EGR_VLAN_XLATEm_field32_get(unit, &egr_vent, NEW_OTAG_VPTAGf);
   1481     sal_memset(&ing_vent, 0, sizeof(ing_vent));
   1482     soc_VLAN_XLATEm_field32_set(unit, &ing_vent, VALIDf, 1);
   1483     soc_VLAN_XLATEm_field32_set(unit, &ing_vent, KEY_TYPEf,
   1484                                 TR_VLXLT_HASH_KEY_TYPE_OTAG);
   1485     soc_VLAN_XLATEm_field32_set(unit, &ing_vent, OTAGf, pkt_vlan);
   1486     soc_VLAN_XLATEm_field32_set(unit, &ing_vent, MODULE_IDf, modid);
   1487     soc_VLAN_XLATEm_field32_set(unit, &ing_vent, PORT_NUMf, port);
   1488 
   1489     MEM_LOCK(unit, VLAN_XLATEm);
   1490     rv = soc_mem_search(unit, VLAN_XLATEm, MEM_BLOCK_ALL, &vt_index,
   1491                         &ing_vent, &ing_vent, 0);
   1492     if (rv < 0) {
   1493         MEM_UNLOCK(unit, VLAN_XLATEm);
   1494         return rv;
   1495     }
   1496 
   1497     /* Get the old vlan translate profile entry */
   1498     ing_profile_idx = soc_VLAN_XLATEm_field32_get(unit, &ing_vent,
   1499                                                   TAG_ACTION_PROFILE_PTRf);
   1500 
   1501     /* Delete the ingress vlan translate entry */
   1502     rv = soc_mem_delete(unit, VLAN_XLATEm, MEM_BLOCK_ALL, &ing_vent);
   1503     MEM_UNLOCK(unit, VLAN_XLATEm);
   1504     BCM_IF_ERROR_RETURN(rv);
   1505 
   1506     /* Delete the old vlan translate profile entry */
   1507     rv = _bcm_trx_vlan_action_profile_entry_delete(unit, ing_profile_idx);
   1508     BCM_IF_ERROR_RETURN(rv);
   1509 
   1510     /* Clear the EGR_L3_INTF entry */
   1511     sal_memset(&l3_intf, 0, sizeof(egr_l3_intf_entry_t));
   1512     rv = soc_mem_write(unit, EGR_L3_INTFm, MEM_BLOCK_ALL, l3_idx, &l3_intf);
   1513 
   1514     /* Free the L3_INTF index */
   1515     BCM_L3_INTF_USED_CLR(unit, l3_idx);
   1516 
   1517 #ifdef BCM_TRIUMPH2_SUPPORT
   1518     if (soc_feature(unit, soc_feature_gport_service_counters)) {
   1519         bcm_gport_t gport;
   1520 
   1521         /* Release Service counter, if any */
   1522         BCM_GPORT_SUBPORT_PORT_SET(gport, vp);
   1523         _bcm_esw_flex_stat_handle_free(unit, _bcmFlexStatTypeGport, gport);
   1524     }
   1525 #endif
   1526 
   1527     /* Clear the subport usage SW state */
   1528     _BCM_SUBPORT_ID_CLR(unit, vp);
   1529 
   1530 #ifdef BCM_WARM_BOOT_SUPPORT
   1531     SOC_CONTROL_LOCK(unit);
   1532     SOC_CONTROL(unit)->scache_dirty = 1;
   1533     SOC_CONTROL_UNLOCK(unit);
   1534 #endif
   1535 
   1536     return BCM_E_NONE;
   1537 }
   1538 
   1539 /*
   1540  * Function:
   1541  *      bcm_subport_port_delete
   1542  * Purpose:
   1543  *      Delete a subport 
   1544  * Parameters:
   1545  *      unit   - (IN) Device Number
   1546  *      port   - (IN) GPORT (generic port) identifier
   1547  * Returns:
   1548  *      BCM_E_XXX
   1549  */
   1550 int
   1551 bcm_tr_subport_port_delete(int unit, bcm_gport_t port)
   1552 {
   1553     egr_l3_intf_entry_t l3_intf;
   1554     int l3_idx, vp=-1, rv, is_modid_local;
   1555     bcm_module_t modid;
   1556 
   1557     _TR_SUBPORT_CHECK_INIT(unit);
   1558 
   1559     modid = (BCM_GPORT_SUBPORT_PORT_GET(port) >> 12) & SOC_MODID_MAX(unit);
   1560     BCM_IF_ERROR_RETURN(
   1561         _bcm_esw_modid_is_local(unit, modid, &is_modid_local));
   1562 
   1563     if (TRUE != is_modid_local) {
   1564         return BCM_E_PORT;
   1565     }
   1566 
   1567     l3_idx = BCM_GPORT_SUBPORT_PORT_GET(port) & 0xfff;
   1568     if (l3_idx >= BCM_XGS3_L3_IF_TBL_SIZE(unit)) { 
   1569         return (BCM_E_PARAM);
   1570     }
   1571 
   1572     rv = soc_mem_read(unit, EGR_L3_INTFm, MEM_BLOCK_ALL, l3_idx, &l3_intf);
   1573     BCM_IF_ERROR_RETURN(rv);
   1574 
   1575     
   1576     if (SOC_IS_TR_VL(unit)) {
   1577         vp = soc_mem_field32_get(unit, EGR_L3_INTFm, &l3_intf, IVIDf);
   1578         if (_BCM_SUBPORT_ID_GET(unit, vp) != l3_idx) {
   1579             return BCM_E_NOT_FOUND;
   1580         }
   1581     } else if (SOC_IS_SC_CQ(unit)) {
   1582         /* IVIDf in Scorpion can not be used for vp */       
   1583         
   1584         for (vp = 0; vp < SUBPORT_NUM_VP; vp++) {
   1585              if (l3_idx == _BCM_SUBPORT_ID_GET(unit, vp)) {
   1586                  break;
   1587              }
   1588         }
   1589         if (vp == SUBPORT_NUM_VP) {
   1590             return BCM_E_NOT_FOUND;
   1591         }
   1592     }
   1593 
   1594     if (vp == -1) {
   1595         return BCM_E_INTERNAL;
   1596     }
   1597 
   1598     return _bcm_tr_subport_port_delete(unit, l3_idx, vp);
   1599 }
   1600 
   1601 STATIC int
   1602 _bcm_tr_subport_port_get(int unit, int l3_idx,
   1603                          bcm_subport_config_t *config)
   1604 {
   1605     int index, vp=-1, rv, vp_base, nh_index=-1;
   1606     egr_l3_intf_entry_t l3_intf;
   1607     ing_l3_next_hop_entry_t ing_nh;
   1608     egr_l3_next_hop_entry_t egr_nh;
   1609     egr_vlan_xlate_entry_t egr_vent;
   1610     ing_dvp_table_entry_t dvp;
   1611     bcm_port_t port = 0;
   1612     bcm_vlan_t ovid = 0;
   1613     uint32 port_class = 0;
   1614 
   1615     rv = soc_mem_read(unit, EGR_L3_INTFm, MEM_BLOCK_ALL, l3_idx, &l3_intf);
   1616     BCM_IF_ERROR_RETURN(rv);
   1617 
   1618     if (SOC_IS_TR_VL(unit)) {
   1619         vp = soc_mem_field32_get(unit, EGR_L3_INTFm, &l3_intf, IVIDf);
   1620         if (_BCM_SUBPORT_ID_GET(unit, vp) != l3_idx) {
   1621             return BCM_E_NOT_FOUND;
   1622         }
   1623     } else if (SOC_IS_SC_CQ(unit)) {
   1624         /* IVIDf in Scorpion can not be used for vp */
   1625         for (vp = 0; vp < SUBPORT_NUM_VP; vp++) {
   1626              if (_sc_subport_port_l3idx_map[unit][vp] == l3_idx) {
   1627                  break;
   1628              }
   1629         }
   1630         if (vp == SUBPORT_NUM_VP) {
   1631             return BCM_E_NOT_FOUND;
   1632         }
   1633     } 
   1634     
   1635     /* Get the base group VP */
   1636     if (SOC_IS_SC_CQ(unit)) {
   1637        vp_base = _sc_subport_group_vp_base[unit][vp];
   1638     } else {
   1639     /* Get the base group VP */
   1640        vp_base = vp & ~(0x7);
   1641     }
   1642 
   1643     /* Get the group's next-hop index */
   1644     if (SOC_IS_TR_VL(unit)) {
   1645         rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base, &dvp);
   1646         BCM_IF_ERROR_RETURN(rv);
   1647         nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   1648         /* Get the group's OVID from the group's egress next-hop entry */
   1649         rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm,
   1650                           MEM_BLOCK_ALL, nh_index, &egr_nh);
   1651         BCM_IF_ERROR_RETURN(rv);
   1652         ovid = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, OVIDf);
   1653     } else if (SOC_IS_SC_CQ(unit)) {
   1654         int idx = vp_base / 8;
   1655         nh_index = _sc_subport_group_index[unit][idx];
   1656         ovid     = _sc_subport_group_ovid[unit][idx];
   1657     }
   1658  	
   1659     if (nh_index == -1) {
   1660         return BCM_E_INTERNAL;
   1661     }
   1662 
   1663     /* Get the egress port class */
   1664     BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   1665                                       nh_index, &ing_nh));
   1666     if (!soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) {
   1667         port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf);
   1668         rv = bcm_esw_port_class_get(unit, port, bcmPortClassVlanTranslateEgress,
   1669                                     &port_class);
   1670         BCM_IF_ERROR_RETURN(rv);
   1671     } 
   1672 
   1673     /* Find the egress vlan translate entry */
   1674     sal_memset(&egr_vent, 0, sizeof(egr_vent));
   1675     soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, VALIDf, 1);
   1676     soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, OVIDf, ovid);
   1677     
   1678     if (SOC_IS_TR_VL(unit)) {
   1679         soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, IVIDf, vp);
   1680     } else if (SOC_IS_SC_CQ(unit)) {
   1681         soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, IVIDf, vp);
   1682     }
   1683     soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, PORT_GROUP_IDf, port_class);
   1684 
   1685     MEM_LOCK(unit, EGR_VLAN_XLATEm);
   1686     rv = soc_mem_search(unit, EGR_VLAN_XLATEm, MEM_BLOCK_ALL, &index,
   1687                         &egr_vent, &egr_vent, 0);
   1688     if (rv < 0) {
   1689         MEM_UNLOCK(unit, EGR_VLAN_XLATEm);
   1690         return rv;
   1691     }
   1692 
   1693     /* Set the config data to be returned */
   1694     BCM_GPORT_SUBPORT_GROUP_SET(config->group, vp_base);	
   1695     config->pkt_vlan = soc_EGR_VLAN_XLATEm_field32_get(unit, &egr_vent, NEW_OTAG_VPTAGf);
   1696     if (SOC_IS_SC_CQ(unit)) {
   1697         config->int_pri = (vp & (~nh_index));
   1698     } else {
   1699         config->int_pri = vp & 0x7;
   1700     }
   1701     return BCM_E_NONE;
   1702 }
   1703 
   1704 /*
   1705  * Function:
   1706  *      bcm_subport_port_get
   1707  * Purpose:
   1708  *      Get a subport
   1709  * Parameters:
   1710  *      unit   - (IN) Device Number
   1711  *      port   - (IN) GPORT (generic port) identifier
   1712  *      config - (OUT) Subport config information
   1713  * Returns:
   1714  *      BCM_E_XXX
   1715  */     
   1716 int
   1717 bcm_tr_subport_port_get(int unit, bcm_gport_t port,
   1718                         bcm_subport_config_t *config)
   1719 {
   1720     int l3_idx, is_modid_local;
   1721     bcm_module_t modid;
   1722 
   1723     _TR_SUBPORT_CHECK_INIT(unit);
   1724 
   1725     if (config == NULL) {
   1726         return BCM_E_PARAM;
   1727     }
   1728 
   1729     modid = (BCM_GPORT_SUBPORT_PORT_GET(port) >> 12) & SOC_MODID_MAX(unit);
   1730     BCM_IF_ERROR_RETURN(
   1731         _bcm_esw_modid_is_local(unit, modid, &is_modid_local));
   1732 
   1733     if (TRUE != is_modid_local) {
   1734         return BCM_E_PORT;
   1735     }
   1736 
   1737     l3_idx = BCM_GPORT_SUBPORT_PORT_GET(port) & 0xfff;
   1738     if (l3_idx >= BCM_XGS3_L3_IF_TBL_SIZE(unit)) {
   1739         return (BCM_E_PARAM);
   1740     }
   1741 
   1742     return _bcm_tr_subport_port_get(unit, l3_idx, config);
   1743 }
   1744 
   1745 /*
   1746  * Function:
   1747  *      bcm_subport_port_traverse
   1748  * Purpose:
   1749  *      Traverse all valid subports and call the
   1750  *      supplied callback routine.
   1751  * Parameters:
   1752  *      unit      - Device Number
   1753  *      cb        - User callback function, called once per subport.
   1754  *      user_data - cookie
   1755  * Returns:
   1756  *      BCM_E_XXX
   1757  */
   1758 int
   1759 bcm_tr_subport_port_traverse(int unit,
   1760                              bcm_subport_port_traverse_cb cb,
   1761                              void *user_data)
   1762 {
   1763     int rv, vp, l3_idx;
   1764     bcm_subport_config_t config;
   1765     bcm_gport_t gport;
   1766     bcm_module_t my_modid;
   1767 
   1768     _TR_SUBPORT_CHECK_INIT(unit);
   1769 
   1770     BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &my_modid));
   1771 
   1772     for (vp = 0; vp < SUBPORT_NUM_VP; vp++) {
   1773         l3_idx = _BCM_SUBPORT_ID_GET(unit, vp);
   1774         if (l3_idx != 0xffff) {
   1775             rv = _bcm_tr_subport_port_get(unit, l3_idx, &config);
   1776             BCM_IF_ERROR_RETURN(rv);
   1777 
   1778             BCM_GPORT_SUBPORT_PORT_SET(gport, ((my_modid << 12) | l3_idx));            
   1779             /* coverity[dead_error_begin] */
   1780             rv = cb(unit, gport, &config, user_data);            
   1781            /* coverity[dead_error_begin] */
   1782 #ifdef BCM_CB_ABORT_ON_ERR
   1783             if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   1784                 return rv;
   1785             }
   1786 #endif
   1787         }
   1788     }
   1789     return BCM_E_NONE;
   1790 }
   1791 
   1792 /*
   1793  * Function:
   1794  *      _bcm_tr_subport_group_resolve
   1795  * Purpose:
   1796  *      Get the modid, port, trunk values for a subport group GPORT
   1797  * Returns:
   1798  *      BCM_E_XXX
   1799  */
   1800 int
   1801 _bcm_tr_subport_group_resolve(int unit, bcm_gport_t gport,
   1802                               bcm_module_t *modid, bcm_port_t *port,
   1803                               bcm_trunk_t *trunk_id, int *id)
   1804 {
   1805     int rv = BCM_E_NONE; 
   1806     ing_l3_next_hop_entry_t ing_nh;
   1807     ing_dvp_table_entry_t dvp;
   1808     int nh_index, vp_base;
   1809 
   1810     _TR_SUBPORT_CHECK_INIT(unit);
   1811     
   1812     vp_base = BCM_GPORT_SUBPORT_GROUP_GET(gport);
   1813     if (vp_base == -1) {
   1814         return BCM_E_PARAM;
   1815     }
   1816 
   1817     if (SOC_IS_TR_VL(unit)) {
   1818         rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base, &dvp);
   1819         BCM_IF_ERROR_RETURN(rv);
   1820         nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   1821         BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   1822                                       nh_index, &ing_nh));
   1823         if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, ENTRY_TYPEf) != 0x3) {
   1824             /* Entry type is not GPON DVP */
   1825             return BCM_E_NOT_FOUND;
   1826         }
   1827     } else if (SOC_IS_SC_CQ(unit)) {
   1828         if (_BCM_GROUP_USED_GET(unit, (vp_base/8)) == 0) {
   1829             return BCM_E_NOT_FOUND;
   1830         } 
   1831         nh_index = _sc_subport_group_index[unit][vp_base/8];
   1832         BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   1833                                       nh_index, &ing_nh));
   1834     }
   1835 
   1836     if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) {
   1837         *trunk_id = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, TGIDf);
   1838     } else {
   1839         *modid = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, MODULE_IDf);
   1840         *port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf);
   1841     }
   1842     *id = vp_base;
   1843     return rv;
   1844 }
   1845 
   1846 /*
   1847  * Function:
   1848  *      _bcm_tr_subport_port_resolve
   1849  * Purpose:
   1850  *      Get the modid, port, trunk values for a subport port GPORT
   1851  * Returns:                  
   1852  *      BCM_E_XXX
   1853  */                          
   1854 int 
   1855 _bcm_tr_subport_port_resolve(int unit, bcm_gport_t gport,
   1856                              bcm_module_t *modid, bcm_port_t *port,
   1857                              bcm_trunk_t *trunk_id, int *id)
   1858 {
   1859     int rv = BCM_E_NONE, l3_idx; 
   1860     ing_l3_next_hop_entry_t ing_nh;
   1861     egr_l3_intf_entry_t l3_intf;
   1862     ing_dvp_table_entry_t dvp;
   1863     int nh_index, vp, vp_base, is_modid_local;
   1864     
   1865     _TR_SUBPORT_CHECK_INIT(unit);
   1866 
   1867     *id = BCM_GPORT_SUBPORT_PORT_GET(gport);
   1868     *modid = (*id >> 12) & SOC_MODID_MAX(unit);
   1869 
   1870     BCM_IF_ERROR_RETURN(
   1871         _bcm_esw_modid_is_local(unit, *modid, &is_modid_local));
   1872 
   1873     if (TRUE != is_modid_local) {
   1874         return (BCM_E_PORT);
   1875     }
   1876 
   1877     l3_idx = BCM_GPORT_SUBPORT_PORT_GET(gport) & 0xfff;
   1878     if (l3_idx >= BCM_XGS3_L3_IF_TBL_SIZE(unit)) {
   1879         return (BCM_E_PARAM);
   1880     }
   1881     rv = soc_mem_read(unit, EGR_L3_INTFm, MEM_BLOCK_ALL, l3_idx, &l3_intf);
   1882     BCM_IF_ERROR_RETURN(rv);
   1883 
   1884     
   1885     if (SOC_IS_TR_VL(unit)) {
   1886         vp = soc_mem_field32_get(unit, EGR_L3_INTFm, &l3_intf, IVIDf);
   1887         vp_base = vp & ~(0x7);
   1888         rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base, &dvp);
   1889         BCM_IF_ERROR_RETURN(rv);
   1890         nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf);
   1891         BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   1892                                       nh_index, &ing_nh));
   1893         if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, ENTRY_TYPEf) != 0x3) {
   1894             /* Entry type is not GPON DVP */
   1895             return BCM_E_NOT_FOUND;
   1896         }
   1897     } else if (SOC_IS_SC_CQ(unit)) {
   1898         /* IVIDf in Scorpion can not be used for vp */
   1899         
   1900         for (vp = 0; vp < SUBPORT_NUM_VP; vp++) {
   1901              if (l3_idx == _BCM_SUBPORT_ID_GET(unit, vp)) {
   1902                  break;
   1903              }
   1904         }
   1905         if (vp == SUBPORT_NUM_VP) {
   1906             return BCM_E_NOT_FOUND;
   1907         }
   1908         vp_base = vp & ~(0x7);
   1909         nh_index = _sc_subport_group_index[unit][vp_base/8];
   1910         BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY,
   1911                                       nh_index, &ing_nh));
   1912     }
   1913 
   1914     if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) {
   1915         *trunk_id = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, TGIDf);
   1916     } else {
   1917         *port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf);
   1918     }
   1919     return rv;
   1920 }
   1921 
   1922 /*
   1923  * Function:
   1924  *      bcm_tr_subport_learn_set
   1925  * Purpose:
   1926  *      Set the CML bits for a subport group.
   1927  * Returns:
   1928  *      BCM_E_XXX
   1929  */
   1930 int
   1931 bcm_tr_subport_learn_set(int unit, bcm_gport_t group, uint32 flags)
   1932 {
   1933     int vp_base, cml = 0, rv = BCM_E_NONE;
   1934     source_vp_entry_t svp;
   1935 
   1936     _TR_SUBPORT_CHECK_INIT(unit);
   1937 
   1938     cml = 0;
   1939     if (!(flags & BCM_PORT_LEARN_FWD)) {
   1940        cml |= (1 << 0);
   1941     }
   1942     if (flags & BCM_PORT_LEARN_CPU) {
   1943        cml |= (1 << 1);
   1944     }
   1945     if (flags & BCM_PORT_LEARN_PENDING) {
   1946        cml |= (1 << 2);
   1947     }
   1948     if (flags & BCM_PORT_LEARN_ARL) {
   1949        cml |= (1 << 3);
   1950     }
   1951 
   1952     vp_base = BCM_GPORT_SUBPORT_GROUP_GET(group); 
   1953     if (vp_base == -1) {
   1954         return BCM_E_PARAM;
   1955     }
   1956 
   1957     if (!_BCM_GROUP_USED_GET(unit, vp_base / 8)) {
   1958         return BCM_E_NOT_FOUND;
   1959     }
   1960     MEM_LOCK(unit, SOURCE_VPm);
   1961     rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp_base, &svp);
   1962     if (soc_SOURCE_VPm_field32_get(unit, &svp, ENTRY_TYPEf) != 0x3) {
   1963         MEM_UNLOCK(unit, SOURCE_VPm);
   1964         return BCM_E_INTERNAL;
   1965     }
   1966     soc_SOURCE_VPm_field32_set(unit, &svp, CML_FLAGS_MOVEf, cml);
   1967     soc_SOURCE_VPm_field32_set(unit, &svp, CML_FLAGS_NEWf, cml);
   1968     rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp_base, &svp);
   1969     MEM_UNLOCK(unit, SOURCE_VPm);
   1970     return rv;
   1971 }
   1972 
   1973 /*
   1974  * Function:
   1975  *      bcm_tr_subport_learn_get
   1976  * Purpose:
   1977  *      Get the CML bits for a subport group.
   1978  * Returns: 
   1979  *      BCM_E_XXX
   1980  */     
   1981 int
   1982 bcm_tr_subport_learn_get(int unit, bcm_gport_t group, uint32 *flags)
   1983 {
   1984     int vp_base, cml;
   1985     source_vp_entry_t svp; 
   1986     
   1987     _TR_SUBPORT_CHECK_INIT(unit);
   1988 
   1989     vp_base = BCM_GPORT_SUBPORT_GROUP_GET(group);
   1990     if (vp_base == -1) {
   1991         return BCM_E_PARAM;
   1992     }
   1993 
   1994     if (!_BCM_GROUP_USED_GET(unit, vp_base / 8)) {
   1995         return BCM_E_NOT_FOUND;
   1996     }
   1997     BCM_IF_ERROR_RETURN
   1998         (READ_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp_base, &svp));
   1999     if (soc_SOURCE_VPm_field32_get(unit, &svp, ENTRY_TYPEf) != 0x3) {
   2000         return BCM_E_INTERNAL;
   2001     }
   2002     cml = soc_SOURCE_VPm_field32_get(unit, &svp, CML_FLAGS_NEWf);
   2003 
   2004     *flags = 0;
   2005     if (!(cml & (1 << 0))) {
   2006        *flags |= BCM_PORT_LEARN_FWD;
   2007     }
   2008     if (cml & (1 << 1)) {
   2009        *flags |= BCM_PORT_LEARN_CPU;
   2010     }
   2011     if (cml & (1 << 2)) {
   2012        *flags |= BCM_PORT_LEARN_PENDING;
   2013     }
   2014     if (cml & (1 << 3)) {
   2015        *flags |= BCM_PORT_LEARN_ARL;
   2016     }
   2017 
   2018     return BCM_E_NONE;
   2019 }
   2020 
   2021 #ifdef BCM_WARM_BOOT_SUPPORT_SW_DUMP
   2022 /*
   2023  * Function:
   2024  *      _bcm_tr_subport_sw_dump
   2025  * Purpose:
   2026  *      Print Subport module s/w state
   2027  * Returns: 
   2028  *      void
   2029  */     
   2030 void
   2031 _bcm_tr_subport_sw_dump(int unit)
   2032 {
   2033     int idx, sub_prt;
   2034 
   2035     if(BCM_ESW_SUBPORT_DRV(unit) == NULL) {
   2036         LOG_CLI((BSL_META_U(unit,
   2037                             "\nSubport DRV function is not initialized\n")));
   2038         return;
   2039     }
   2040     LOG_CLI((BSL_META_U(unit,
   2041                         "Subport Groups:\n")));
   2042     for(idx = 0; idx < SUBPORT_NUM_GROUP; idx++) {
   2043         if(_BCM_GROUP_USED_GET(unit, idx)) {
   2044             LOG_CLI((BSL_META_U(unit,
   2045                                 "%d "), idx));
   2046         }
   2047     }
   2048 
   2049     LOG_CLI((BSL_META_U(unit,
   2050                         "\n----\n")));
   2051 
   2052     LOG_CLI((BSL_META_U(unit,
   2053                         "Subport IDs used:\n")));
   2054     for(idx = 0; idx < SUBPORT_NUM_VP; idx++) {
   2055         if((sub_prt = _BCM_SUBPORT_ID_GET(unit, idx)) != 0xffff) {
   2056             LOG_CLI((BSL_META_U(unit,
   2057                                 "Subport ID=%d, VP=%d \n"), sub_prt, idx));
   2058         }
   2059     }
   2060 }
   2061 #endif /* BCM_WARM_BOOT_SUPPORT_SW_DUMP */
   2062 
   2063 #else  /* INCLUDE_L3 && BCM_TRX_SUPPORT */
   2064 int bcm_esw_triumph_subport_not_empty;
   2065 #endif /* INCLUDE_L3 && BCM_TRX_SUPPORT */