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

l2_helpers.c (84901B)


      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:        l2.c
      8  * Purpose:     Triumph L2 function implementations
      9  */
     10 
     11 #include <shared/bsl.h>
     12 
     13 #include <soc/defs.h>
     14 #include <assert.h>
     15 
     16 #include <sal/core/libc.h>
     17 
     18 #include <soc/mem.h>
     19 #include <soc/cm.h>
     20 #include <soc/drv.h>
     21 #include <soc/register.h>
     22 #include <soc/memory.h>
     23 #include <soc/hash.h>
     24 #include <soc/l2x.h>
     25 #include <soc/tomahawk3.h>
     26 #include <soc/triumph.h>
     27 #ifdef BCM_TRIDENT2_SUPPORT
     28 #include <soc/trident2.h>
     29 #endif /* BCM_TRIDENT2_SUPPORT */
     30 #ifdef BCM_TOMAHAWK_SUPPORT
     31 #include <soc/tomahawk.h>
     32 #endif /* BCM_TOMAHAWK_SUPPORT */
     33 
     34 #include <bcm/l2.h>
     35 #include <bcm/error.h>
     36 
     37 #include <bcm_int/esw/mbcm.h>
     38 #include <bcm_int/esw/l2.h>
     39 #include <bcm_int/esw/firebolt.h>
     40 #include <bcm_int/esw/trx.h>
     41 #include <bcm_int/esw/triumph.h>
     42 #include <bcm_int/esw/mpls.h>
     43 #include <bcm_int/common/multicast.h>
     44 #include <bcm_int/esw/multicast.h>
     45 #include <bcm_int/esw_dispatch.h>
     46 #include <bcm_int/esw/trident.h>
     47 #include <bcm_int/esw/switch.h>
     48 #if defined(BCM_TRIUMPH3_SUPPORT)
     49 #include <bcm_int/esw/triumph3.h>
     50 #endif /* BCM_TRIUMPH3_SUPPORT */
     51 #if defined(BCM_TRIDENT2_SUPPORT)
     52 #include <bcm_int/esw/trident2.h>
     53 #endif /* BCM_TRIDENT2_SUPPORT */
     54 
     55 #ifdef BCM_TOMAHAWK3_SUPPORT
     56 #include <bcm_int/esw/tomahawk3.h>
     57 
     58 #if defined(BCM_TRIUMPH_SUPPORT) /* BCM_TRIUMPH_SUPPORT */
     59 
     60 #define GPORT_TYPE(_gport) (((_gport) >> _SHR_GPORT_TYPE_SHIFT) & _SHR_GPORT_TYPE_MASK)
     61 
     62 #endif /* !BCM_TRIUMPH_SUPPORT */
     63 #define DEFAULT_L2DELETE_CHUNKS		64	/* 8k entries / 64 = 512 */
     64 
     65 typedef struct _bcm_mac_block_info_s {
     66     bcm_pbmp_t mb_pbmp;
     67     int ref_count;
     68 } _bcm_mac_block_info_t;
     69 
     70 static _bcm_mac_block_info_t *_mbi_entries[BCM_MAX_NUM_UNITS];
     71 static int _mbi_num[BCM_MAX_NUM_UNITS];
     72 
     73 #if defined(INCLUDE_L3)
     74 extern int16 * _sc_subport_group_index[BCM_MAX_NUM_UNITS];
     75 #define _SC_SUBPORT_NUM_PORT  (4096)
     76 #define _SC_SUBPORT_NUM_GROUP (4096/8)
     77 #define _SC_SUBPORT_VPG_FIND(unit, vp, grp) \
     78     do { \
     79          int ix; \
     80          grp = -1; \
     81          for (ix = 0; ix < _SC_SUBPORT_NUM_GROUP; ix++) { \
     82               if (_sc_subport_group_index[unit][ix] == vp) { \
     83                   grp = ix * 8; \
     84                   break;  \
     85               } \
     86          } \
     87        } while ((0))
     88 #endif /* INCLUDE_L3 */
     89 
     90 typedef enum _bcm_th3_l2x_memacc_field_e {
     91     _BCM_TH3_L2X_MEMACC_BASE_VALID_f,
     92     _BCM_TH3_L2X_MEMACC_KEY_TYPE_f,
     93     _BCM_TH3_L2X_MEMACC_MAC_ADDR_f,
     94     _BCM_TH3_L2X_MEMACC_VLAN_ID_f,
     95     _BCM_TH3_L2X_MEMACC_L2MC_PTR_f,
     96     _BCM_TH3_L2X_MEMACC_DEST_TYPE_f,
     97     _BCM_TH3_L2X_MEMACC_TGID_f,
     98     _BCM_TH3_L2X_MEMACC_PORT_NUM_f,
     99     _BCM_TH3_L2X_MEMACC_CLASS_ID_f,
    100     _BCM_TH3_L2X_MEMACC_MAC_BLOCK_INDEX_f,
    101     _BCM_TH3_L2X_MEMACC_PRI_f,
    102     _BCM_TH3_L2X_MEMACC_CPU_f,
    103     _BCM_TH3_L2X_MEMACC_DST_DISCARD_f,
    104     _BCM_TH3_L2X_MEMACC_SRC_DISCARD_f,
    105     _BCM_TH3_L2X_MEMACC_SCP_f,
    106     _BCM_TH3_L2X_MEMACC_STATIC_BIT_f,
    107     _BCM_TH3_L2X_MEMACC_HITDA_f,
    108     _BCM_TH3_L2X_MEMACC_HITSA_f,
    109     _BCM_TH3_L2X_MEMACC_LOCAL_SA_f,
    110     _BCM_TH3_L2X_MEMACC_DESTINATION_f,
    111     _BCM_TH3_L2X_MEMACC_T_f,
    112     _BCM_TH3_L2X_MEMACC_RPE_f,
    113     _BCM_TH3_L2X_MEMACC_RESERVED_KEY_PADDING_f,
    114     _BCM_TH3_L2X_MEMACC_NUM
    115 } _bcm_th3_l2x_memacc_field_t;
    116 
    117 static soc_memacc_t *_bcm_th3_l2x_memacc[BCM_UNITS_MAX];
    118 static soc_field_t   _bcm_th3_l2x_fields[] = {
    119     BASE_VALIDf,
    120     KEY_TYPEf,
    121     MAC_ADDRf,
    122     VLAN_IDf,
    123     L2MC_PTRf,
    124     DEST_TYPEf,
    125     TGIDf,
    126     PORT_NUMf,
    127     CLASS_IDf,
    128     MAC_BLOCK_INDEXf,
    129     PRIf,
    130     CPUf,
    131     DST_DISCARDf,
    132     SRC_DISCARDf,
    133     SCPf,
    134     STATIC_BITf,
    135     HITDAf,
    136     HITSAf,
    137     LOCAL_SAf,
    138     DESTINATIONf,
    139     Tf,
    140     RPEf,
    141     RESERVED_KEY_PADDINGf 
    142 };
    143 
    144 #define _BCM_L2X_MEMACC_FIELD(_u_, _f_) \
    145             (&_bcm_th3_l2x_memacc[_u_][_BCM_TH3_L2X_MEMACC_##_f_])
    146 
    147 #define _BCM_L2X_MEMACC_FIELD_VALID(_u_, _f_) \
    148             SOC_MEMACC_VALID(_BCM_L2X_MEMACC_FIELD(_u_, _f_))
    149 
    150 #define _BCM_L2X_MEMACC_FIELD32_GET(_u_, _entBuf_, _f_) \
    151             soc_memacc_field32_get(_BCM_L2X_MEMACC_FIELD(_u_, _f_), _entBuf_)
    152 
    153 #define _BCM_L2X_MEMACC_FIELD32_SET(_u_, _entBuf_, _f_, _v_) \
    154             soc_memacc_field32_set(_BCM_L2X_MEMACC_FIELD(_u_, _f_), _entBuf_, \
    155                                    _v_)
    156 
    157 typedef enum _bcm_th3_l2hit_mem_e {
    158     _BCM_TH3_L2HITDA,
    159     _BCM_TH3_L2HITSA,
    160     _BCM_TH3_L2HIT_MEM_NUM
    161 } _bcm_th3_l2hit_mem_t;
    162 
    163 typedef enum _bcm_th3_l2hit_field_e {
    164     _BCM_TH3_L2HITDA_HITDA_f_0,
    165     _BCM_TH3_L2HITDA_HITDA_f_1,
    166     _BCM_TH3_L2HITDA_HITDA_f_2,
    167     _BCM_TH3_L2HITDA_HITDA_f_3,
    168     _BCM_TH3_L2HITSA_HITSA_f_0,
    169     _BCM_TH3_L2HITSA_HITSA_f_1,
    170     _BCM_TH3_L2HITSA_HITSA_f_2,
    171     _BCM_TH3_L2HITSA_HITSA_f_3,
    172     _BCM_TH3_L2HITSA_LOCAL_SA_f_0,
    173     _BCM_TH3_L2HITSA_LOCAL_SA_f_1,
    174     _BCM_TH3_L2HITSA_LOCAL_SA_f_2,
    175     _BCM_TH3_L2HITSA_LOCAL_SA_f_3,
    176     _BCM_TH3_L2HIT_FIELD_NUM
    177 } _bcm_th3_l2hit_field_t;
    178 
    179 
    180 static soc_memacc_t *_th3_l2hit_memacc[BCM_UNITS_MAX][_BCM_TH3_L2HIT_MEM_NUM];
    181 
    182 #define _TH3_L2HIT_MEM(_u_, _m_, _p_) \
    183             (_BCM_TH3_##_m_ + (_p_))
    184 
    185 #define _TH3_L2HIT_FIELD(_u_, _m_,_f_, _i_) \
    186             (_BCM_TH3_##_m_##_##_f_##_0 + (_i_))
    187 
    188 #define _TH3_L2HIT_MEMACC_FIELD(_u_, _mem_, _fld_) \
    189             (&_th3_l2hit_memacc[_u_][_mem_][_fld_])
    190 
    191 #define _TH3_L2HIT_MEMACC_FIELD32_GET(_u_, _mem_, _entBuf_, _fld_) \
    192             soc_memacc_field32_get(_TH3_L2HIT_MEMACC_FIELD(_u_, _mem_, _fld_), \
    193                                    _entBuf_)
    194 
    195 STATIC int
    196 _bcm_th3_l2_memacc_init(int unit)
    197 {
    198     int rv, i;
    199     int alloc_size;
    200     int m, f;
    201     static soc_mem_t   _bcm_th3_l2hit_mems[] = {
    202         L2_HITDA_ONLYm,
    203         L2_HITSA_ONLYm,
    204     };
    205     static soc_field_t   _bcm_th3_l2hit_fields[] = {
    206         HITDA_0f, HITDA_1f, HITDA_2f, HITDA_3f,
    207         HITSA_0f, HITSA_1f, HITSA_2f, HITSA_3f,
    208         LOCAL_SA_0f, LOCAL_SA_1f, LOCAL_SA_2f, LOCAL_SA_3f,
    209     };
    210 
    211     if (_bcm_th3_l2x_memacc[unit] != NULL) {
    212         sal_free(_bcm_th3_l2x_memacc[unit]);
    213     }
    214     alloc_size = sizeof(soc_memacc_t) * _BCM_TH3_L2X_MEMACC_NUM;
    215     _bcm_th3_l2x_memacc[unit] = sal_alloc(alloc_size, "L2 memacc");
    216     if (_bcm_th3_l2x_memacc[unit] == NULL) {
    217         return BCM_E_MEMORY;
    218     }
    219     sal_memset(_bcm_th3_l2x_memacc[unit], 0, alloc_size);
    220 
    221     for (i = 0; i < _BCM_TH3_L2X_MEMACC_NUM; i++) {
    222         rv = soc_memacc_init(unit, L2Xm, _bcm_th3_l2x_fields[i], 
    223                              &_bcm_th3_l2x_memacc[unit][i]);
    224         if (BCM_FAILURE(rv)) {
    225             SOC_MEMACC_INVALID_SET(&_bcm_th3_l2x_memacc[unit][i]);
    226         }
    227     }
    228 
    229     for (m = 0; m < _BCM_TH3_L2HIT_MEM_NUM; m++) {
    230         if (_th3_l2hit_memacc[unit][m] != NULL) {
    231             sal_free(_th3_l2hit_memacc[unit][m]);
    232         }
    233         alloc_size = sizeof(soc_memacc_t) * _BCM_TH3_L2HIT_FIELD_NUM;
    234         _th3_l2hit_memacc[unit][m] = sal_alloc(alloc_size, "L2hit memacc");
    235         if (_th3_l2hit_memacc[unit][m] == NULL) {
    236             sal_free(_bcm_th3_l2x_memacc[unit]);
    237             _bcm_th3_l2x_memacc[unit] = NULL;
    238             return BCM_E_MEMORY;
    239         }
    240         
    241         for (f = 0; f < _BCM_TH3_L2HIT_FIELD_NUM; f++) {
    242             rv = soc_memacc_init(unit, _bcm_th3_l2hit_mems[m], 
    243                                  _bcm_th3_l2hit_fields[f], 
    244                                  &_th3_l2hit_memacc[unit][m][f]);
    245             if (BCM_FAILURE(rv)) {
    246                 SOC_MEMACC_INVALID_SET(&_th3_l2hit_memacc[unit][m][f]);
    247             }
    248         }
    249     }
    250 
    251     return BCM_E_NONE;
    252 }
    253 
    254 STATIC int
    255 _bcm_th3_l2_memacc_deinit(int unit)
    256 {
    257     int m;
    258 
    259     if (_bcm_th3_l2x_memacc[unit] != NULL) {
    260         sal_free(_bcm_th3_l2x_memacc[unit]);
    261         _bcm_th3_l2x_memacc[unit] = NULL;
    262     }
    263 
    264     for (m = 0; m < _BCM_TH3_L2HIT_MEM_NUM; m++) {
    265         if (_th3_l2hit_memacc[unit][m] != NULL) {
    266             sal_free(_th3_l2hit_memacc[unit][m]);
    267             _th3_l2hit_memacc[unit][m] = NULL;
    268         }
    269     }
    270     
    271     return BCM_E_NONE;
    272 }
    273 
    274 /*
    275  * Function:
    276  *      _bcm_th3_mac_block_delete
    277  * Purpose:
    278  *      Remove reference to MAC_BLOCK table entry matching the given bitmap
    279  * Parameters:
    280  *      unit - Unit number
    281  *      mb_index - Index of MAC_BLOCK table with bitmap
    282  */
    283 STATIC void
    284 _bcm_th3_mac_block_delete(int unit, int mb_index)
    285 {
    286     if (_mbi_entries[unit][mb_index].ref_count > 0) {
    287         _mbi_entries[unit][mb_index].ref_count--;
    288     } else if (mb_index) {
    289         /* Someone reran init without flushing L2 table */
    290     } /* else mb_index = 0, as expected for learning */
    291 }
    292 
    293 /*
    294  * Function:
    295  *      _bcm_th3_mac_block_insert
    296  * Purpose:
    297  *      Find or create a MAC_BLOCK table entry matching the given bitmap
    298  * Parameters:
    299  *      unit - Unit number
    300  *      mb_pbmp - egress port bitmap for source MAC blocking
    301  *      mb_index - (OUT) Index of MAC_BLOCK table with bitmap
    302  * Returns:
    303  *      BCM_E_NONE              Success
    304  *      BCM_E_INTERNAL          Chip access failure
    305  *      BCM_E_RESOURCE          No more MAC_BLOCK entries available
    306  *      BCM_E_PARAM             Bad bitmap supplied
    307  */
    308 STATIC int
    309 _bcm_th3_mac_block_insert(int unit, bcm_pbmp_t mb_pbmp, int *mb_index)
    310 {
    311     int cur_index = 0;
    312     _bcm_mac_block_info_t *mbi = _mbi_entries[unit];
    313     mac_block_entry_t mbe;
    314     bcm_pbmp_t temp_pbmp;
    315 
    316     /* Check for reasonable pbmp */
    317     BCM_PBMP_ASSIGN(temp_pbmp, mb_pbmp);
    318     BCM_PBMP_AND(temp_pbmp, PBMP_ALL(unit));
    319     if (BCM_PBMP_NEQ(mb_pbmp, temp_pbmp)) {
    320         return BCM_E_PARAM;
    321     }
    322 
    323     for (cur_index = 0; cur_index < _mbi_num[unit]; cur_index++) {
    324         if (BCM_PBMP_EQ(mbi[cur_index].mb_pbmp, mb_pbmp)) {
    325             mbi[cur_index].ref_count++;
    326             *mb_index = cur_index;
    327             return BCM_E_NONE;
    328         }
    329     }
    330 
    331     /* Not in table already, see if any space free */
    332     for (cur_index = 1; cur_index < _mbi_num[unit]; cur_index++) {
    333         if (mbi[cur_index].ref_count == 0) {
    334             /* Attempt insert */
    335             sal_memset(&mbe, 0, sizeof(mac_block_entry_t));
    336 
    337             soc_mem_pbmp_field_set(unit, MAC_BLOCKm, &mbe, MAC_BLOCK_MASKf,
    338                                    &mb_pbmp);
    339 
    340             SOC_IF_ERROR_RETURN(WRITE_MAC_BLOCKm(unit, MEM_BLOCK_ALL,
    341                                                  cur_index, &mbe));
    342             mbi[cur_index].ref_count++;
    343             BCM_PBMP_ASSIGN(mbi[cur_index].mb_pbmp, mb_pbmp);
    344             *mb_index = cur_index;
    345             return BCM_E_NONE;
    346         }
    347     }
    348 
    349     /* Didn't find a free slot, out of table space */
    350     return BCM_E_RESOURCE;
    351 }
    352 
    353 
    354 #if 0
    355 /*
    356  * function:
    357  *     _bcm_tr_l2_traverse_mem
    358  * Description:
    359  *      Helper function to _bcm_esw_l2_traverse to itterate over given memory
    360  *      and actually read the table and parse entries for Triumph external
    361  *      memory
    362  * Parameters:
    363  *     unit         device number
    364  *      mem         External L2 memory to read
    365  *     trav_st      Traverse structure with all the data.
    366  * Return:
    367  *     BCM_E_XXX
    368  */
    369 #ifdef BCM_TRIUMPH_SUPPORT
    370 int
    371 _bcm_tr_l2_traverse_mem(int unit, soc_mem_t mem, _bcm_l2_traverse_t *trav_st)
    372 {
    373     _soc_tr_l2e_ppa_info_t    *ppa_info;
    374     ext_l2_entry_entry_t      ext_l2_entry;
    375     ext_l2_entry_tcam_entry_t tcam_entry;
    376     ext_l2_entry_data_entry_t data_entry;
    377     ext_src_hit_bits_l2_entry_t src_hit_entry;
    378     ext_dst_hit_bits_l2_entry_t dst_hit_entry;
    379     int                       src_hit, dst_hit;
    380     int                       idx, idx_max;
    381 
    382     if (mem != EXT_L2_ENTRYm) {
    383         return BCM_E_UNAVAIL;
    384     }
    385 
    386     if (!soc_mem_index_count(unit, mem)) {
    387         return BCM_E_NONE;
    388     }
    389 
    390     ppa_info = SOC_CONTROL(unit)->ext_l2_ppa_info;
    391     if (ppa_info == NULL) {
    392         return BCM_E_NONE;
    393     }
    394 
    395     idx_max = soc_mem_index_max(unit, mem);
    396     for (idx = soc_mem_index_min(unit, mem); idx <= idx_max; idx++ ) {
    397         if (!(ppa_info[idx].data & _SOC_TR_L2E_VALID)) {
    398             continue;
    399         }
    400         SOC_IF_ERROR_RETURN
    401             (soc_mem_read(unit, EXT_L2_ENTRY_TCAMm, MEM_BLOCK_ANY, idx,
    402                           &tcam_entry));
    403         SOC_IF_ERROR_RETURN
    404             (soc_mem_read(unit, EXT_L2_ENTRY_DATAm, MEM_BLOCK_ANY, idx,
    405                           &data_entry));
    406         SOC_IF_ERROR_RETURN
    407             (soc_mem_read(unit, EXT_SRC_HIT_BITS_L2m, MEM_BLOCK_ANY, idx >> 5,
    408                           &src_hit_entry));
    409         SOC_IF_ERROR_RETURN
    410             (soc_mem_read(unit, EXT_DST_HIT_BITS_L2m, MEM_BLOCK_ANY, idx >> 5,
    411                           &dst_hit_entry));
    412         src_hit = (soc_mem_field32_get
    413                    (unit, EXT_SRC_HIT_BITS_L2m, &src_hit_entry, SRC_HITf) >>
    414                    (idx & 0x1f)) & 1;
    415         dst_hit = (soc_mem_field32_get
    416                    (unit, EXT_DST_HIT_BITS_L2m, &dst_hit_entry, DST_HITf) >>
    417                    (idx & 0x1f)) & 1;
    418         BCM_IF_ERROR_RETURN
    419             (_bcm_tr_compose_ext_l2_entry(unit, &tcam_entry, &data_entry,
    420                                           src_hit, dst_hit, &ext_l2_entry));
    421         trav_st->data = (uint32 *)&ext_l2_entry;
    422         trav_st->mem = mem;
    423 
    424         BCM_IF_ERROR_RETURN(trav_st->int_cb(unit, trav_st));
    425     }
    426 
    427     return BCM_E_NONE;
    428 }
    429 #endif /* BCM_TRIUMPH_SUPPORT */
    430 
    431 /*
    432  * Function:
    433  *      _bcm_mac_block_insert
    434  * Purpose:
    435  *      Find or create a MAC_BLOCK table entry matching the given bitmap.
    436  * Parameters:
    437  *      unit - Unit number
    438  *      mb_pbmp - egress port bitmap for source MAC blocking
    439  *      mb_index - (OUT) Index of MAC_BLOCK table with bitmap.
    440  * Returns:
    441  *      BCM_E_NONE              Success
    442  *      BCM_E_INTERNAL          Chip access failure
    443  *      BCM_E_RESOURCE          No more MAC_BLOCK entries available
    444  *      BCM_E_PARAM             Bad bitmap supplied
    445  */
    446 static int
    447 _bcm_mac_block_insert(int unit, bcm_pbmp_t mb_pbmp, int *mb_index)
    448 {
    449     int cur_index = 0;
    450     _bcm_mac_block_info_t *mbi = _mbi_entries[unit];
    451     mac_block_entry_t mbe;
    452     bcm_pbmp_t temp_pbmp;
    453 #if defined(BCM_KATANA2_SUPPORT)
    454     uint32     fldbuf[SOC_PBMP_WORD_MAX];
    455     bcm_pbmp_t mb_pbmp0, mb_pbmp1;
    456     int        mask_w0_width = 0;
    457     int        mask_w1_width = 0;
    458     int        i = 0;
    459 
    460     SOC_PBMP_CLEAR(mb_pbmp0);
    461     SOC_PBMP_CLEAR(mb_pbmp1);
    462 #endif
    463 
    464     /* Check for reasonable pbmp */
    465     BCM_PBMP_ASSIGN(temp_pbmp, mb_pbmp);
    466     BCM_PBMP_AND(temp_pbmp, PBMP_ALL(unit));
    467     if (BCM_PBMP_NEQ(mb_pbmp, temp_pbmp)) {
    468         return BCM_E_PARAM;
    469     }
    470 
    471     for (cur_index = 0; cur_index < _mbi_num[unit]; cur_index++) {
    472         if (BCM_PBMP_EQ(mbi[cur_index].mb_pbmp, mb_pbmp)) {
    473             mbi[cur_index].ref_count++;
    474             *mb_index = cur_index;
    475             return BCM_E_NONE;
    476         }
    477     }
    478 
    479     /* Not in table already, see if any space free */
    480     for (cur_index = 1; cur_index < _mbi_num[unit]; cur_index++) {
    481         if (mbi[cur_index].ref_count == 0) {
    482             /* Attempt insert */
    483             sal_memset(&mbe, 0, sizeof(mac_block_entry_t));
    484 
    485             if (soc_mem_field_valid(unit, MAC_BLOCKm, MAC_BLOCK_MASK_LOf)) {
    486                 soc_MAC_BLOCKm_field32_set(unit, &mbe, MAC_BLOCK_MASK_LOf,
    487                                            SOC_PBMP_WORD_GET(mb_pbmp, 0));
    488             } else if (soc_mem_field_valid(unit, MAC_BLOCKm,
    489                                            MAC_BLOCK_MASK_W0f)) {
    490 #if defined(BCM_KATANA2_SUPPORT)
    491                 if (SOC_IS_KATANA2(unit)) {
    492                     mask_w0_width = soc_mem_field_length(unit, MAC_BLOCKm,
    493                                                          MAC_BLOCK_MASK_W0f);
    494                     for (i = 0; i < mask_w0_width; i++) {
    495                         if (SOC_PBMP_MEMBER(mb_pbmp, i)) {
    496                             SOC_PBMP_PORT_ADD(mb_pbmp0, i);
    497                         }
    498                     }
    499 
    500                     sal_memset(fldbuf, 0, SOC_PBMP_WORD_MAX * sizeof(uint32));
    501                     for (i = 0; i < SOC_PBMP_WORD_MAX; i++) {
    502                         fldbuf[i] = SOC_PBMP_WORD_GET(mb_pbmp0, i);
    503                     }
    504                     soc_MAC_BLOCKm_field_set(unit, &mbe,
    505                                              MAC_BLOCK_MASK_W0f, fldbuf);
    506                 } else
    507 #endif /* BCM_KATANA2_SUPPORT */
    508                 {
    509                     soc_MAC_BLOCKm_field32_set(unit, &mbe, MAC_BLOCK_MASK_W0f,
    510                                            SOC_PBMP_WORD_GET(mb_pbmp, 0));
    511                 }
    512             } else if (soc_mem_field_valid(unit, MAC_BLOCKm,
    513                                            MAC_BLOCK_MASKf)) {
    514                 soc_mem_pbmp_field_set(unit, MAC_BLOCKm, &mbe, MAC_BLOCK_MASKf,
    515                                        &mb_pbmp); 
    516             } else {
    517                 return BCM_E_INTERNAL;
    518             }
    519             if (soc_mem_field_valid(unit, MAC_BLOCKm, MAC_BLOCK_MASK_HIf)) {
    520                 soc_MAC_BLOCKm_field32_set(unit, &mbe, MAC_BLOCK_MASK_HIf,
    521                                            SOC_PBMP_WORD_GET(mb_pbmp, 1));
    522             } else if (soc_mem_field_valid(unit, MAC_BLOCKm, MAC_BLOCK_MASK_W1f)) {
    523 #if defined(BCM_KATANA2_SUPPORT)
    524                 if (SOC_IS_KATANA2(unit)) {
    525                     mask_w1_width = soc_mem_field_length(unit, MAC_BLOCKm,
    526                                                          MAC_BLOCK_MASK_W1f);
    527 
    528                     for (i = mask_w0_width;
    529                          i < (mask_w0_width + mask_w1_width); i++) {
    530                         if (SOC_PBMP_MEMBER(mb_pbmp, i)) {
    531                             SOC_PBMP_PORT_ADD(mb_pbmp1, (i - mask_w0_width));
    532                         }
    533                     }
    534 
    535                     sal_memset(fldbuf, 0, SOC_PBMP_WORD_MAX * sizeof(uint32));
    536                     for (i = 0; i < SOC_PBMP_WORD_MAX; i++) {
    537                         fldbuf[i] = SOC_PBMP_WORD_GET(mb_pbmp1, i);
    538                     }
    539                     soc_MAC_BLOCKm_field_set(unit, &mbe,
    540                                              MAC_BLOCK_MASK_W1f, fldbuf);
    541                 } else
    542 #endif /* BCM_KATANA2_SUPPORT */
    543                 {
    544                     soc_MAC_BLOCKm_field32_set(unit, &mbe, MAC_BLOCK_MASK_W1f,
    545                                            SOC_PBMP_WORD_GET(mb_pbmp, 1));
    546                 }
    547             }
    548             if (soc_mem_field_valid(unit, MAC_BLOCKm, MAC_BLOCK_MASK_W2f)) {
    549 #if defined(BCM_TRIDENT_SUPPORT)
    550                 if (SOC_IS_TRIDENT(unit)) {
    551                     soc_MAC_BLOCKm_field32_set(unit, &mbe, MAC_BLOCK_MASK_W2f,
    552                                                SOC_PBMP_WORD_GET(mb_pbmp, 2));
    553                 }
    554 #endif
    555             }
    556 
    557             SOC_IF_ERROR_RETURN(WRITE_MAC_BLOCKm(unit, MEM_BLOCK_ALL,
    558                                                  cur_index, &mbe));
    559             mbi[cur_index].ref_count++;
    560             BCM_PBMP_ASSIGN(mbi[cur_index].mb_pbmp, mb_pbmp);
    561             *mb_index = cur_index;
    562             return BCM_E_NONE;
    563         }
    564     }
    565 
    566     /* Didn't find a free slot, out of table space */
    567     return BCM_E_RESOURCE;
    568 }
    569 
    570 /*
    571  * Function:
    572  *      _bcm_mac_block_delete
    573  * Purpose:
    574  *      Remove reference to MAC_BLOCK table entry matching the given bitmap.
    575  * Parameters:
    576  *      unit - Unit number
    577  *      mb_index - Index of MAC_BLOCK table with bitmap.
    578  */
    579 static void
    580 _bcm_mac_block_delete(int unit, int mb_index)
    581 {
    582     if (_mbi_entries[unit][mb_index].ref_count > 0) {
    583         _mbi_entries[unit][mb_index].ref_count--;
    584     } else if (mb_index) {
    585         
    586         /* Someone reran init without flushing the L2 table */
    587     } /* else mb_index = 0, as expected for learning */
    588 }
    589 
    590 #endif /* 0 */
    591 
    592 
    593 #if 0
    594 #ifdef BCM_TRIUMPH_SUPPORT
    595 STATIC int
    596 _bcm_t_l2e_ppa_match(int unit, _bcm_l2_replace_t *rep_st)
    597 {
    598     _soc_tr_l2e_ppa_info_t      *ppa_info;
    599     _soc_tr_l2e_ppa_vlan_t      *ppa_vlan;
    600     int                         i, imin, imax, rv, nmatches;
    601     soc_mem_t                   mem;
    602     uint32                      entdata, entmask, entvalue, newdata, newmask;
    603     ext_l2_entry_entry_t        l2entry, old_l2entry;
    604     int                         same_dest;
    605 
    606     ppa_info = SOC_CONTROL(unit)->ext_l2_ppa_info;
    607     ppa_vlan = SOC_CONTROL(unit)->ext_l2_ppa_vlan;
    608     if (ppa_info == NULL) {
    609         return BCM_E_NONE;
    610     }
    611 
    612     mem = EXT_L2_ENTRYm;
    613     imin = soc_mem_index_min(unit, mem);
    614     imax = soc_mem_index_max(unit, mem);
    615 
    616     /* convert match data */
    617     entdata = _SOC_TR_L2E_VALID;
    618     entmask = _SOC_TR_L2E_VALID;
    619     if (!(rep_st->flags & BCM_L2_REPLACE_MATCH_STATIC)) {
    620         entdata |= 0x00000000;
    621         entmask |= _SOC_TR_L2E_STATIC;
    622     }
    623     if (rep_st->flags & BCM_L2_REPLACE_MATCH_VLAN) {
    624         entdata |= (rep_st->key_vlan & _SOC_TR_L2E_VLAN_MASK) <<
    625             _SOC_TR_L2E_VLAN_SHIFT;
    626         entmask |= _SOC_TR_L2E_VLAN_MASK << _SOC_TR_L2E_VLAN_SHIFT;
    627         imin = ppa_vlan->vlan_min[rep_st->key_vlan];
    628         imax = ppa_vlan->vlan_max[rep_st->key_vlan];
    629     }
    630     if (rep_st->flags & BCM_L2_REPLACE_MATCH_DEST) {
    631         if (rep_st->match_dest.trunk != -1) {
    632             entdata |= _SOC_TR_L2E_T |
    633                 ((rep_st->match_dest.trunk & _SOC_TR_L2E_TRUNK_MASK)
    634                  << _SOC_TR_L2E_TRUNK_SHIFT);
    635             entmask |= _SOC_TR_L2E_T |
    636                 (_SOC_TR_L2E_TRUNK_MASK << _SOC_TR_L2E_TRUNK_SHIFT);
    637         } else {
    638             entdata |= 
    639                 ((rep_st->match_dest.module & _SOC_TR_L2E_MOD_MASK) <<
    640                  _SOC_TR_L2E_MOD_SHIFT) |
    641                 ((rep_st->match_dest.port & _SOC_TR_L2E_PORT_MASK) <<
    642                  _SOC_TR_L2E_PORT_SHIFT);
    643             entmask |= _SOC_TR_L2E_T |
    644                 (_SOC_TR_L2E_MOD_MASK << _SOC_TR_L2E_MOD_SHIFT) |
    645                 (_SOC_TR_L2E_PORT_MASK << _SOC_TR_L2E_PORT_SHIFT);
    646         }
    647     }
    648 
    649     nmatches = 0;
    650 
    651     if (imin >= 0) {
    652         soc_mem_lock(unit, mem);
    653         for (i = imin; i <= imax; i++) {
    654             entvalue = ppa_info[i].data;
    655             if ((entvalue & entmask) != entdata) {
    656                 continue;
    657             }
    658             if (rep_st->flags & BCM_L2_REPLACE_MATCH_MAC) {
    659                 if (ENET_CMP_MACADDR(rep_st->key_mac, ppa_info[i].mac)) {
    660                     continue;
    661                 }
    662             }
    663             nmatches += 1;
    664 
    665             /* lookup the matched entry */
    666             sal_memset(&l2entry, 0, sizeof(l2entry));
    667             soc_mem_field32_set(unit, mem, &l2entry, VLAN_IDf,
    668                                 (entvalue >> 16) & 0xfff);
    669             soc_mem_mac_addr_set(unit, mem, &l2entry, MAC_ADDRf,
    670                                  ppa_info[i].mac);
    671 
    672             /* operate on matched entry */
    673             if (rep_st->flags & BCM_L2_REPLACE_DELETE) {
    674                 int             mb_index;
    675 
    676                 /* coverity[value_overwrite] */
    677                 rv = soc_mem_generic_delete(unit, mem, MEM_BLOCK_ANY, 0,
    678                                             &l2entry, &l2entry, NULL);
    679                 if (rv < 0) {
    680                     soc_mem_unlock(unit, mem);
    681                     return rv;
    682                 }
    683                 if (!SOC_CONTROL(unit)->l2x_group_enable) {
    684                     mb_index = soc_mem_field32_get(unit, mem, &l2entry,
    685                                                    MAC_BLOCK_INDEXf);
    686                     _bcm_mac_block_delete(unit, mb_index);
    687                 }
    688                 if (entvalue & _SOC_TR_L2E_LIMIT_COUNTED) {
    689                     /* coverity[returned_value] */
    690                     rv = soc_triumph_learn_count_update(unit, &l2entry,
    691                                                         TRUE, -1);
    692                 }
    693             } else {
    694                 /* replace destination fields */
    695                 /* coverity[value_overwrite] */
    696                 rv = soc_mem_generic_lookup(unit, mem, MEM_BLOCK_ANY, 0,
    697                                             &l2entry, &l2entry, NULL);
    698                 if (rep_st->flags & BCM_L2_REPLACE_NEW_TRUNK) {
    699                     newdata = _SOC_TR_L2E_T |
    700                         ((rep_st->new_dest.trunk & _SOC_TR_L2E_TRUNK_MASK) <<
    701                          _SOC_TR_L2E_TRUNK_SHIFT);
    702                     newmask = _SOC_TR_L2E_T |
    703                         (_SOC_TR_L2E_TRUNK_MASK << _SOC_TR_L2E_TRUNK_SHIFT);
    704                     soc_mem_field32_set(unit, mem, &l2entry, Tf, 1);
    705                     soc_mem_field32_set(unit, mem, &l2entry, TGIDf,
    706                                         rep_st->new_dest.trunk);
    707                 } else {
    708                     newdata =
    709                         (rep_st->new_dest.module << _SOC_TR_L2E_MOD_SHIFT) |
    710                         (rep_st->new_dest.port << _SOC_TR_L2E_PORT_SHIFT);
    711                     newmask = _SOC_TR_L2E_T |
    712                         (_SOC_TR_L2E_MOD_MASK << _SOC_TR_L2E_MOD_SHIFT) |
    713                         (_SOC_TR_L2E_PORT_MASK << _SOC_TR_L2E_PORT_SHIFT);
    714                     soc_mem_field32_set(unit, mem, &l2entry, MODULE_IDf,
    715                                         rep_st->new_dest.module);
    716                     soc_mem_field32_set(unit, mem, &l2entry, PORT_NUMf,
    717                                         rep_st->new_dest.port);
    718                 }
    719                 same_dest = !((entvalue ^ newdata) & newmask);
    720 
    721                 if ((entvalue & _SOC_TR_L2E_LIMIT_COUNTED) && !same_dest) {
    722                     rv = soc_triumph_learn_count_update(unit, &l2entry, FALSE,
    723                                                         1);
    724                     if (SOC_FAILURE(rv)) {
    725                         soc_mem_unlock(unit, mem);
    726                         return rv;
    727                     }
    728                 }
    729 
    730                 /* re-insert entry */
    731                 rv = soc_mem_generic_insert(unit, mem, MEM_BLOCK_ANY, 0,
    732                                             &l2entry, &old_l2entry, NULL);
    733                 if (rv == BCM_E_EXISTS) {
    734                     rv = BCM_E_NONE;
    735                 }
    736                 if (rv < 0) {
    737                     soc_mem_unlock(unit, mem);
    738                     return rv;
    739                 }
    740                 if ((entvalue & _SOC_TR_L2E_LIMIT_COUNTED) && !same_dest) {
    741                     rv = soc_triumph_learn_count_update(unit, &old_l2entry,
    742                                                         FALSE, -1);
    743                     if (SOC_FAILURE(rv)) {
    744                         soc_mem_unlock(unit, mem);
    745                         return rv;
    746                     }
    747                 }
    748             }
    749         }
    750         soc_mem_unlock(unit, EXT_L2_ENTRYm);
    751     }
    752     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    753                 (BSL_META_U(unit,
    754                             "tr_l2e_ppa_match: imin=%d imax=%d nmatches=%d flags=0x%x\n"),
    755                  imin, imax, nmatches, rep_st->flags));
    756     return BCM_E_NONE;
    757 }
    758 #endif /* BCM_TRIUMPH_SUPPORT */
    759 
    760 /*
    761  * Function:
    762  *      _bcm_l2_hash_dynamic_replace
    763  * Purpose:
    764  *      Replace dynamic L2 entries in a dual hash.
    765  * Parameters:
    766  *      unit - Unit number
    767  *      l2x_entry - Entry to insert instead of dynamic entry.
    768  * Returns:
    769  *      BCM_E_NONE              Success
    770  *      BCM_E_XXX          		Error 
    771  */
    772 
    773 int _bcm_l2_hash_dynamic_replace(int unit, l2x_entry_t *l2x_entry)
    774 {
    775     l2x_entry_t     l2ent;
    776     int             rv;
    777     uint32          fval;
    778     bcm_mac_t       mac;
    779     int             cf_hit, cf_unhit;
    780     int             bank, bucket, slot, index;
    781     int             num_banks;
    782     int             entries_per_bank, entries_per_row, entries_per_bucket;
    783     int             bank_base, bucket_offset;
    784 
    785 
    786     
    787     BCM_IF_ERROR_RETURN(soc_trident2_hash_bank_count_get(unit, L2Xm, &num_banks));
    788 
    789     BCM_IF_ERROR_RETURN(soc_l2x_freeze(unit));
    790 
    791     cf_hit = cf_unhit = -1;
    792     for (bank = 0; bank < num_banks; bank++) {
    793         {
    794             
    795             rv = soc_trident2_hash_bank_info_get(unit, L2Xm, bank,
    796                                                  &entries_per_bank,
    797                                                  &entries_per_row,
    798                                                  &entries_per_bucket,
    799                                                  &bank_base, &bucket_offset);
    800             if (SOC_FAILURE(rv)) {
    801                 (void)soc_l2x_thaw(unit);
    802                 return rv;
    803             }
    804             bucket = soc_td2_l2x_bank_entry_hash(unit, bank,
    805                                                  (uint32 *)l2x_entry);
    806         }
    807 
    808 
    809         for (slot = 0; slot < entries_per_bucket; slot++) {
    810             uint32 valid = 0;
    811             index = bank_base + bucket * entries_per_row + bucket_offset +
    812                 slot;
    813             rv = soc_mem_read(unit, L2Xm, MEM_BLOCK_ANY, index, &l2ent);
    814             if (SOC_FAILURE(rv)) {
    815                 (void)soc_l2x_thaw(unit);
    816                 return rv;
    817             }
    818 
    819             if (soc_feature(unit, soc_feature_base_valid)) {
    820                 valid = soc_L2Xm_field32_get(unit, &l2ent, BASE_VALIDf);
    821             } else {
    822                 valid = soc_L2Xm_field32_get(unit, &l2ent, VALIDf);
    823             }
    824             if (!valid) {
    825                 /* Found invalid entry - stop the search victim found */
    826                 cf_unhit = index; 
    827                 break;
    828             }
    829 
    830             fval = soc_mem_field32_get(unit, L2Xm, &l2ent, KEY_TYPEf);
    831 #ifdef BCM_TRIDENT2_SUPPORT
    832             if (SOC_IS_TD2_TT2(unit)) {
    833                 if (fval != TD2_L2_HASH_KEY_TYPE_BRIDGE &&
    834                     fval != TD2_L2_HASH_KEY_TYPE_VFI) {
    835                     continue;
    836                 }
    837             } else
    838 #endif /* BCM_TRIDENT2_SUPPORT */
    839             if (fval != TR_L2_HASH_KEY_TYPE_BRIDGE &&
    840                 fval != TR_L2_HASH_KEY_TYPE_VFI) {
    841                 continue;
    842             }
    843 
    844             soc_L2Xm_mac_addr_get(unit, &l2ent, MAC_ADDRf, mac);
    845             /* Skip static entries */
    846             if ((soc_L2Xm_field32_get(unit, &l2ent, STATIC_BITf)) ||
    847                 (BCM_MAC_IS_MCAST(mac)) ||
    848                 (soc_mem_field_valid(unit, L2Xm, L3f) && 
    849                  soc_L2Xm_field32_get(unit, &l2ent, L3f))) {
    850                 continue;
    851             }
    852 
    853             if (soc_L2Xm_field32_get(unit, &l2ent, HITDAf) || 
    854                 soc_L2Xm_field32_get(unit, &l2ent, HITSAf) ) {
    855                 cf_hit =  index;
    856             } else {
    857                 /* Found unhit entry - stop search victim found */
    858                 cf_unhit = index;
    859                 break;
    860             }
    861         }
    862         if (cf_unhit != -1) {
    863             break;
    864         }
    865     }
    866 
    867     COMPILER_REFERENCE(entries_per_bank);
    868 
    869     if (cf_unhit >= 0) {
    870         index = cf_unhit;   /* take last unhit dynamic */
    871     } else if (cf_hit >= 0) {
    872         index = cf_hit;     /* or last hit dynamic */
    873     } else {
    874         rv = BCM_E_FULL;     /* no dynamics to delete */
    875         (void) soc_l2x_thaw(unit);
    876          return rv;
    877     }
    878 
    879     rv = soc_mem_delete_index(unit, L2Xm, MEM_BLOCK_ALL, index);
    880     if (SOC_SUCCESS(rv)) {
    881         rv = soc_mem_generic_insert(unit, L2Xm, MEM_BLOCK_ANY, 0,
    882                                     l2x_entry, NULL, NULL);
    883     }
    884     if (SOC_FAILURE(rv)) {
    885         (void) soc_l2x_thaw(unit);
    886         return rv;
    887     }
    888 
    889     return soc_l2x_thaw(unit);
    890 }
    891 
    892 /*
    893  * Function:
    894  *      bcm_bfd_l2_hash_dynamic_replace
    895  * Purpose:
    896  *      Replace dynamic L2 entries in a dual hash.
    897  * Parameters:
    898  *      unit - Unit number
    899  *      l2x_entry - Entry to insert instead of dynamic entry.
    900  * Returns:
    901  *      BCM_E_NONE              Success
    902  *      BCM_E_XXX               Error
    903  */
    904 
    905 int bcm_bfd_l2_hash_dynamic_replace(int unit, l2x_entry_t *l2x_entry)
    906 {
    907     int rv;
    908 
    909 #if defined(BCM_TRIUMPH3_SUPPORT)
    910     if (SOC_IS_TRIUMPH3(unit)) {
    911         rv = bcm_tr3_bfd_l2_hash_dynamic_replace(unit, (void *)l2x_entry);
    912     } else
    913 #endif /* BCM_TRIUMPH3_SUPPORT */
    914     {
    915         rv = _bcm_l2_hash_dynamic_replace(unit, l2x_entry);
    916     }
    917 
    918     return rv;
    919 }
    920 
    921 #endif
    922 
    923 #if defined(BCM_TRIDENT2_SUPPORT)
    924 /*
    925  * Function:
    926  *      _bcm_th3_l2_hit_retrieve
    927  * Purpose:
    928  *      Retrieve the hit bit from both x and y pipe, then "or" the hitbit values and assign it to 
    929  *      L2_ENTRY data structure.
    930  * Parameters:
    931  *      unit        Unit number
    932  *      l2addr      (OUT) L2 API data structure
    933  *      l2x_entry   L2X entry
    934  *      l2_hw_index   L2X entry hardware index
    935  */
    936 int
    937 _bcm_th3_l2_hit_retrieve(int unit, l2x_entry_t *l2x_entry,
    938                                  int l2_hw_index)
    939 { 
    940     uint32 hit_sa, hit_da, hit_local_sa;          /* composite hit = hit_x|hit_y */    
    941     int idx_offset, hit_idx_shift;
    942     l2_hitsa_only_x_entry_t hit_sa_x;
    943     l2_hitsa_only_y_entry_t hit_sa_y;
    944     l2_hitda_only_x_entry_t hit_da_x;
    945     l2_hitda_only_y_entry_t hit_da_y;  
    946     soc_field_t hit_saf[] = { HITSA_0f, HITSA_1f, HITSA_2f, HITSA_3f};
    947     soc_field_t hit_daf[] = { HITDA_0f, HITDA_1f, HITDA_2f, HITDA_3f};   
    948     soc_field_t hit_local_saf[] = { LOCAL_SA_0f, LOCAL_SA_1f, 
    949                                     LOCAL_SA_2f, LOCAL_SA_3f};     
    950 
    951     idx_offset = (l2_hw_index & 0x3);
    952     hit_idx_shift = 2;
    953 
    954     /* Retrieve DA HIT */
    955     BCM_IF_ERROR_RETURN(
    956         BCM_XGS3_MEM_READ(unit, L2_HITDA_ONLY_Xm,
    957           (l2_hw_index >> hit_idx_shift), &hit_da_x));
    958     
    959     BCM_IF_ERROR_RETURN(
    960         BCM_XGS3_MEM_READ(unit, L2_HITDA_ONLY_Ym,
    961           (l2_hw_index >> hit_idx_shift), &hit_da_y)); 
    962 
    963     hit_da = 0;
    964     hit_da |= soc_mem_field32_get(unit, L2_HITDA_ONLY_Xm,
    965                                    &hit_da_x, hit_daf[idx_offset]);
    966     
    967     hit_da |= soc_mem_field32_get(unit, L2_HITDA_ONLY_Ym,
    968                                    &hit_da_y, hit_daf[idx_offset]);
    969     
    970     _BCM_L2X_MEMACC_FIELD32_SET(unit, l2x_entry, HITDA_f, hit_da);  
    971 
    972     /* Retrieve SA HIT */
    973     BCM_IF_ERROR_RETURN(
    974         BCM_XGS3_MEM_READ(unit, L2_HITSA_ONLY_Xm,
    975           (l2_hw_index >> hit_idx_shift), &hit_sa_x));
    976     
    977     BCM_IF_ERROR_RETURN(
    978         BCM_XGS3_MEM_READ(unit, L2_HITSA_ONLY_Ym,
    979           (l2_hw_index >> hit_idx_shift), &hit_sa_y)); 
    980 
    981     hit_sa = 0;
    982     hit_sa |= soc_mem_field32_get(unit, L2_HITSA_ONLY_Xm,
    983                                    &hit_sa_x, hit_saf[idx_offset]);
    984     
    985     hit_sa |= soc_mem_field32_get(unit, L2_HITSA_ONLY_Ym,
    986                                    &hit_sa_y, hit_saf[idx_offset]);
    987     
    988     _BCM_L2X_MEMACC_FIELD32_SET(unit, l2x_entry, HITSA_f, hit_sa);        
    989     
    990     /* Retrieve LOCAL_SA HIT */
    991     hit_local_sa = 0;
    992     hit_local_sa |= soc_mem_field32_get(unit, L2_HITSA_ONLY_Xm,
    993                                    &hit_sa_x, hit_local_saf[idx_offset]);
    994     
    995     hit_local_sa |= soc_mem_field32_get(unit, L2_HITSA_ONLY_Ym,
    996                                    &hit_sa_y, hit_local_saf[idx_offset]);
    997     
    998     _BCM_L2X_MEMACC_FIELD32_SET(unit, l2x_entry, LOCAL_SA_f, hit_local_sa);        
    999     
   1000     return BCM_E_NONE;    
   1001 }
   1002 
   1003 #endif /* BCM_TRIDENT2_SUPPORT */
   1004 
   1005 
   1006 #if 0
   1007 /*
   1008  * Function:
   1009  *      bcm_tr_l2_addr_add
   1010  * Description:
   1011  *      Add a MAC address to the Switch Address Resolution Logic (ARL)
   1012  *      port with the given VLAN ID and parameters.
   1013  * Parameters:
   1014  *      unit - StrataSwitch PCI device unit number (driver internal).
   1015  *      l2addr - Pointer to bcm_l2_addr_t containing all valid fields
   1016  * Returns:
   1017  *      BCM_E_NONE              Success
   1018  *      BCM_E_INTERNAL          Chip access failure
   1019  *      BCM_E_RESOURCE          No MAC_BLOCK entries available
   1020  * Notes:
   1021  *      Use CMIC_PORT(unit) to associate the entry with the CPU.
   1022  *      Use flag of BCM_L2_COPY_TO_CPU to send a copy to the CPU.
   1023  *      Use flag of BCM_L2_TRUNK_MEMBER to set trunking (TGID must be
   1024  *      passed as well with non-zero trunk group ID)
   1025  *      In case the L2X table is full (e.g. bucket full), an attempt
   1026  *      will be made to store the entry in the L2_USER_ENTRY table.
   1027  */
   1028 int
   1029 bcm_tr_l2_addr_add(int unit, bcm_l2_addr_t *l2addr)
   1030 {
   1031     l2x_entry_t  l2x_entry, l2x_lookup;
   1032 #ifdef BCM_TRIUMPH_SUPPORT
   1033     _soc_tr_l2e_ppa_info_t *ppa_info = NULL;
   1034     ext_l2_entry_entry_t ext_l2_entry, ext_l2_lookup;
   1035     int          exist_in_ext_l2 =0, limit_counted;
   1036     int          rv1, ext_l2_index;
   1037 #endif /* BCM_TRIUMPH_SUPPORT */
   1038     int          enable_ppa_war;
   1039     int          rv, l2_index, mb_index = 0;
   1040 
   1041 #ifdef BCM_TRIDENT_SUPPORT
   1042     if (SOC_IS_TRIDENT(unit) || SOC_IS_KATANAX(unit) ||
   1043          SOC_IS_TD2_TT2(unit)) {       
   1044         if (soc_mem_is_valid(unit, MY_STATION_TCAMm) &&
   1045             (l2addr->flags & BCM_L2_L3LOOKUP)) {
   1046             BCM_IF_ERROR_RETURN(bcm_td_l2_myStation_add(unit, l2addr));
   1047         }
   1048         else if (soc_mem_is_valid(unit, MY_STATION_TCAMm) &&
   1049                 !(l2addr->flags & BCM_L2_L3LOOKUP)) {
   1050             /* If VPN specified do not perform myStation delete */
   1051             if (!_BCM_VPN_VFI_IS_SET(l2addr->vid)) {
   1052                 rv = bcm_td_l2_myStation_delete(unit, 
   1053                             l2addr->mac, l2addr->vid, &l2_index);
   1054                 if (rv != BCM_E_NONE && rv != BCM_E_NOT_FOUND) {
   1055                     return rv;
   1056                 }
   1057             }
   1058         }
   1059     }
   1060 #endif /* BCM_TRIDENT_SUPPORT */
   1061 
   1062     BCM_IF_ERROR_RETURN(_bcm_tr_l2_to_l2x(unit, &l2x_entry, l2addr, FALSE));
   1063 
   1064     rv = soc_mem_generic_lookup(unit, L2Xm, MEM_BLOCK_ANY, 0, &l2x_entry,
   1065                                 &l2x_lookup, &l2_index);
   1066     if (BCM_FAILURE(rv) && rv != BCM_E_NOT_FOUND) {
   1067         return rv;
   1068     }
   1069 
   1070     if (!SOC_CONTROL(unit)->l2x_group_enable) {
   1071         /* Mac blocking, attempt to associate with bitmap entry */
   1072         BCM_IF_ERROR_RETURN
   1073             (_bcm_mac_block_insert(unit, l2addr->block_bitmap, &mb_index));
   1074         soc_mem_field32_set(unit, L2Xm, &l2x_entry, MAC_BLOCK_INDEXf,
   1075                             mb_index);
   1076     }
   1077 
   1078     enable_ppa_war = FALSE;
   1079     if (SOC_CONTROL(unit)->l2x_ppa_bypass == FALSE &&
   1080         soc_feature(unit, soc_feature_ppa_bypass) &&
   1081         soc_mem_field32_get(unit, L2Xm, &l2x_entry, KEY_TYPEf) !=
   1082         TR_L2_HASH_KEY_TYPE_BRIDGE) {
   1083         enable_ppa_war = TRUE;
   1084     }
   1085 
   1086     rv = soc_mem_insert_return_old(unit, L2Xm, MEM_BLOCK_ANY, 
   1087                                    (void *)&l2x_entry, NULL);
   1088     if ((rv == BCM_E_FULL) && (l2addr->flags & BCM_L2_REPLACE_DYNAMIC)) {
   1089         rv = _bcm_l2_hash_dynamic_replace( unit, &l2x_entry);
   1090         if (rv < 0 ) {
   1091             goto done;
   1092         }
   1093     } else if (rv == BCM_E_EXISTS) {
   1094         if (!SOC_CONTROL(unit)->l2x_group_enable) {
   1095             mb_index = soc_mem_field32_get(unit, L2Xm, &l2x_lookup,
   1096                                            MAC_BLOCK_INDEXf);
   1097             _bcm_mac_block_delete(unit, mb_index);
   1098         }
   1099         rv = BCM_E_NONE;
   1100     }
   1101 
   1102     if (BCM_SUCCESS(rv) && enable_ppa_war) {
   1103         SOC_CONTROL(unit)->l2x_ppa_bypass = TRUE;
   1104     }
   1105 
   1106 #ifdef BCM_TRIUMPH_SUPPORT
   1107     if (SOC_SUCCESS(rv)) {
   1108         if (exist_in_ext_l2) {
   1109             soc_mem_lock(unit, EXT_L2_ENTRYm);
   1110             limit_counted =
   1111                 ppa_info[ext_l2_index].data & _SOC_TR_L2E_LIMIT_COUNTED;
   1112             rv1 = soc_mem_generic_delete(unit, EXT_L2_ENTRYm, MEM_BLOCK_ANY,
   1113                                          0, &ext_l2_entry, &ext_l2_lookup,
   1114                                          &ext_l2_index);
   1115             if (SOC_SUCCESS(rv1)) {
   1116                 if (!SOC_CONTROL(unit)->l2x_group_enable) {
   1117                     mb_index =
   1118                         soc_mem_field32_get(unit, EXT_L2_ENTRYm,
   1119                                             &ext_l2_lookup, MAC_BLOCK_INDEXf);
   1120                     _bcm_mac_block_delete(unit, mb_index);
   1121                 }
   1122                 if (limit_counted) {
   1123                     (void)soc_triumph_learn_count_update(unit, &ext_l2_lookup,
   1124                                                          TRUE, -1);
   1125                 }
   1126             }
   1127             soc_mem_unlock(unit, EXT_L2_ENTRYm);
   1128         }
   1129     }
   1130 #endif
   1131 
   1132 done:
   1133     if (rv < 0) {
   1134         _bcm_mac_block_delete(unit, mb_index);
   1135     }
   1136 
   1137     return rv;
   1138 }
   1139 
   1140 /*
   1141  * Function:
   1142  *      bcm_tr_l2_addr_delete
   1143  * Description:
   1144  *      Delete an L2 address (MAC+VLAN) from the device
   1145  * Parameters:
   1146  *      unit - device unit
   1147  *      mac  - MAC address to delete
   1148  *      vid  - VLAN id
   1149  * Returns:
   1150  *      BCM_E_XXX
   1151  */
   1152 int
   1153 bcm_tr_l2_addr_delete(int unit, bcm_mac_t mac, bcm_vlan_t vid)
   1154 {
   1155     bcm_l2_addr_t  l2addr;
   1156     l2x_entry_t    l2x_entry, l2x_lookup;
   1157     int            l2_index, mb_index;
   1158     int            rv;
   1159     soc_control_t  *soc = SOC_CONTROL(unit);
   1160 
   1161     bcm_l2_addr_t_init(&l2addr, mac, vid);
   1162 
   1163 #ifdef BCM_TRIDENT_SUPPORT
   1164     if (SOC_IS_TRIDENT(unit) || (SOC_IS_KATANAX(unit)) ||
   1165         SOC_IS_TD2_TT2(unit)) {
   1166         if (soc_mem_is_valid(unit, MY_STATION_TCAMm) && BCM_VLAN_VALID(vid)) {
   1167               rv = bcm_td_l2_myStation_delete (unit, mac, vid, &l2_index);
   1168             if ((rv != BCM_E_NOT_FOUND) && (rv != BCM_E_FULL)) {
   1169                    if (rv != BCM_E_NONE) {
   1170                         return rv;
   1171                    }
   1172               }
   1173          }
   1174     }
   1175 #endif /* BCM_TRIDENT_SUPPORT */
   1176 
   1177     BCM_IF_ERROR_RETURN(_bcm_tr_l2_to_l2x(unit, &l2x_entry, &l2addr, TRUE));
   1178 
   1179     soc_mem_lock(unit, L2Xm);
   1180 
   1181     rv = soc_mem_search(unit, L2Xm, MEM_BLOCK_ANY, &l2_index,
   1182                        (void *)&l2x_entry, (void *)&l2x_lookup, 0);
   1183     if (BCM_E_NONE != rv) {
   1184         soc_mem_unlock(unit, L2Xm);
   1185         return rv;
   1186     }
   1187 
   1188     if (!SOC_CONTROL(unit)->l2x_group_enable) {
   1189         mb_index = soc_L2Xm_field32_get(unit, &l2x_lookup, MAC_BLOCK_INDEXf);
   1190         _bcm_mac_block_delete(unit, mb_index);
   1191     }
   1192 
   1193     if (SOC_L2_DEL_SYNC_LOCK(soc) < 0) {
   1194         soc_mem_unlock(unit, L2Xm);
   1195         return BCM_E_RESOURCE;
   1196     }
   1197     rv = soc_mem_delete_return_old(unit, L2Xm, MEM_BLOCK_ANY,
   1198                                    (void *)&l2x_entry, (void *)&l2x_entry);
   1199     if (rv >= 0) {
   1200         rv = soc_l2x_sync_delete(unit, (uint32 *) &l2x_lookup, l2_index, 0);
   1201     }
   1202     SOC_L2_DEL_SYNC_UNLOCK(soc);
   1203     soc_mem_unlock(unit, L2Xm);
   1204 
   1205     return rv;
   1206 }
   1207 
   1208 /*
   1209  * Function:
   1210  *      bcm_tr_l2_addr_get
   1211  * Description:
   1212  *      Given a MAC address and VLAN ID, check if the entry is present
   1213  *      in the L2 table, and if so, return all associated information.
   1214  * Parameters:
   1215  *      unit - Device unit number
   1216  *      mac - input MAC address to search
   1217  *      vid - input VLAN ID to search
   1218  *      check_l2_only - only check if the target exist in L2 table.
   1219  *      l2addr - Pointer to bcm_l2_addr_t structure to receive results
   1220  * Returns:
   1221  *      BCM_E_NONE              Success (l2addr filled in)
   1222  *      BCM_E_PARAM             Illegal parameter (NULL pointer)
   1223  *      BCM_E_INTERNAL          Chip access failure
   1224  *      BCM_E_NOT_FOUND Address not found (l2addr not filled in)
   1225  */
   1226 
   1227 int
   1228 _bcm_tr_l2_addr_get(int unit, sal_mac_addr_t mac, bcm_vlan_t vid,
   1229     int check_l2_only, bcm_l2_addr_t *l2addr)
   1230 {
   1231     bcm_l2_addr_t l2addr_key;
   1232     l2x_entry_t  l2x_entry, l2x_lookup;
   1233     int          l2_hw_index;
   1234     int          rv;
   1235 
   1236     bcm_l2_addr_t_init(&l2addr_key, mac, vid);
   1237 
   1238 #ifdef BCM_TRIDENT_SUPPORT
   1239     if (SOC_IS_TRIDENT(unit) || SOC_IS_KATANAX(unit) ||       
   1240         SOC_IS_TD2_TT2(unit)) {
   1241         if (soc_mem_is_valid(unit, MY_STATION_TCAMm) && (!check_l2_only)) {
   1242               rv = bcm_td_l2_myStation_get (unit, mac, vid, l2addr);
   1243               if (BCM_SUCCESS(rv)) {
   1244                    return rv;
   1245               }
   1246          }
   1247     }
   1248 #endif /* BCM_TRIDENT_SUPPORT */
   1249 
   1250     BCM_IF_ERROR_RETURN(
   1251         _bcm_tr_l2_to_l2x(unit, &l2x_entry, &l2addr_key, TRUE));
   1252 
   1253     soc_mem_lock(unit, L2Xm);
   1254 
   1255     rv = soc_mem_generic_lookup(unit, L2Xm, MEM_BLOCK_ANY, 0, &l2x_entry,
   1256                                 &l2x_lookup, &l2_hw_index);
   1257 
   1258     soc_mem_unlock(unit, L2Xm);
   1259 
   1260     if (check_l2_only) {
   1261         return rv;
   1262     }
   1263 
   1264     if (SOC_SUCCESS(rv)) {
   1265         /* Retrieve the hit bit for TD2/TT2 */
   1266 #ifdef BCM_TRIDENT2_SUPPORT
   1267         if (!SOC_IS_TOMAHAWK(unit) && !SOC_IS_APACHE(unit) &&
   1268             !SOC_IS_TRIDENT3(unit) &&
   1269                 SOC_IS_TD2_TT2(unit)) {
   1270             BCM_IF_ERROR_RETURN(
   1271                 _bcm_th3_l2_hit_retrieve(unit, &l2x_lookup, l2_hw_index));
   1272         }
   1273 #endif /* BCM_TRIDENT2_SUPPORT */
   1274         rv = _bcm_tr_l2_from_l2x(unit, l2addr, &l2x_lookup);
   1275     }
   1276 
   1277     return rv;
   1278 }
   1279 
   1280 int
   1281 bcm_tr_l2_addr_get(int unit, sal_mac_addr_t mac, bcm_vlan_t vid,
   1282                    bcm_l2_addr_t *l2addr)
   1283 {
   1284     return _bcm_tr_l2_addr_get(unit, mac, vid, FALSE, l2addr);
   1285 }
   1286 
   1287 #endif
   1288 
   1289 #ifdef BCM_WARM_BOOT_SUPPORT
   1290 /*
   1291  * Function:
   1292  *      _bcm_th3_l2_reload_mbi
   1293  * Description:
   1294  *      Load MAC block info from hardware into software data structures
   1295  * Parameters:
   1296  *      unit - StrataSwitch unit number
   1297  */
   1298 int
   1299 _bcm_th3_l2_reload_mbi(int unit)
   1300 {
   1301     _bcm_mac_block_info_t *mbi = _mbi_entries[unit];
   1302     l2x_entry_t         *l2x_entry, *l2x_table;
   1303     mac_block_entry_t   mbe;
   1304     int                 index, mb_index, l2x_size;
   1305     pbmp_t              mb_pbmp;
   1306 
   1307     /*
   1308      * Refresh MAC Block information from the hardware tables
   1309      */
   1310 
   1311     for (mb_index = 0; mb_index < _mbi_num[unit]; mb_index++) {
   1312         SOC_IF_ERROR_RETURN
   1313             (READ_MAC_BLOCKm(unit, MEM_BLOCK_ANY, mb_index, &mbe));
   1314 
   1315         SOC_PBMP_CLEAR(mb_pbmp);
   1316 
   1317         soc_mem_pbmp_field_set(unit, MAC_BLOCKm, &mbe, MAC_BLOCK_MASKf,
   1318                                &mb_pbmp); 
   1319 
   1320         BCM_PBMP_ASSIGN(mbi[mb_index].mb_pbmp, mb_pbmp);
   1321     }
   1322 
   1323     if (!SOC_CONTROL(unit)->l2x_group_enable) {
   1324         l2x_size = sizeof(l2x_entry_t) * soc_mem_index_count(unit, L2Xm);
   1325         l2x_table = soc_cm_salloc(unit, l2x_size, "l2 reload");
   1326         if (l2x_table == NULL) {
   1327             return BCM_E_MEMORY;
   1328         }
   1329 
   1330         memset((void *)l2x_table, 0, l2x_size);
   1331         if (soc_mem_read_range(unit, L2Xm, MEM_BLOCK_ANY,
   1332                                soc_mem_index_min(unit, L2Xm),
   1333                                soc_mem_index_max(unit, L2Xm),
   1334                                l2x_table) < 0) {
   1335             soc_cm_sfree(unit, l2x_table);
   1336             return SOC_E_INTERNAL;
   1337         }
   1338 
   1339         for (index = soc_mem_index_min(unit, L2Xm);
   1340              index <= soc_mem_index_max(unit, L2Xm); index++) {
   1341 
   1342              l2x_entry = soc_mem_table_idx_to_pointer(unit, L2Xm,
   1343                                                       l2x_entry_t *,
   1344                                                       l2x_table, index);
   1345 
   1346              if (!soc_L2Xm_field32_get(unit, l2x_entry, BASE_VALIDf)) {
   1347                  continue;
   1348              }
   1349   
   1350              mb_index = soc_L2Xm_field32_get(unit, l2x_entry, MAC_BLOCK_INDEXf);
   1351              mbi[mb_index].ref_count++;
   1352         }
   1353         soc_cm_sfree(unit, l2x_table);
   1354     }
   1355 
   1356     return BCM_E_NONE;
   1357 }
   1358 #endif /* BCM_WARM_BOOT_SUPPORT */
   1359 
   1360 /*
   1361  * Function:
   1362  *      _bcm_th3_l2x_delete_all
   1363  * Purpose:
   1364  *      Clear L2 table by invalidating entries
   1365  * Parameters:
   1366  *      unit - StrataSwitch unit #
   1367  * Returns:
   1368  *      SOC_E_XXX
   1369  */
   1370 
   1371 STATIC int
   1372 _bcm_th3_l2x_delete_all(int unit)
   1373 {
   1374     soc_control_t *soc = SOC_CONTROL(unit);
   1375     int copyno;
   1376     int index_min, index_max, index, mem_max;
   1377     l2_entry_only_single_entry_t *l2x_entry;
   1378     int rv = SOC_E_NONE;
   1379     int *buffer = NULL;
   1380     int mem_size, idx;
   1381     int modified;
   1382     uint32 key_type;
   1383 
   1384     index_min = soc_mem_index_min(unit, L2Xm);
   1385     mem_max = soc_mem_index_max(unit, L2Xm);
   1386     mem_size =  DEFAULT_L2DELETE_CHUNKS * sizeof(l2_entry_only_single_entry_t);
   1387     
   1388     buffer = soc_cm_salloc(unit, mem_size, "L2_ENTRY_ONLY_SINGLE_delete");
   1389     if (buffer == NULL) {
   1390         return SOC_E_MEMORY;
   1391     }
   1392 
   1393     /* Lock on aggregate entry */
   1394     soc_mem_lock(unit, L2Xm);
   1395     for (idx = index_min; idx < mem_max; idx += DEFAULT_L2DELETE_CHUNKS) {
   1396         index_max = idx + DEFAULT_L2DELETE_CHUNKS - 1;
   1397         if (index_max > mem_max) {
   1398             index_max = mem_max;
   1399         }
   1400 
   1401         if ((rv = soc_mem_read_range(unit, L2Xm, MEM_BLOCK_ALL,
   1402                                      idx, index_max, buffer)) < 0 ) {
   1403             soc_cm_sfree(unit, buffer);
   1404             soc_mem_unlock(unit, L2Xm);
   1405             return rv;
   1406         }
   1407 
   1408         modified = FALSE;
   1409         for (index = 0; index < DEFAULT_L2DELETE_CHUNKS; index++) {
   1410             l2x_entry =
   1411                 soc_mem_table_idx_to_pointer(unit, L2Xm,
   1412                                              l2_entry_only_single_entry_t *,
   1413                                              buffer, index);
   1414             if (!soc_L2Xm_field32_get(unit, l2x_entry, BASE_VALIDf)) {
   1415                 continue;
   1416             }
   1417 
   1418             key_type = soc_L2Xm_field32_get(unit, l2x_entry, KEY_TYPEf);
   1419             if (key_type == TH3_L2_HASH_KEY_TYPE_BRIDGE) {
   1420                 sal_memcpy(l2x_entry, soc_mem_entry_null(unit, L2Xm),
   1421                            sizeof(l2_entry_only_single_entry_t));
   1422                 modified = TRUE;
   1423             }
   1424         }
   1425 
   1426         if (!modified) {
   1427             continue;
   1428         }
   1429 
   1430         if ((rv = soc_mem_write_range(unit, L2Xm,
   1431                                       MEM_BLOCK_ALL, idx, index_max, buffer))
   1432                                       < 0) {
   1433             soc_cm_sfree(unit, buffer);
   1434             soc_mem_unlock(unit, L2Xm);
   1435             return rv;
   1436         }
   1437     }
   1438 
   1439     soc_cm_sfree(unit, buffer);
   1440 
   1441     /* Clear all shadow table entries */
   1442     if (soc->arlShadow != NULL) {
   1443         sal_mutex_take(soc->arlShadowMutex, sal_mutex_FOREVER);
   1444         (void) shr_avl_delete_all(soc->arlShadow);
   1445         sal_mutex_give(soc->arlShadowMutex);
   1446     }
   1447 
   1448     /* Free AVL table used for L2 learning */
   1449     if (soc->l2x_lrn_shadow != NULL) {
   1450         sal_mutex_take(soc->l2x_lrn_shadow_mutex, sal_mutex_FOREVER);
   1451         shr_avl_delete_all(soc->l2x_lrn_shadow);
   1452         sal_mutex_give(soc->l2x_lrn_shadow_mutex);
   1453     }
   1454 
   1455     copyno = SOC_MEM_BLOCK_ANY(unit, L2Xm);
   1456     if (SOC_MEM_BLOCK_VALID(unit, L2Xm, copyno)) {
   1457         SOP_MEM_STATE(unit, L2Xm).count[copyno] = 0;
   1458     }
   1459 
   1460     soc_mem_unlock(unit, L2Xm);
   1461 
   1462     return rv;
   1463 }
   1464 
   1465 
   1466 
   1467 /*
   1468  * Function:
   1469  *      bcm_th3_l2_init
   1470  * Description:
   1471  *      Initialize chip-dependent parts of L2 module
   1472  * Parameters:
   1473  *      unit - StrataSwitch unit number
   1474  */
   1475 
   1476 int
   1477 bcm_th3_l2_init(int unit)
   1478 {
   1479     int         rv, was_running = FALSE;
   1480     uint32      flags;
   1481     sal_usecs_t interval = 0;
   1482     sal_usecs_t lrn_interval;
   1483     int lrn_thread_running = FALSE;
   1484 
   1485     if (soc_l2x_running(unit, &flags, &interval)) {
   1486         was_running = TRUE;
   1487         BCM_IF_ERROR_RETURN(soc_l2x_stop(unit));
   1488     }
   1489 
   1490     if (soc_th3_l2_learn_thread_running(unit, &lrn_interval)) {
   1491         lrn_thread_running = TRUE;
   1492         BCM_IF_ERROR_RETURN(soc_th3_l2_learn_thread_stop(unit));
   1493     }
   1494 
   1495     if (!SOC_WARM_BOOT(unit) && !SOC_IS_RCPU_ONLY(unit)) {
   1496 
   1497         if (!(SAL_BOOT_QUICKTURN || 
   1498              ((SAL_BOOT_SIMULATION || SAL_BOOT_BCMSIM || SAL_BOOT_XGSSIM) &&
   1499               !SOC_IS_TOMAHAWKX(unit)))) {
   1500             _bcm_th3_l2x_delete_all(unit);
   1501         }
   1502     }
   1503 
   1504     if (_mbi_entries[unit] != NULL) {
   1505         sal_free(_mbi_entries[unit]);
   1506         _mbi_entries[unit] = NULL;
   1507     }
   1508 
   1509     _mbi_num[unit] = (SOC_MEM_INFO(unit, MAC_BLOCKm).index_max -
   1510                       SOC_MEM_INFO(unit, MAC_BLOCKm).index_min + 1);
   1511     _mbi_entries[unit] = sal_alloc(_mbi_num[unit] *
   1512                                    sizeof(_bcm_mac_block_info_t),
   1513                                    "BCM L2X MAC blocking info");
   1514     if (!_mbi_entries[unit]) {
   1515         return BCM_E_MEMORY;
   1516     }
   1517     sal_memset(_mbi_entries[unit], 0, _mbi_num[unit] * sizeof(_bcm_mac_block_info_t));
   1518 
   1519     BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_init(unit));
   1520 
   1521 #ifdef BCM_WARM_BOOT_SUPPORT
   1522     if (SOC_WARM_BOOT(unit)) {
   1523         BCM_IF_ERROR_RETURN(_bcm_th3_l2_reload_mbi(unit));
   1524 
   1525 #if defined(BCM_TRIUMPH_SUPPORT)
   1526         BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_reload(unit));
   1527 #endif
   1528     }
   1529 #endif
   1530 
   1531     BCM_IF_ERROR_RETURN(_bcm_l2_match_ctrl_init(unit));
   1532 
   1533     rv = _bcm_th3_l2_memacc_init(unit);
   1534     if (BCM_FAILURE(rv)) {
   1535         _bcm_l2_match_ctrl_deinit(unit);
   1536         return rv;
   1537     }
   1538 
   1539     /* bcm_l2_register clients */
   1540     soc_l2x_register(unit, _bcm_th3_l2_register_callback, NULL);
   1541 
   1542     if (was_running) {
   1543         /* Use value saved in soc_control[]. Original code running on
   1544          * bcmsim sets it back to default value
   1545          * 'interval' should be non-0 if the task was running originally
   1546          */
   1547         soc_l2x_start(unit, flags, interval);
   1548     }
   1549 
   1550     if (lrn_thread_running) {
   1551         /* Use value saved in soc_control[], no point setting it back to
   1552          * default value
   1553          * 'lrn_interval' should be non-0 if the task was running originally
   1554          */
   1555         soc_th3_l2_learn_thread_start(unit, lrn_interval);
   1556     }
   1557 
   1558     return BCM_E_NONE;
   1559 }
   1560 
   1561 /*
   1562  * Function:
   1563  *      bcm_th3_l2_term
   1564  * Description:
   1565  *      Finalize chip-dependent parts of L2 module
   1566  * Parameters:
   1567  *      unit - StrataSwitch unit number.
   1568  */
   1569 
   1570 int
   1571 bcm_th3_l2_term(int unit)
   1572 {
   1573     if (_mbi_entries[unit] != NULL) {
   1574         sal_free(_mbi_entries[unit]);
   1575         _mbi_entries[unit] = NULL;
   1576     }
   1577 
   1578     BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_deinit(unit));
   1579 
   1580     /* Free resources allocated for match control data */
   1581     _bcm_l2_match_ctrl_deinit(unit);
   1582 
   1583     BCM_IF_ERROR_RETURN(_bcm_th3_l2_memacc_deinit(unit));
   1584 
   1585     return BCM_E_NONE;
   1586 }
   1587 
   1588 STATIC int
   1589 _bcm_th3_dual_l2_conflict_get(int unit, bcm_l2_addr_t *addr,
   1590                               bcm_l2_addr_t *cf_array, int cf_max,
   1591                               int *cf_count)
   1592 {
   1593     l2x_entry_t     match_entry, entry;
   1594     uint32          fval;
   1595     int             bank, bucket, slot, index;
   1596     int             num_banks;
   1597     int             entries_per_bank, entries_per_row, entries_per_bucket;
   1598     int             bank_base, bucket_offset;
   1599 
   1600 
   1601     BCM_IF_ERROR_RETURN(soc_tomahawk3_hash_bank_count_get(unit, L2Xm,
   1602                                                               &num_banks));
   1603 
   1604     *cf_count = 0;
   1605 
   1606     BCM_IF_ERROR_RETURN(_bcm_th3_l2_to_l2x(unit, &match_entry, addr, TRUE));
   1607     for (bank = 0; bank < num_banks; bank++) {
   1608 
   1609         BCM_IF_ERROR_RETURN(soc_tomahawk3_hash_bank_info_get(unit,
   1610                                 L2Xm,
   1611                                 bank,
   1612                                 &entries_per_bank,
   1613                                 &entries_per_row,
   1614                                 &entries_per_bucket,
   1615                                 &bank_base, &bucket_offset));
   1616 
   1617         bucket = soc_tomahawk3_l2x_bank_entry_hash(unit, bank,
   1618                                             (uint32 *)&match_entry);
   1619 
   1620         for (slot = 0; slot < entries_per_bucket; slot++) {
   1621             index = bank_base + bucket * entries_per_row + bucket_offset +
   1622                 slot;
   1623 
   1624             LOG_DEBUG(BSL_LS_BCM_L2,
   1625                       (BSL_META_U(unit,
   1626                       "bucket=%d, index=%d) \n"), bucket, index));
   1627 
   1628             SOC_IF_ERROR_RETURN(soc_mem_read(unit, L2Xm, MEM_BLOCK_ANY, index,
   1629                                              &entry));
   1630 
   1631             if (!soc_L2Xm_field32_get(unit, &entry, BASE_VALIDf)) {
   1632                 continue;
   1633             }
   1634 
   1635             fval = soc_mem_field32_get(unit, L2Xm, &entry, KEY_TYPEf);
   1636 
   1637             if (fval != TH3_L2_HASH_KEY_TYPE_BRIDGE) {
   1638                 continue;
   1639             }
   1640 
   1641             BCM_IF_ERROR_RETURN(_bcm_th3_l2_from_l2x(unit,
   1642                                     &cf_array[*cf_count],
   1643                                     &entry));
   1644 
   1645             *cf_count += 1;
   1646             if (*cf_count >= cf_max) {
   1647                 return BCM_E_NONE;
   1648             }
   1649         }
   1650     }
   1651 
   1652     COMPILER_REFERENCE(entries_per_bank);
   1653 
   1654     return BCM_E_NONE;
   1655 }
   1656 
   1657 int
   1658 bcm_th3_l2_conflict_get(int unit, bcm_l2_addr_t *addr, bcm_l2_addr_t *cf_array,
   1659                         int cf_max, int *cf_count)
   1660 {
   1661 
   1662     if (soc_feature(unit, soc_feature_dual_hash)) {
   1663         return _bcm_th3_dual_l2_conflict_get(unit, addr, cf_array,
   1664                                              cf_max, cf_count);
   1665     }
   1666 
   1667     return BCM_E_UNAVAIL;
   1668 }
   1669 
   1670 #ifdef BCM_WARM_BOOT_SUPPORT_SW_DUMP
   1671 /*
   1672  * Function:
   1673  *     _bcm_th3_l2_sw_dump
   1674  * Purpose:
   1675  *     Displays L2 information maintained by software.
   1676  * Parameters:
   1677  *     unit - Device unit number
   1678  * Returns:
   1679  *     None
   1680  */
   1681 void
   1682 _bcm_th3_l2_sw_dump(int unit)
   1683 {
   1684     _bcm_mac_block_info_t *mbi;
   1685      char                 pfmt[SOC_PBMP_FMT_LEN];
   1686      int                  i;
   1687 
   1688     LOG_CLI((BSL_META_U(unit,
   1689                         "\n")));
   1690     LOG_CLI((BSL_META_U(unit,
   1691                         "  TR L2 MAC Blocking Info -\n")));
   1692     LOG_CLI((BSL_META_U(unit,
   1693                         "      Number : %d\n"), _mbi_num[unit]));
   1694 
   1695     mbi = _mbi_entries[unit];
   1696     LOG_CLI((BSL_META_U(unit,
   1697                         "      Entries (index: pbmp-count) :\n")));
   1698     if (mbi != NULL) {
   1699         for (i = 0; i < _mbi_num[unit]; i++) {
   1700             SOC_PBMP_FMT(mbi[i].mb_pbmp, pfmt);
   1701             LOG_CLI((BSL_META_U(unit,
   1702                                 "          %5d: %s-%d\n"), i, pfmt, mbi[i].ref_count));
   1703         }
   1704     }
   1705     LOG_CLI((BSL_META_U(unit,
   1706                         "\n")));
   1707 
   1708     LOG_CLI((BSL_META_U(unit,
   1709                         "\n  TR L2 PPA bypass - %s\n"),
   1710              SOC_CONTROL(unit)->l2x_ppa_bypass ? "TRUE" : "FALSE"));
   1711     return;
   1712 }
   1713 #endif /* BCM_WARM_BOOT_SUPPORT_SW_DUMP */
   1714 
   1715 /*
   1716  * Function:
   1717  *	_bcm_th3_l2_gport_parse
   1718  * Description:
   1719  *	Parse gport in the l2 table
   1720  * Parameters:
   1721  *	unit -      [IN] StrataSwitch PCI device unit number (driver internal).
   1722  *  l2addr -    [IN/OUT] l2 addr structure to parse and fill
   1723  *  sub_port -  [OUT] Virtual port group (-1 if not supported)
   1724  *  mpls_port - [OUT] MPLS port (-1 if not supported)
   1725  * Returns:
   1726  *	BCM_E_XXX
   1727  */
   1728 int
   1729 _bcm_th3_l2_gport_parse(int unit, bcm_l2_addr_t *l2addr,
   1730                         _bcm_l2_gport_params_t *params)
   1731 {
   1732     int             id;
   1733     bcm_port_t      _port;
   1734     bcm_trunk_t     _trunk;
   1735     bcm_module_t    _modid, _mymodid;
   1736 
   1737     if ((NULL == l2addr) || (NULL == params)){
   1738         return BCM_E_PARAM;
   1739     }
   1740 
   1741     params->param0 = -1;
   1742     params->param1 = -1;
   1743     params->type = 0;
   1744 
   1745     
   1746     BCM_IF_ERROR_RETURN(
   1747         _bcm_esw_gport_resolve(unit, l2addr->port, &_modid, &_port,
   1748                                &_trunk, &id));
   1749 
   1750     _mymodid = 0;
   1751 
   1752     if ((BCM_TRUNK_INVALID != _trunk) && (-1 == id)) {
   1753         params->param0 = _trunk;
   1754         params->type = _SHR_GPORT_TYPE_TRUNK;
   1755         return BCM_E_NONE;
   1756     }
   1757 
   1758     if ((-1 != _port) && (-1 == id)) {
   1759         params->param0 = _port;
   1760         if ((_port == CMIC_PORT(unit)) && (_modid == _mymodid)) {
   1761             params->type = _SHR_GPORT_TYPE_LOCAL_CPU;
   1762             return BCM_E_NONE;
   1763         }
   1764         params->param1 = _modid;
   1765         params->type = _SHR_GPORT_TYPE_MODPORT;
   1766         return BCM_E_NONE;
   1767     }
   1768 
   1769     if (-1 != id) {
   1770         params->param0 = id;
   1771         /* Check if the settings below apply to TH3 L2 */
   1772         if (BCM_GPORT_IS_MPLS_PORT(l2addr->port)){
   1773             params->type = _SHR_GPORT_TYPE_MPLS_PORT;
   1774         } else if (BCM_GPORT_IS_VLAN_PORT(l2addr->port)){
   1775             params->type = _SHR_GPORT_TYPE_VLAN_PORT;
   1776         }
   1777         return BCM_E_NONE;
   1778     } else if (BCM_GPORT_IS_BLACK_HOLE(l2addr->port)) {
   1779        params->type = _SHR_GPORT_TYPE_BLACK_HOLE;
   1780        params->param0 = 0;
   1781        params->param1 = id;
   1782 
   1783        return BCM_E_NONE;
   1784     }
   1785 
   1786     return BCM_E_PORT;
   1787 }
   1788 
   1789 /*
   1790  * Function:
   1791  *      _bcm_th3_l2_to_l2x
   1792  * Purpose:
   1793  *      Convert an L2 API data structure to a Triumph L2X entry
   1794  * Parameters:
   1795  *      unit        Unit number
   1796  *      l2x_entry   (OUT) Triumph L2X entry
   1797  *      l2addr      L2 API data structure
   1798  *      key_only    Only construct key portion
   1799  */
   1800 int
   1801 _bcm_th3_l2_to_l2x(int unit, l2x_entry_t *l2x_entry, bcm_l2_addr_t *l2addr,
   1802                    int key_only)
   1803 {
   1804     bcm_cos_t cos_dst = l2addr->cos_dst;
   1805     int group = l2addr->group;
   1806 
   1807     if (l2addr->cos_dst < 0 || l2addr->cos_dst > 15) {
   1808         return BCM_E_PARAM;
   1809     }
   1810 
   1811     /*  BCM_L2_MIRROR is not supported starting from Triumph */
   1812     if (l2addr->flags & BCM_L2_MIRROR) {
   1813         return BCM_E_PARAM;
   1814     }
   1815 
   1816     /* Setting both flags is not a valid configuration. */
   1817     if (l2addr->flags & BCM_L2_LEARN_LIMIT_EXEMPT &&
   1818         l2addr->flags & BCM_L2_LEARN_LIMIT_EXEMPT_LOCAL) {
   1819         return BCM_E_PARAM;
   1820     }
   1821 
   1822     sal_memset(l2x_entry, 0, sizeof (*l2x_entry));
   1823 
   1824     VLAN_CHK_ID(unit, l2addr->vid);
   1825     soc_L2Xm_field32_set(unit, l2x_entry, VLAN_IDf, l2addr->vid);
   1826     soc_L2Xm_field32_set(unit, l2x_entry, KEY_TYPEf,
   1827                              TH3_L2_HASH_KEY_TYPE_BRIDGE);
   1828 
   1829     soc_L2Xm_mac_addr_set(unit, l2x_entry, MAC_ADDRf, l2addr->mac);
   1830 
   1831     if (key_only) {
   1832         return BCM_E_NONE;
   1833     }
   1834 
   1835     if (BCM_MAC_IS_MCAST(l2addr->mac)) {
   1836         if (l2addr->l2mc_group < 0) {
   1837             return BCM_E_PARAM;
   1838         }
   1839 
   1840         if (_BCM_MULTICAST_IS_SET(l2addr->l2mc_group)) {
   1841             soc_L2Xm_field32_set(unit, l2x_entry, DESTINATIONf,
   1842                 _BCM_MULTICAST_ID_GET(l2addr->l2mc_group));
   1843         } else {
   1844             soc_L2Xm_field32_set(unit, l2x_entry, L2MC_PTRf,
   1845                                  l2addr->l2mc_group);
   1846         }
   1847     } else {
   1848         bcm_port_t      port = -1;
   1849         bcm_trunk_t     tgid = BCM_TRUNK_INVALID;
   1850         bcm_module_t    modid = -1;
   1851         int             gport_id = -1;
   1852 
   1853         if (BCM_GPORT_IS_SET(l2addr->port)) {
   1854             _bcm_l2_gport_params_t  g_params;
   1855 
   1856             if (BCM_GPORT_IS_BLACK_HOLE(l2addr->port)) {
   1857                 soc_L2Xm_field32_set(unit, l2x_entry, SRC_DISCARDf, 1);
   1858             } else {
   1859                 soc_L2Xm_field32_set(unit, l2x_entry, SRC_DISCARDf, 0);
   1860                 BCM_IF_ERROR_RETURN(
   1861                         _bcm_th3_l2_gport_parse(unit, l2addr, &g_params));
   1862 
   1863                 switch (g_params.type) {
   1864                     case _SHR_GPORT_TYPE_TRUNK:
   1865                         tgid = g_params.param0;
   1866                         break;
   1867                     case  _SHR_GPORT_TYPE_MODPORT:
   1868                         port = g_params.param0;
   1869                         modid = g_params.param1;
   1870                         break;
   1871                     case _SHR_GPORT_TYPE_LOCAL_CPU:
   1872                         port = g_params.param0;
   1873                         BCM_IF_ERROR_RETURN(
   1874                                 bcm_esw_stk_my_modid_get(unit, &modid));
   1875                         break;
   1876                     case _SHR_GPORT_TYPE_MPLS_PORT:
   1877                         gport_id = g_params.param0;
   1878                         break;
   1879                     case _SHR_GPORT_TYPE_VLAN_PORT:
   1880                         gport_id = g_params.param0;
   1881                         break;
   1882                     default:
   1883                         return BCM_E_PORT;
   1884                 }
   1885             }
   1886         } else if (l2addr->flags & BCM_L2_TRUNK_MEMBER) {
   1887             tgid = l2addr->tgid;
   1888         } else {
   1889             /* Check parameters */
   1890             if (!SOC_MODID_ADDRESSABLE(unit, l2addr->modid)) {
   1891                 return BCM_E_BADID;
   1892             }
   1893             modid = l2addr->modid; /* Should be zero */
   1894             if (!SOC_PORT_ADDRESSABLE(unit, l2addr->port)) {
   1895                 return BCM_E_PORT;
   1896             }
   1897             port = l2addr->port;
   1898         }
   1899 
   1900         /* Setting l2x_entry fields according to parameters */
   1901         if (BCM_TRUNK_INVALID != tgid) {
   1902             soc_L2Xm_field32_set(unit, l2x_entry, Tf, 1);
   1903             soc_L2Xm_field32_set(unit, l2x_entry, TGIDf, tgid);
   1904             soc_L2Xm_field32_set(unit, l2x_entry, DEST_TYPEf, 0x1);
   1905 
   1906             if (l2addr->flags & BCM_L2_REMOTE_TRUNK) {
   1907                 /* Note REMOTE_TRUNK is not supported.
   1908                  * Remove this if after top-level check
   1909                  */
   1910             }
   1911         } else if (-1 != port) {
   1912             soc_L2Xm_field32_set(unit, l2x_entry, PORT_NUMf, port);
   1913             soc_L2Xm_field32_set(unit, l2x_entry, DEST_TYPEf, 0x0);
   1914         } else if (-1 != gport_id) {
   1915                 
   1916                 soc_L2Xm_field32_set(unit, l2x_entry, DESTINATIONf, gport_id);
   1917         }
   1918     }
   1919 
   1920     if (SOC_L2X_GROUP_ENABLE_GET(unit)) {
   1921         if (soc_feature(unit, soc_feature_overlaid_address_class) &&
   1922             !BCM_L2_PRE_SET(l2addr->flags)) {
   1923             if ((l2addr->group > SOC_OVERLAID_ADDR_CLASS_MAX(unit)) ||
   1924                 (l2addr->group < 0)) {
   1925                 return BCM_E_PARAM;
   1926             }
   1927             cos_dst = (l2addr->group & 0x3C0) >> 6;
   1928             group = l2addr->group & 0x3F;
   1929         }
   1930     }
   1931 
   1932     if (SOC_CONTROL(unit)->l2x_group_enable) {
   1933         soc_L2Xm_field32_set(unit, l2x_entry, CLASS_IDf, group);
   1934     } /* else MAC_BLOCK_INDEXf is handled in the add/remove functions below */
   1935 
   1936     if (l2addr->flags & BCM_L2_SETPRI) {
   1937         soc_L2Xm_field32_set(unit, l2x_entry, RPEf, 1);
   1938     }
   1939 
   1940     if (!SOC_IS_TRIUMPH3(unit)) {
   1941         soc_L2Xm_field32_set(unit, l2x_entry, PRIf, cos_dst);
   1942     }
   1943 
   1944     if (l2addr->flags & BCM_L2_COPY_TO_CPU) {
   1945         soc_L2Xm_field32_set(unit, l2x_entry, CPUf, 1);
   1946     }
   1947 
   1948     if (l2addr->flags & BCM_L2_DISCARD_DST) {
   1949         soc_L2Xm_field32_set(unit, l2x_entry, DST_DISCARDf, 1);
   1950     }
   1951 
   1952     if (l2addr->flags & BCM_L2_DISCARD_SRC) {
   1953         soc_L2Xm_field32_set(unit, l2x_entry, SRC_DISCARDf, 1);
   1954     }
   1955 
   1956     if (l2addr->flags & BCM_L2_COS_SRC_PRI) {
   1957         soc_L2Xm_field32_set(unit, l2x_entry, SCPf, 1);
   1958     }
   1959 
   1960     if (l2addr->flags & BCM_L2_PENDING) {
   1961         /* Not supported - relevant h/w learn support is absent in TH3 */
   1962     }
   1963 
   1964     if (l2addr->flags & BCM_L2_STATIC) {
   1965         soc_L2Xm_field32_set(unit, l2x_entry, STATIC_BITf, 1);
   1966     }
   1967 
   1968     soc_L2Xm_field32_set(unit, l2x_entry, BASE_VALIDf, 1);
   1969 
   1970     if ((l2addr->flags & BCM_L2_DES_HIT) ||
   1971         (l2addr->flags & BCM_L2_HIT)) {
   1972         soc_L2Xm_field32_set(unit, l2x_entry, HITDAf, 1);
   1973     }
   1974 
   1975     if ((l2addr->flags & BCM_L2_SRC_HIT) ||
   1976         (l2addr->flags & BCM_L2_HIT)) {
   1977         soc_L2Xm_field32_set(unit, l2x_entry, HITSAf, 1);
   1978     }
   1979 
   1980     if (SOC_MEM_FIELD_VALID(unit, L2Xm, LOCAL_SAf)) {
   1981         if (l2addr->flags & BCM_L2_NATIVE) {
   1982             soc_L2Xm_field32_set(unit, l2x_entry, LOCAL_SAf, 1);
   1983         }
   1984     }
   1985 
   1986     if (l2addr->flags & BCM_L2_LEARN_LIMIT_EXEMPT_LOCAL) {
   1987         return BCM_E_PARAM;
   1988     }
   1989 
   1990     return BCM_E_NONE;
   1991 }
   1992 
   1993 /*
   1994  * Function:
   1995  *      _bcm_th3_l2_from_l2x
   1996  * Purpose:
   1997  *      Convert a L2X entry to an L2 API data structure
   1998  * Parameters:
   1999  *      unit        Unit number
   2000  *      l2addr      (OUT) L2 API data structure
   2001  *      l2x_entry   Triumph L2X entry
   2002  */
   2003 int
   2004 _bcm_th3_l2_from_l2x(int unit, bcm_l2_addr_t *l2addr, l2x_entry_t *l2x_entry)
   2005 {
   2006     int l2mc_index, mb_index, rval;
   2007     soc_memacc_t *memacc;
   2008 
   2009     sal_memset(l2addr, 0, sizeof(*l2addr));
   2010 
   2011     /* _BCM_L2X_MEMACC_FIELD and related macros defined for TH3(l2_helpers.c) */
   2012     memacc = _BCM_L2X_MEMACC_FIELD(unit, MAC_ADDR_f);
   2013     soc_memacc_mac_addr_get(memacc, l2x_entry, l2addr->mac);
   2014 
   2015     l2addr->vid = _BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, VLAN_ID_f);
   2016 
   2017     if (BCM_MAC_IS_MCAST(l2addr->mac)) {
   2018         l2addr->flags |= BCM_L2_MCAST;
   2019         l2mc_index = _BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, L2MC_PTR_f);
   2020 
   2021         l2addr->l2mc_group = l2mc_index;
   2022         /* Translate l2mc index */
   2023         BCM_IF_ERROR_RETURN(
   2024             bcm_esw_switch_control_get(unit, bcmSwitchL2McIdxRetType, &rval));
   2025         if (rval) {
   2026             _BCM_MULTICAST_GROUP_SET(l2addr->l2mc_group, _BCM_MULTICAST_TYPE_L2,
   2027                 l2addr->l2mc_group);
   2028         }
   2029     } else {
   2030         _bcm_gport_dest_t       dest;
   2031         int                     dest_type_is_trunk = 0;
   2032         int                     isGport = 0;
   2033 
   2034         _bcm_gport_dest_t_init(&dest);
   2035 #if defined(INCLUDE_L3)
   2036         dest_type_is_trunk = _BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, T_f);
   2037 #endif /* INCLUDE_L3 */
   2038         if (dest_type_is_trunk) {
   2039             /* Trunk group */
   2040             l2addr->flags |= BCM_L2_TRUNK_MEMBER;
   2041             l2addr->tgid = _BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, TGID_f);
   2042 
   2043             dest.tgid = l2addr->tgid;
   2044             dest.gport_type = _SHR_GPORT_TYPE_TRUNK;
   2045             BCM_IF_ERROR_RETURN(
   2046                 bcm_esw_switch_control_get(unit, bcmSwitchUseGport, &isGport));
   2047         } else {
   2048             bcm_module_t    mod_in;
   2049             bcm_port_t      port_in;
   2050 
   2051             port_in = _BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, PORT_NUM_f);
   2052             mod_in  = 0;
   2053 
   2054             l2addr->modid = mod_in;
   2055             l2addr->port = port_in;
   2056             dest.port = l2addr->port;
   2057             dest.modid = l2addr->modid;
   2058             dest.gport_type = _SHR_GPORT_TYPE_MODPORT;
   2059             BCM_IF_ERROR_RETURN(
   2060                 bcm_esw_switch_control_get(unit, bcmSwitchUseGport, &isGport));
   2061         }
   2062 
   2063         if (isGport) {
   2064             
   2065             BCM_IF_ERROR_RETURN(
   2066                 _bcm_esw_gport_construct(unit, &dest, &(l2addr->port)));
   2067         }
   2068     }
   2069 
   2070     if (SOC_CONTROL(unit)->l2x_group_enable) {
   2071         l2addr->group = _BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry,
   2072                                                     CLASS_ID_f);
   2073     } else {
   2074         mb_index = _BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry,
   2075                                                MAC_BLOCK_INDEX_f);
   2076         if (mb_index) {
   2077             BCM_PBMP_ASSIGN(l2addr->block_bitmap,
   2078                             _mbi_entries[unit][mb_index].mb_pbmp);
   2079         }
   2080     }
   2081 
   2082     if (_BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, RPE_f)) {
   2083         l2addr->flags |= BCM_L2_SETPRI;
   2084     }
   2085 
   2086     l2addr->cos_dst = _BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, PRI_f);
   2087     l2addr->cos_src = _BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, PRI_f);
   2088 
   2089     if (SOC_CONTROL(unit)->l2x_group_enable) {
   2090         if (!BCM_L2_PRE_SET(l2addr->flags)) {
   2091             l2addr->group |= (l2addr->cos_dst & 0xF) << 6;
   2092         }
   2093     }
   2094 
   2095     if (_BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, CPU_f)) {
   2096         l2addr->flags |= BCM_L2_COPY_TO_CPU;
   2097     }
   2098 
   2099     if (_BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, DST_DISCARD_f)) {
   2100         l2addr->flags |= BCM_L2_DISCARD_DST;
   2101     }
   2102 
   2103     if (_BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, SRC_DISCARD_f)) {
   2104         l2addr->flags |= BCM_L2_DISCARD_SRC;
   2105     }
   2106 
   2107     if (_BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, SCP_f)) {
   2108         l2addr->flags |= BCM_L2_COS_SRC_PRI;
   2109     }
   2110 
   2111     if (_BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, STATIC_BIT_f)) {
   2112         l2addr->flags |= BCM_L2_STATIC;
   2113     }
   2114 
   2115     /* No 'pending' support in h/w, so do not set BCM_L2_PENDING */
   2116 
   2117     if (_BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, HITDA_f)) {
   2118         l2addr->flags |= BCM_L2_DES_HIT;
   2119         l2addr->flags |= BCM_L2_HIT;
   2120     }
   2121 
   2122     if (_BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, HITSA_f)) {
   2123         l2addr->flags |= BCM_L2_SRC_HIT;
   2124         l2addr->flags |= BCM_L2_HIT;
   2125     }
   2126 
   2127     if (_BCM_L2X_MEMACC_FIELD_VALID(unit, LOCAL_SA_f)) {
   2128         if (_BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, LOCAL_SA_f)) {
   2129             l2addr->flags |= BCM_L2_NATIVE;
   2130         }
   2131     }
   2132 
   2133     return BCM_E_NONE;
   2134 }
   2135 
   2136 /*
   2137  * Function:
   2138  *      _bcm_th3_l2_addr_get
   2139  * Description:
   2140  *      Given a MAC address and VLAN ID, check if the entry is present
   2141  *      in the L2 table, and if so, return all associated information
   2142  * Parameters:
   2143  *      unit - Device unit number
   2144  *      mac - input MAC address to search
   2145  *      vid - input VLAN ID to search
   2146  *      check_l2_only - only check if the target exist in L2 table
   2147  *      l2addr - Pointer to bcm_l2_addr_t structure to receive results
   2148  * Returns:
   2149  *      BCM_E_NONE              Success (l2addr filled in)
   2150  *      BCM_E_PARAM             Illegal parameter (NULL pointer)
   2151  *      BCM_E_INTERNAL          Chip access failure
   2152  *      BCM_E_NOT_FOUND Address not found (l2addr not filled in)
   2153  */
   2154 
   2155 int
   2156 _bcm_th3_l2_addr_get(int unit, sal_mac_addr_t mac, bcm_vlan_t vid,
   2157                      int check_l2_only, bcm_l2_addr_t *l2addr)
   2158 {
   2159     bcm_l2_addr_t l2addr_key;
   2160     l2x_entry_t  l2x_entry, l2x_lookup;
   2161     int          l2_hw_index;
   2162     int          rv;
   2163 
   2164     bcm_l2_addr_t_init(&l2addr_key, mac, vid);
   2165 
   2166     if (!check_l2_only) {
   2167         /* Check if function below has all l2 my stn mem fields */
   2168         rv = bcm_td_l2_myStation_get (unit, mac, vid, l2addr);
   2169         if (BCM_SUCCESS(rv)) {
   2170             return rv;
   2171         }
   2172     }
   2173 
   2174     BCM_IF_ERROR_RETURN(
   2175         _bcm_th3_l2_to_l2x(unit, &l2x_entry, &l2addr_key, TRUE));
   2176 
   2177     soc_mem_lock(unit, L2Xm);
   2178 
   2179     rv = soc_mem_generic_lookup(unit, L2Xm, MEM_BLOCK_ANY, 0, &l2x_entry,
   2180                                 &l2x_lookup, &l2_hw_index);
   2181 
   2182     soc_mem_unlock(unit, L2Xm);
   2183 
   2184     if (check_l2_only) {
   2185         return rv;
   2186     }
   2187 
   2188     if (SOC_SUCCESS(rv)) {
   2189         rv = _bcm_th3_l2_from_l2x(unit, l2addr, &l2x_lookup);
   2190     }
   2191 
   2192     return rv;
   2193 }
   2194 
   2195 int
   2196 bcm_th3_l2_addr_get(int unit, sal_mac_addr_t mac, bcm_vlan_t vid,
   2197                    bcm_l2_addr_t *l2addr)
   2198 {
   2199     return _bcm_th3_l2_addr_get(unit, mac, vid, FALSE, l2addr);
   2200 }
   2201 
   2202 /*
   2203  * Function:
   2204  *      bcm_th3_l2_addr_delete
   2205  * Description:
   2206  *      Delete an L2 address (MAC+VLAN) from the device
   2207  * Parameters:
   2208  *      unit - device unit
   2209  *      mac  - MAC address to delete
   2210  *      vid  - VLAN id
   2211  * Returns:
   2212  *      BCM_E_XXX
   2213  */
   2214 int
   2215 bcm_th3_l2_addr_delete(int unit, bcm_mac_t mac, bcm_vlan_t vid)
   2216 {
   2217     bcm_l2_addr_t  l2addr;
   2218     l2x_entry_t    l2x_entry, l2x_lookup;
   2219     int            l2_index, mb_index;
   2220     int            rv;
   2221     soc_control_t  *soc = SOC_CONTROL(unit);
   2222 
   2223     bcm_l2_addr_t_init(&l2addr, mac, vid);
   2224 
   2225     if (BCM_VLAN_VALID(vid)) {
   2226         rv = bcm_td_l2_myStation_delete (unit, mac, vid, &l2_index);
   2227         if ((rv != BCM_E_NOT_FOUND) && (rv != BCM_E_FULL)) {
   2228             if (rv != BCM_E_NONE) {
   2229                 return rv;
   2230             }
   2231         }
   2232     }
   2233 
   2234     BCM_IF_ERROR_RETURN(_bcm_th3_l2_to_l2x(unit, &l2x_entry, &l2addr, TRUE));
   2235 
   2236     soc_mem_lock(unit, L2Xm);
   2237 
   2238     rv = soc_mem_search(unit, L2Xm, MEM_BLOCK_ANY, &l2_index,
   2239                        (void *)&l2x_entry, (void *)&l2x_lookup, 0);
   2240     if (BCM_E_NONE != rv) {
   2241         soc_mem_unlock(unit, L2Xm);
   2242         return rv;
   2243     }
   2244 
   2245     if (!SOC_CONTROL(unit)->l2x_group_enable) {
   2246         mb_index = soc_L2Xm_field32_get(unit, &l2x_lookup, MAC_BLOCK_INDEXf);
   2247         _bcm_th3_mac_block_delete(unit, mb_index);
   2248     }
   2249 
   2250     if (SOC_L2_DEL_SYNC_LOCK(soc) < 0) {
   2251         soc_mem_unlock(unit, L2Xm);
   2252         return BCM_E_RESOURCE;
   2253     }
   2254     rv = soc_mem_delete_return_old(unit, L2Xm, MEM_BLOCK_ANY,
   2255                                    (void *)&l2x_entry, (void *)&l2x_entry);
   2256     if (rv >= 0) {
   2257         rv = soc_l2x_sync_delete(unit, (uint32 *) &l2x_lookup, l2_index, 0);
   2258     }
   2259     SOC_L2_DEL_SYNC_UNLOCK(soc);
   2260     soc_mem_unlock(unit, L2Xm);
   2261 
   2262     return rv;
   2263 }
   2264 
   2265 /*
   2266  * Function:
   2267  *      _bcm_th3_l2_hash_dynamic_replace
   2268  * Purpose:
   2269  *      Replace dynamic L2 entries in a dual hash.
   2270  * Parameters:
   2271  *      unit - Unit number
   2272  *      l2x_entry - Entry to insert instead of dynamic entry.
   2273  * Returns:
   2274  *      BCM_E_NONE Success
   2275  *      BCM_E_XXX  Error
   2276  */
   2277 
   2278 int _bcm_th3_l2_hash_dynamic_replace(int unit, l2x_entry_t *l2x_entry)
   2279 {
   2280     l2x_entry_t     l2ent;
   2281     int             rv;
   2282     uint32          fval;
   2283     bcm_mac_t       mac;
   2284     int             cf_hit, cf_unhit;
   2285     int             bank, bucket, slot, index;
   2286     int             num_banks;
   2287     int             entries_per_bank, entries_per_row, entries_per_bucket;
   2288     int             bank_base, bucket_offset;
   2289 
   2290     BCM_IF_ERROR_RETURN
   2291         (soc_tomahawk3_hash_bank_count_get(unit, L2Xm, &num_banks));
   2292 
   2293     BCM_IF_ERROR_RETURN(soc_l2x_freeze(unit));
   2294 
   2295     cf_hit = cf_unhit = -1;
   2296     for (bank = 0; bank < num_banks; bank++) {
   2297 
   2298         rv = soc_tomahawk3_hash_bank_info_get(unit, L2Xm, bank,
   2299                                               &entries_per_bank,
   2300                                               &entries_per_row,
   2301                                               &entries_per_bucket,
   2302                                               &bank_base, &bucket_offset);
   2303         if (SOC_FAILURE(rv)) {
   2304             (void)soc_l2x_thaw(unit);
   2305             return rv;
   2306         }
   2307 
   2308         bucket = soc_tomahawk3_l2x_bank_entry_hash(unit, bank, (uint32 *)l2x_entry);
   2309 
   2310         for (slot = 0; slot < entries_per_bucket; slot++) {
   2311             uint32 valid = 0;
   2312             index = bank_base + bucket * entries_per_row + bucket_offset +
   2313                 slot;
   2314             rv = soc_mem_read(unit, L2Xm, MEM_BLOCK_ANY, index, &l2ent);
   2315             if (SOC_FAILURE(rv)) {
   2316                 (void)soc_l2x_thaw(unit);
   2317                 return rv;
   2318             }
   2319 
   2320             valid = soc_L2Xm_field32_get(unit, &l2ent, BASE_VALIDf);
   2321 
   2322             if (!valid) {
   2323                 /* Found invalid entry - stop the search victim found */
   2324                 cf_unhit = index;
   2325                 break;
   2326             }
   2327 
   2328             fval = soc_mem_field32_get(unit, L2Xm, &l2ent, KEY_TYPEf);
   2329 
   2330             if (fval != TH3_L2_HASH_KEY_TYPE_BRIDGE) {
   2331                 continue;
   2332             }
   2333 
   2334             soc_L2Xm_mac_addr_get(unit, &l2ent, MAC_ADDRf, mac);
   2335 
   2336             /* Skip static entries */
   2337             if ((soc_L2Xm_field32_get(unit, &l2ent, STATIC_BITf)) ||
   2338                 (BCM_MAC_IS_MCAST(mac))) {
   2339                 continue;
   2340             }
   2341 
   2342             if (soc_L2Xm_field32_get(unit, &l2ent, HITDAf) ||
   2343                 soc_L2Xm_field32_get(unit, &l2ent, HITSAf) ) {
   2344                 cf_hit =  index;
   2345             } else {
   2346                 /* Found unhit entry - stop search victim found */
   2347                 cf_unhit = index;
   2348                 break;
   2349             }
   2350         }
   2351         if (cf_unhit != -1) {
   2352             break;
   2353         }
   2354     }
   2355 
   2356     COMPILER_REFERENCE(entries_per_bank);
   2357 
   2358     if (cf_unhit >= 0) {
   2359         index = cf_unhit;   /* take last unhit dynamic */
   2360     } else if (cf_hit >= 0) {
   2361         index = cf_hit;     /* or last hit dynamic */
   2362     } else {
   2363         rv = BCM_E_FULL;     /* no dynamics to delete */
   2364         (void) soc_l2x_thaw(unit);
   2365          return rv;
   2366     }
   2367 
   2368     rv = soc_mem_delete_index(unit, L2Xm, MEM_BLOCK_ALL, index);
   2369     if (SOC_SUCCESS(rv)) {
   2370         rv = soc_mem_generic_insert(unit, L2Xm, MEM_BLOCK_ANY, 0,
   2371                                     l2x_entry, NULL, NULL);
   2372     }
   2373     if (SOC_FAILURE(rv)) {
   2374         (void) soc_l2x_thaw(unit);
   2375         return rv;
   2376     }
   2377 
   2378     return soc_l2x_thaw(unit);
   2379 }
   2380 
   2381 /*
   2382  * Function:
   2383  *      bcm_th3_l2_addr_add
   2384  * Description:
   2385  *      Add a MAC address to the Switch Address Resolution Logic (ARL)
   2386  *      port with the given VLAN ID and parameters.
   2387  * Parameters:
   2388  *      unit - StrataSwitch PCI device unit number (driver internal).
   2389  *      l2addr - Pointer to bcm_l2_addr_t containing all valid fields
   2390  * Returns:
   2391  *      BCM_E_NONE              Success
   2392  *      BCM_E_INTERNAL          Chip access failure
   2393  *      BCM_E_RESOURCE          No MAC_BLOCK entries available
   2394  * Notes:
   2395  *      Use CMIC_PORT(unit) to associate the entry with the CPU.
   2396  *      Use flag of BCM_L2_COPY_TO_CPU to send a copy to the CPU.
   2397  *      Use flag of BCM_L2_TRUNK_MEMBER to set trunking (TGID must be
   2398  *      passed as well with non-zero trunk group ID)
   2399  *      In case the L2X table is full (e.g. bucket full), an attempt
   2400  *      will be made to store the entry in the L2_USER_ENTRY table.
   2401  */
   2402 int
   2403 bcm_th3_l2_addr_add(int unit, bcm_l2_addr_t *l2addr)
   2404 {
   2405     l2x_entry_t  l2x_entry, l2x_lookup;
   2406     int rv, l2_index, mb_index = 0;
   2407 
   2408     if (l2addr->flags & BCM_L2_L3LOOKUP) {
   2409         BCM_IF_ERROR_RETURN(bcm_td_l2_myStation_add(unit, l2addr));
   2410     } else {
   2411         rv = bcm_td_l2_myStation_delete(unit, l2addr->mac, l2addr->vid,
   2412                                         &l2_index);
   2413         if (rv != BCM_E_NONE && rv != BCM_E_NOT_FOUND) {
   2414             return rv;
   2415         }
   2416     }
   2417 
   2418     BCM_IF_ERROR_RETURN(_bcm_th3_l2_to_l2x(unit, &l2x_entry, l2addr, FALSE));
   2419 
   2420     rv = soc_mem_generic_lookup(unit, L2Xm, MEM_BLOCK_ANY, 0, &l2x_entry,
   2421                                 &l2x_lookup, &l2_index);
   2422     if (BCM_FAILURE(rv) && rv != BCM_E_NOT_FOUND) {
   2423         return rv;
   2424     }
   2425 
   2426     if (!SOC_CONTROL(unit)->l2x_group_enable) {
   2427         /* Mac blocking, attempt to associate with bitmap entry */
   2428         BCM_IF_ERROR_RETURN
   2429             (_bcm_th3_mac_block_insert(unit, l2addr->block_bitmap, &mb_index));
   2430         soc_mem_field32_set(unit, L2Xm, &l2x_entry, MAC_BLOCK_INDEXf,
   2431                             mb_index);
   2432     }
   2433 
   2434     rv = soc_mem_insert_return_old(unit, L2Xm, MEM_BLOCK_ANY,
   2435                                    (void *)&l2x_entry, NULL);
   2436     if ((rv == BCM_E_FULL) && (l2addr->flags & BCM_L2_REPLACE_DYNAMIC)) {
   2437         rv = _bcm_th3_l2_hash_dynamic_replace( unit, &l2x_entry);
   2438         if (rv < 0 ) {
   2439             goto done;
   2440         }
   2441     } else if (rv == BCM_E_EXISTS) {
   2442         if (!SOC_CONTROL(unit)->l2x_group_enable) {
   2443             mb_index = soc_mem_field32_get(unit, L2Xm, &l2x_lookup,
   2444                                            MAC_BLOCK_INDEXf);
   2445             _bcm_th3_mac_block_delete(unit, mb_index);
   2446         }
   2447         rv = BCM_E_NONE;
   2448     }
   2449 
   2450 done:
   2451     if (rv < 0) {
   2452         _bcm_th3_mac_block_delete(unit, mb_index);
   2453     }
   2454 
   2455     return rv;
   2456 }
   2457 
   2458 /*
   2459  * Function:
   2460  *      _bcm_th3_l2_cross_connect_add
   2461  * Description:
   2462  *      Add a VLAN cross connect entry
   2463  * Parameters:
   2464  *      unit       - Device unit number
   2465  *      outer_vlan - Outer vlan ID
   2466  *      destt      - array of 2, specifies the corresponding dst is TGID or Port
   2467  *      destv      - array of 2, TGID or Port corresponding to two gports
   2468  * Returns:
   2469  *      BCM_E_NONE - Success.
   2470  *      BCM_E_XXX
   2471  * Notes:
   2472  *      All incoming paramaters are assumed to be valid
   2473  *      and hence no further checks are performed on them
   2474  */
   2475 int
   2476 _bcm_th3_l2_cross_connect_add(
   2477     int unit, bcm_vlan_t outer_vlan, uint8 *destt, int *destv)
   2478 {
   2479     int rv;
   2480     int l2_index;
   2481     l2x_entry_t l2x_entry;
   2482     l2x_entry_t l2x_lookup;
   2483 
   2484     sal_memset(&l2x_entry, 0, sizeof (l2x_entry));
   2485 
   2486     soc_L2Xm_field32_set(unit, &l2x_entry, BASE_VALIDf, 1);
   2487     soc_L2Xm_field32_set(unit, &l2x_entry, STATIC_BITf, 1);
   2488     soc_L2Xm_field32_set(unit, &l2x_entry, VLAN__OVIDf, outer_vlan);
   2489     soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf,
   2490                              TH3_L2_HASH_KEY_TYPE_SINGLE_CROSS_CONNECT);
   2491 
   2492     /* See if the entry already exists */
   2493     rv = soc_mem_generic_lookup(
   2494             unit, L2Xm, MEM_BLOCK_ANY, 0, &l2x_entry, &l2x_lookup, &l2_index);
   2495 
   2496     if ((rv < 0) && (rv != BCM_E_NOT_FOUND)) {
   2497          return rv;
   2498     }
   2499 
   2500     /* Fill in first port */
   2501     soc_L2Xm_field32_set(unit, &l2x_entry, VLAN__DEST_TYPEf, !!destt[0]);
   2502     soc_L2Xm_field32_set(unit, &l2x_entry, VLAN__DESTINATIONf, destv[0]);
   2503     /* Fill in second port */
   2504     soc_L2Xm_field32_set(unit, &l2x_entry, VLAN__DEST_TYPE_1f, !!destt[1]);
   2505     soc_L2Xm_field32_set(unit, &l2x_entry, VLAN__DESTINATION_1f, destv[1]);
   2506 
   2507     rv = soc_mem_insert_return_old(unit, L2Xm, MEM_BLOCK_ANY,
   2508                                    (void *)&l2x_entry, (void *)&l2x_entry);
   2509     if (rv == BCM_E_FULL) {
   2510         rv = _bcm_th3_l2_hash_dynamic_replace(unit, &l2x_entry);
   2511     }
   2512 
   2513     return rv;
   2514 }
   2515 
   2516 #if defined(BCM_WARM_BOOT_SUPPORT)
   2517 /*
   2518  * Function:
   2519  *      _bcm_th3_l2_cross_connect_entry_add_all
   2520  * Description:
   2521  *      Walks through the valid cross connect entries
   2522  *      in L2X and adds the entry in VLAN CC Database.
   2523  * Parameters:
   2524  *      unit       - (IN) bcm device.
   2525  * Returns:
   2526  *      BCM_E_NONE - Success.
   2527  *      BCM_E_XXX
   2528  */
   2529 int
   2530 _bcm_th3_l2_cross_connect_entry_add_all(int unit)
   2531 {
   2532     int idx, index;
   2533     int index_min, index_max, mem_max;
   2534     int rv = SOC_E_NONE;
   2535     int *buffer = NULL;
   2536     l2x_entry_t *l2x_entry;
   2537     bcm_vlan_t outer_vlan;
   2538     soc_mem_t mem = L2Xm;
   2539     uint8 destt[2];
   2540     int destv[2];
   2541     int l2delete_chunks = DEFAULT_L2DELETE_CHUNKS;
   2542 
   2543     index_min = soc_mem_index_min(unit, mem);
   2544     mem_max = soc_mem_index_max(unit, mem);
   2545 
   2546     buffer = soc_cm_salloc( unit,
   2547                             (l2delete_chunks * sizeof(l2x_entry_t)),
   2548                             "cross connect traverse");
   2549     if (NULL == buffer) {
   2550         return SOC_E_MEMORY;
   2551     }
   2552 
   2553     soc_mem_lock(unit, L2Xm);
   2554     for (idx = index_min; idx < mem_max; idx += l2delete_chunks) {
   2555         index_max = idx + l2delete_chunks - 1;
   2556         if ( index_max > mem_max) {
   2557             index_max = mem_max;
   2558         }
   2559         if ((rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ALL,
   2560                                      idx, index_max, buffer)) < 0 ) {
   2561             break;
   2562         }
   2563         for (index = 0; index < l2delete_chunks; index++) {
   2564             l2x_entry =
   2565                 soc_mem_table_idx_to_pointer(unit, mem,
   2566                                              l2x_entry_t *, buffer, index);
   2567             if (soc_L2Xm_field32_get(unit, l2x_entry, BASE_VALIDf)) {
   2568                 if (TH3_L2_HASH_KEY_TYPE_SINGLE_CROSS_CONNECT !=
   2569                         soc_L2Xm_field32_get(unit, l2x_entry, KEY_TYPEf)) {
   2570                     continue;
   2571                 }
   2572 
   2573                 /* Extract the outer vlan */
   2574                 outer_vlan = soc_L2Xm_field32_get(unit, l2x_entry, VLAN__OVIDf);
   2575 
   2576                 /* Deduce the first destination */
   2577                 destv[0] =
   2578                     soc_L2Xm_field32_get(unit, l2x_entry, VLAN__DESTINATIONf);
   2579                 destt[0] = (uint8)
   2580                     soc_L2Xm_field32_get(unit, l2x_entry, VLAN__DEST_TYPEf);
   2581 
   2582                 /* Deduce the second destination */
   2583                 destv[1] =
   2584                     soc_L2Xm_field32_get(unit, l2x_entry, VLAN__DESTINATION_1f);
   2585                 destt[1] = (uint8)
   2586                     soc_L2Xm_field32_get(unit, l2x_entry, VLAN__DEST_TYPE_1f);
   2587 
   2588                 rv =  _bcm_th3_vlan_xconnect_db_entry_add(
   2589                                                unit, outer_vlan, destt, destv);
   2590                 if (BCM_FAILURE(rv)) {
   2591                     soc_mem_unlock(unit, L2Xm);
   2592                     soc_cm_sfree(unit, buffer);
   2593                     return rv;
   2594                 }
   2595             }
   2596         }
   2597     }
   2598     soc_mem_unlock(unit, L2Xm);
   2599     soc_cm_sfree(unit, buffer);
   2600 
   2601     return rv;
   2602 }
   2603 #endif /* BCM_WARM_BOOT_SUPPORT */
   2604 #endif /* BCM_TOMAHAWK3_SUPPORT */